I have created a custom trigger called "Shipped" which seems to work perfectly in my list of options.
function add_new_order_woocommerce_email( $email_classes ) {
// include our custom email class
require( 'includes/class-wc-shipped-order-email.php' );
// add the email class to the list of email classes that WooCommerce loads
$email_classes['WC_Shipped_Order_Email'] = new WC_Shipped_Order_Email();
return $email_classes;
}
add_filter( 'woocommerce_email_classes', 'add_new_order_woocommerce_email' );
function register_shipped_order_status() {
register_post_status( 'wc-shipped', array(
'label' => 'Shipped',
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'Shipped <span class="count">(%s)</span>', 'Shipped <span class="count">(%s)</span>' )
) );
}
add_action( 'init', 'register_shipped_order_status' );
function add_new_to_order_statuses( $order_statuses ) {
$new_order_statuses = array();
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-processing' === $key ) {
$new_order_statuses['wc-shipped'] = 'Shipped';
}
}
return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_new_to_order_statuses' );
I have been having issues trying to get this email to trigger when the status is changed to my custom status provided above. I have searched the internet for multiple examples and possible solutions to my problem but have been unable to find anything that helps.
The email template in the code has been created and is in the correct directory location.
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
* A custom Shipped Order WooCommerce Email class
*
* #since 0.1
* #extends \WC_Email
*/
class WC_Shipped_Order_Email extends WC_Email {
public function __construct() {
// set ID, this simply needs to be a unique name
$this->id = 'wc_shipped_order';
// this is the title in WooCommerce Email settings
$this->title = 'Shipped';
// defines the email for customers only
$this->customer_email = true;
// this is the description in WooCommerce email settings
$this->description = 'Shipped order notification emails are sent when a customers order has been shipped.';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'Order Shipped';
$this->subject = 'Order Shipped';
// these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
$this->template_html = 'emails/customer-shipped-order.php';
$this->template_plain = 'emails/plain/customer-shipped-order.php';
// Trigger on new paid orders
add_action( 'woocommerce_order_status_pending_to_shipped', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_processing_to_shipped', array( $this, 'trigger' ) );
// Call parent constructor to load any other defaults not explicity defined here
parent::__construct();
// this sets the recipient to the settings defined below in init_form_fields()
$this->recipient = $this->get_option( 'recipient' );
// if none was entered, just use the WP admin email as a fallback
if ( ! $this->recipient )
$this->recipient = get_option( 'admin_email' );
}
/**
* Determine if the email should actually be sent and setup email merge variables
*
* #since 0.1
* #param int $order_id
*/
public function trigger( $order_id ) {
// bail if no order ID is present
if ( ! $order_id )
return;
// setup order object
$this->object = new WC_Order( $order_id );
// replace variables in the subject/headings
$this->find[] = '{order_date}';
$this->replace[] = date_i18n( woocommerce_date_format(), strtotime( $this->object->order_date ) );
$this->find[] = '{order_number}';
$this->replace[] = $this->object->get_order_number();
if ( ! $this->is_enabled() || ! $this->get_recipient() )
return;
// woohoo, send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
/**
* Get email subject.
*
* #since 3.1.0
* #return string
*/
public function get_default_subject() {
return __( 'Your order has been shipped', 'woocommerce' );
}
/**
* Get email heading.
*
* #since 3.1.0
* #return string
*/
public function get_default_heading() {
return __( 'Thanks for shopping with us', 'woocommerce' );
}
/**
* Get content html.
*
* #return string
*/
public function get_content_html() {
return wc_get_template_html(
$this->template_html, array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'sent_to_admin' => false,
'plain_text' => false,
'email' => $this,
)
);
}
/**
* Get content plain.
*
* #return string
*/
public function get_content_plain() {
return wc_get_template_html(
$this->template_plain, array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'sent_to_admin' => false,
'plain_text' => true,
'email' => $this,
)
);
}
/**
* Initialise settings form fields.
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable this email notification', 'woocommerce' ),
'default' => 'yes',
),
'subject' => array(
'title' => __( 'Subject', 'woocommerce' ),
'type' => 'text',
'desc_tip' => true,
/* translators: %s: list of placeholders */
'description' => sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '<code>{site_title}, {order_date}, {order_number}</code>' ),
'placeholder' => $this->get_default_subject(),
'default' => '',
),
'heading' => array(
'title' => __( 'Email heading', 'woocommerce' ),
'type' => 'text',
'desc_tip' => true,
/* translators: %s: list of placeholders */
'description' => sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '<code>{site_title}, {order_date}, {order_number}</code>' ),
'placeholder' => $this->get_default_heading(),
'default' => '',
),
'email_type' => array(
'title' => __( 'Email type', 'woocommerce' ),
'type' => 'select',
'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
'default' => 'html',
'class' => 'email_type wc-enhanced-select',
'options' => $this->get_email_type_options(),
'desc_tip' => true,
),
);
}
} // end \WC_Shipped_Order_Email class
function fabricdeluxe_shipped_woocommerce_email_actions( $actions ){
$actions[] = 'woocommerce_order_status_shipped';
return $actions;
}
add_filter( 'woocommerce_email_actions', 'fabricdeluxe_shipped_woocommerce_email_actions' );
A lot of this coding was sourced via other sources and customised to suit my application, however I have been stuck on this one problem for so long I have no decided to resorting to this amazing website to get some expert opinions on what I could possibly be doing wrong or where I may find a solution. (I prefer to learn myself, but my brain can only take so much before it becomes annoyingly hard to solve haha!)
Any help is greatly appreciated!
Related
In Woocommerce, I would like to have a custom payment gateway, with a complete form. And that the answers to that form, are displayed in the validation page (I think it is the thank you page in english) AND in the back office, in the order.
I'm not good enough in PHP to create this, all on my own.
But I learn to be better, trying to understand how code is working.
So I tried to found something close to my question
And I found this excellent answer:
Add a custom payment gateway with additional radio buttons in Woocommerce
which answer for 90% to my question.
I found myself how to add other type of form's elements, like text, checkboxes...
/**
* Output the "payment type" radio buttons fields in checkout.
*/
public function payment_fields(){
if ( $description = $this->get_description() ) {
echo wpautop( wptexturize( $description ) );
}
/**echo '<style>#transaction_type_field label.radio { display:inline-block; margin:0 .8em 0 .4em}</style>';**/
$option_keys = array_keys($this->options);
woocommerce_form_field( 'transaction_type-1', array(
'type' => 'checkbox',
'class' => array('transaction_type form-row-wide'),
'label' => __('Espèces', $this->domain),
), reset( $option_keys ) );
woocommerce_form_field( 'transaction_type-2', array(
'type' => 'checkbox',
'class' => array('transaction_type form-row-wide'),
'label' => __('Tickets restaurants', $this->domain),
), reset( $option_keys ) );
woocommerce_form_field( 'transaction_type-3', array(
'type' => 'checkbox',
'class' => array('transaction_type form-row-wide'),
'label' => __('Chèques vacances', $this->domain),
), reset( $option_keys ) );
woocommerce_form_field( 'transaction_type-4', array(
'type' => 'radio',
'class' => array('transaction_type form-row-wide'),
'label' => __('Payment Information - Test', $this->domain),
'options' => $this->options,
), reset( $option_keys ) );
}
But I don't understand how to "stock" the answers and displayed it.
I tried with the first checkbox and I tried this :
/**
* Save the chosen payment type as order meta data.
*
* #param object $order
* #param array $data
*/
public function save_order_payment_type_meta_data( $order, $data ) {
if ( $data['payment_method'] === $this->id && isset($_POST['transaction_type-1']) )
$order->update_meta_data('_transaction_type', esc_attr($_POST['transaction_type-1']) );
}
But it is not working.
I think I missed something, perhaps around this, that I don't understand :
reset( $option_keys )
So if you have the solution ans explanations to my problem, or at least a clue, it will help me a lot.
Try the following replacement code functions (for multiple checkboxes):
/**
* Output the "payment type" fields in checkout.
*/
public function payment_fields(){
if ( $description = $this->get_description() ) {
echo wpautop( wptexturize( $description ) );
}
woocommerce_form_field( 'transaction_type-1', array(
'type' => 'checkbox',
'class' => array('transaction_type form-row-wide'),
'label' => __('Espèces', $this->domain),
), '' );
woocommerce_form_field( 'transaction_type-2', array(
'type' => 'checkbox',
'class' => array('transaction_type form-row-wide'),
'label' => __('Tickets restaurants', $this->domain),
), '' );
woocommerce_form_field( 'transaction_type-3', array(
'type' => 'checkbox',
'class' => array('transaction_type form-row-wide'),
'label' => __('Chèques vacances', $this->domain),
), '' );
$option_keys = array_keys($this->options);
woocommerce_form_field( 'transaction_type-4', array(
'type' => 'radio',
'class' => array('transaction_type form-row-wide'),
'label' => __('Payment Information - Test', $this->domain),
'options' => $this->options,
), reset( $option_keys ) );
}
/**
* Save the chosen payment type as order meta data.
*
* #param object $order
* #param array $data
*/
public function save_order_payment_type_meta_data( $order, $data ) {
if ( $data['payment_method'] === $this->id ) {
$meta_value = array(); // Initializing
if ( isset($_POST['transaction_type-1']) ) {
$meta_value[1] = __('Espèces', $this->domain);
}
if ( isset($_POST['transaction_type-2']) ) {
$meta_value[2] = __('Tickets restaurants', $this->domain);
}
if ( isset($_POST['transaction_type-3']) ) {
$meta_value[3] = __('Chèques vacances', $this->domain);
}
// Save transaction type (from fields 1 to 3) as an array
if( sizeof($meta_value) > 0 ) {
$order->update_meta_data('_transaction_type', $meta_value );
}
// Save transaction type test (from fields 4) as a string
if ( isset($_POST['transaction_type-4']) ) {
$order->update_meta_data('_transaction_type_test', esc_attr($_POST['transaction_type-4']) );
}
}
}
/**
* Display the chosen payment type on order totals table
*
* #param array $total_rows
* #param WC_Order $order
* #param bool $tax_display
* #return array
*/
public function display_transaction_type_order_item_totals( $total_rows, $order, $tax_display ){
if( is_a( $order, 'WC_Order' ) && $order->get_meta('_transaction_type') ) {
$new_rows = []; // Initializing
$options = $this->options;
// Loop through order total lines
foreach( $total_rows as $total_key => $total_values ) {
$new_rows[$total_key] = $total_values;
if( $total_key === 'payment_method' ) {
// Get transaction type array
if( $meta_data = $order->get_meta('_transaction_type') ) {
$new_rows['payment_type'] = [
'label' => __("Transaction type", $this->domain) . ':',
'value' => implode(',', $meta_data),
];
}
}
}
$total_rows = $new_rows;
}
return $total_rows;
}
It should better work…
Related thread: Add a custom payment gateway with additional radio buttons in Woocommerce
I am developing a custom payment method for woocommerce follogin is my code :
class WC_Gateway_Custom extends WC_Payment_Gateway {
public $domain;
/**
* Constructor for the gateway.
*/
public function __construct() {
$this->domain = 'custom_payment';
$this->id = 'custom';
$this->icon = apply_filters('woocommerce_custom_gateway_icon', '');
$this->has_fields = false;
$this->method_title = __( 'Custom', $this->domain );
$this->method_description = __( 'Allows payments with custom gateway.', $this->domain );
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Define user set variables
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions', $this->description );
$this->order_status = $this->get_option( 'order_status', 'completed' );
// Actions
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_thankyou_custom', array( $this, 'thankyou_page' ) );
// Customer Emails
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
}
/**
* Initialise Gateway Settings Form Fields.
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', $this->domain ),
'type' => 'checkbox',
'label' => __( 'Enable Custom Payment', $this->domain ),
'default' => 'yes'
),
'title' => array(
'title' => __( 'Title', $this->domain ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', $this->domain ),
'default' => __( 'Custom Payment', $this->domain ),
'desc_tip' => true,
),
'order_status' => array(
'title' => __( 'Order Status', $this->domain ),
'type' => 'select',
'class' => 'wc-enhanced-select',
'description' => __( 'Choose whether status you wish after checkout.', $this->domain ),
'default' => 'wc-completed',
'desc_tip' => true,
'options' => wc_get_order_statuses()
),
'description' => array(
'title' => __( 'Description', $this->domain ),
'type' => 'textarea',
'description' => __( 'Payment method description that the customer will see on your checkout.', $this->domain ),
'default' => __('Payment Information', $this->domain),
'desc_tip' => true,
),
'instructions' => array(
'title' => __( 'Instructions', $this->domain ),
'type' => 'textarea',
'description' => __( 'Instructions that will be added to the thank you page and emails.', $this->domain ),
'default' => '',
'desc_tip' => true,
),
);
}
/**
* Output for the order received page.
*/
public function thankyou_page() {
if ( $this->instructions )
echo wpautop( wptexturize( $this->instructions ) );
}
/**
* Add content to the WC emails.
*
* #access public
* #param WC_Order $order
* #param bool $sent_to_admin
* #param bool $plain_text
*/
public function payment_fields(){
if ( $description = $this->get_description() ) {
echo wpautop( wptexturize( $description ) );
}
echo 'added custom field in radio buttons';
/**
* Process the payment and return the result.
*
* #param int $order_id
* #return array
*/
}
public function generate_form($order_id){
global $woocommerce;
// Get this Order's information so that we know
// who to charge and how much
$customer_order = new WC_Order($order_id);
$_instructions = $this->instructions;
$_order_status = $this->order_status;
$items = $customer_order->get_items();
$product_name = array();
foreach ( $items as $item ) {
array_push($product_name, $item['name']);
}
$_Description = implode(", ", $product_name);
echo 'here i want to get the value selected by the customer from front end';
//here is the part where i want to get the value of form inside payment_fields() fucntion
exit;
}
}
i need to set transaction type of my custom payment method attaching screen shot as well for better understanding, see:
there is no help on how to over ride this payment_fields() function i can get the html printed but don't have any idea how to get the value and set it as transaction type of the order
There is some errors, mistakes and missing things in your code… Here is a complete plugin file that works adding to this "Special" payment radio buttons on the gateway when it's selected in checkout page.
The selected "Transaction type" radio button value will be saved in the order as custom meta data.
The selected "Transaction type" value will be displayed in:
Order recieved page, My account > View Order
Admin Edit order pages
On the email notifications
On Order view page:
Here is the complete plugin code:
<?php
/**
* Plugin Name: WooCommerce Special Payment Gateway
* Plugin URI:
* Description: custom Special payment method.
* Author: Me
* Author URI: http://www.something.tld/
* Version: 1.1.0
* Text Domain: wcpg-special
* Domain Path: /i18n/languages/
*
* Copyright: (c) 2018
*
* License: GNU General Public License v3.0
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
*
* #package wcpg-special
* #author Me
* #category Admin
* #copyright Copyright (c) 2016-2018
* #license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
*/
defined( 'ABSPATH' ) or exit;
// Make sure WooCommerce is active
if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
return;
}
/**
* Add the gateway to WC Available Gateways
*
* #since 1.0.0
* #param array $gateways all available WC gateways
* #return array $gateways all WC gateways + Custom Special gateway
*/
function wc_add_special_to_gateways( $gateways ) {
$gateways[] = 'WC_Gateway_Special';
return $gateways;
}
add_filter( 'woocommerce_payment_gateways', 'wc_add_special_to_gateways' );
/**
* Adds plugin page links
*
* #since 1.0.0
* #param array $links all plugin links
* #return array $links all plugin links + our custom links (i.e., "Settings")
*/
function wc_special_gateway_plugin_links( $links ) {
$plugin_links = array(
'' . __( 'Configure', 'wcpg-special' ) . ''
);
return array_merge( $plugin_links, $links );
}
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'wc_special_gateway_plugin_links' );
/**
* Custom Payment Gateway
*
* Provides an Custom Payment Gateway; mainly for testing purposes.
* We load it later to ensure WC is loaded first since we're extending it.
*
* #class WC_Gateway_Special
* #extends WC_Payment_Gateway
* #version 1.0.0
* #package WooCommerce/Classes/Payment
* #author Me
*/
add_action( 'plugins_loaded', 'wc_special_gateway_init', 11 );
function wc_special_gateway_init() {
class WC_Gateway_Special extends WC_Payment_Gateway {
public $domain;
/**
* Constructor for the gateway.
*/
public function __construct() {
$this->id = 'special_payment';
$this->domain = 'wcpg-special';
$this->icon = apply_filters('woocommerce_payment_gateway_icon', '');
$this->has_fields = false;
$this->method_title = __( 'Custom Payment', $this->domain );
// Define "payment type" radio buttons options field
$this->options = array(
'type1' => __( 'Type 1', $this->domain ),
'type2' => __( 'Type 2', $this->domain ),
'type3' => __( 'Type 3', $this->domain ),
);
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Define user set variables
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions' );
$this->order_status = $this->get_option( 'order_status' );
$this->status_text = $this->get_option( 'status_text' );
// Actions
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_checkout_create_order', array( $this, 'save_order_payment_type_meta_data' ), 10, 2 );
add_filter( 'woocommerce_get_order_item_totals', array( $this, 'display_transaction_type_order_item_totals'), 10, 3 );
add_action( 'woocommerce_admin_order_data_after_billing_address', array( $this, 'display_payment_type_order_edit_pages'), 10, 1 );
add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'thankyou_page' ) );
// Customer Emails
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
}
/**
* Initialize Gateway Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = apply_filters( 'wc_special_payment_form_fields', array(
'enabled' => array(
'title' => __( 'Enable/Disable', $this->domain ),
'type' => 'checkbox',
'label' => __( 'Enable Special Payment', $this->domain ),
'default' => 'yes'
),
'title' => array(
'title' => __( 'Title', $this->domain ),
'type' => 'text',
'description' => __( 'This controls the title for the payment method the customer sees during checkout.', $this->domain ),
'default' => __( 'Special Payment', $this->domain ),
'desc_tip' => true,
),
'description' => array(
'title' => __( 'Description', $this->domain ),
'type' => 'textarea',
'description' => __( 'Payment method description that the customer will see on your checkout.', $this->domain ),
'default' => __( 'Please remit payment to Store Name upon pickup or delivery.', $this->domain ),
'desc_tip' => true,
),
'instructions' => array(
'title' => __( 'Instructions', $this->domain ),
'type' => 'textarea',
'description' => __( 'Instructions that will be added to the thank you page and emails.', $this->domain ),
'default' => '', // Empty by default
'desc_tip' => true,
),
'order_status' => array(
'title' => __( 'Order Status', $this->domain ),
'type' => 'select',
'description' => __( 'Choose whether order status you wish after checkout.', $this->domain ),
'default' => 'wc-completed',
'desc_tip' => true,
'class' => 'wc-enhanced-select',
'options' => wc_get_order_statuses()
),
'status_text' => array(
'title' => __( 'Order Status Text', $this->domain ),
'type' => 'text',
'description' => __( 'Set the text for the selected order status.', $this->domain ),
'default' => __( 'Order is completed', $this->domain ),
'desc_tip' => true,
),
) );
}
/**
* Output the "payment type" radio buttons fields in checkout.
*/
public function payment_fields(){
if ( $description = $this->get_description() ) {
echo wpautop( wptexturize( $description ) );
}
echo '<style>#transaction_type_field label.radio { display:inline-block; margin:0 .8em 0 .4em}</style>';
$option_keys = array_keys($this->options);
woocommerce_form_field( 'transaction_type', array(
'type' => 'radio',
'class' => array('transaction_type form-row-wide'),
'label' => __('Payment Information', $this->domain),
'options' => $this->options,
), reset( $option_keys ) );
}
/**
* Save the chosen payment type as order meta data.
*
* #param object $order
* #param array $data
*/
public function save_order_payment_type_meta_data( $order, $data ) {
if ( $data['payment_method'] === $this->id && isset($_POST['transaction_type']) )
$order->update_meta_data('_transaction_type', esc_attr($_POST['transaction_type']) );
}
/**
* Output for the order received page.
*
* #param int $order_id
*/
public function thankyou_page( $order_id ) {
$order = wc_get_order( $order_id );
if ( $this->instructions ) {
echo wpautop( wptexturize( $this->instructions ) );
}
}
/**
* Display the chosen payment type on the order edit pages (backend)
*
* #param object $order
*/
public function display_payment_type_order_edit_pages( $order ){
if( $this->id === $order->get_payment_method() && $order->get_meta('_transaction_type') ) {
$options = $this->options;
echo '<p><strong>'.__('Transaction type').':</strong> ' . $options[$order->get_meta('_transaction_type')] . '</p>';
}
}
/**
* Display the chosen payment type on order totals table
*
* #param array $total_rows
* #param WC_Order $order
* #param bool $tax_display
* #return array
*/
public function display_transaction_type_order_item_totals( $total_rows, $order, $tax_display ){
if( is_a( $order, 'WC_Order' ) && $order->get_meta('_transaction_type') ) {
$new_rows = []; // Initializing
$options = $this->options;
// Loop through order total lines
foreach( $total_rows as $total_key => $total_values ) {
$new_rows[$total_key] = $total_values;
if( $total_key === 'payment_method' ) {
$new_rows['payment_type'] = [
'label' => __("Transaction type", $this->domain) . ':',
'value' => $options[$order->get_meta('_transaction_type')],
];
}
}
$total_rows = $new_rows;
}
return $total_rows;
}
/**
* Add content to the WC emails.
*
* #access public
* #param WC_Order $order
* #param bool $sent_to_admin
* #param bool $plain_text
*/
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
if ( $this->instructions && ! $sent_to_admin && $this->id === $order->get_payment_method()
&& $order->has_status( $this->order_status ) ) {
echo wpautop( wptexturize( $this->instructions ) ) . PHP_EOL;
}
}
/**
* Process the payment and return the result
*
* #param int $order_id
* #return array
*/
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
// Mark as on-hold (we're awaiting the payment)
$order->update_status( $this->order_status, $this->status_text );
// Reduce stock levels
wc_reduce_stock_levels( $order->get_id() );
// Remove cart
WC()->cart->empty_cart();
// Return thankyou redirect
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
}
}
}
Code goes in as plugin php file that you can name as you want (and include it optionally in a folder). Zip the file (or the folder) and add it as a plugin via Wordpress. Activate it.
Tested and works.
On Email notifications:
I need help in generating new shipping method in woocommerce version 3+. The name for new field is "Nextday delivery". Like the flat rate it also need to be there in the method but it was not displayed in the drop down select field.
The below is the code which I tried. But it's not working for me.
function request_a_shipping_quote_init() {
if ( ! class_exists( 'WC_Request_Shipping_Quote_Method' ) ) {
class WC_Request_Shipping_Quote_Method extends WC_Shipping_Method {
public function __construct() {
$this->id = 'request_a_shipping_quote'; // Id for your shipping method. Should be uunique.
$this->method_title = __( 'Request a Shipping Quote' ); // Title shown in admin
$this->method_description = __( 'Shipping method to be used where the exact shipping amount needs to be quoted' ); // Description shown in admin
$this->title = "Request a Shipping Quote"; // This can be added as an setting but for this example its forced.
$this->supports = array(
'shipping-zones'
);
$this->init();
}
function init() {
$this->init_form_fields(); // This is part of the settings API. Override the method to add your own settings
$this->init_settings(); // This is part of the settings API. Loads settings you previously init.
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable', 'dc_raq' ),
'type' => 'checkbox',
'description' => __( 'Enable this shipping method.', 'dc_raq' ),
'default' => 'yes'
),
'title' => array(
'title' => __( 'Title', 'dc_raq' ),
'type' => 'text',
'description' => __( 'Title to be displayed on site', 'dc_raq' ),
'default' => __( 'Request a Quote', 'dc_raq' )
),
);
}
public function calculate_shipping( $packages = array() ) {
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => '0.00',
'calc_tax' => 'per_item'
);
$this->add_rate( $rate );
}
}
}
}
add_action( 'woocommerce_shipping_init', 'request_a_shipping_quote_init' );
function request_shipping_quote_shipping_method( $methods ) {
$methods['request_shipping_quote_shipping_method'] = 'WC_Request_Shipping_Quote_Method';
return $methods;
}
add_filter( 'woocommerce_shipping_methods', 'request_shipping_quote_shipping_method' );
I need it to come in the dropdown like flatrate free shipping etc but it was not coming in the dropdown.
There were some missing things and others unnecessary. The correct way to make it work is:
add_action('woocommerce_shipping_init', 'request_shipping_quote_method');
function request_shipping_quote_method() {
if ( ! class_exists( 'WC_Request_Shipping_Quote_Method' ) ) {
class WC_Request_Shipping_Quote_Method extends WC_Shipping_Method {
public function __construct( $instance_id = 0) {
$this->id = 'request_shipping_quote';
$this->instance_id = absint( $instance_id );
$this->domain = 'rasq';
$this->method_title = __( 'Request a Shipping Quote', $this->domain );
$this->method_description = __( 'Shipping method to be used where the exact shipping amount needs to be quoted', $this->domain );
$this->supports = array(
'shipping-zones',
'instance-settings',
'instance-settings-modal',
);
$this->init();
}
## Load the settings API
function init() {
$this->init_form_fields();
$this->init_settings();
$this->enabled = $this->get_option( 'enabled', $this->domain );
$this->title = $this->get_option( 'title', $this->domain );
$this->info = $this->get_option( 'info', $this->domain );
add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
}
function init_form_fields() {
$this->instance_form_fields = array(
'title' => array(
'type' => 'text',
'title' => __('Title', $this->domain),
'description' => __( 'Title to be displayed on site.', $this->domain ),
'default' => __( 'Request a Quote ', $this->domain ),
),
'cost' => array(
'type' => 'text',
'title' => __('Coast', $this->domain),
'description' => __( 'Enter a cost', $this->domain ),
'default' => '',
),
);
}
public function calculate_shipping( $packages = array() ) {
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => '0',
'calc_tax' => 'per_item'
);
$this->add_rate( $rate );
}
}
}
}
add_filter('woocommerce_shipping_methods', 'add_request_shipping_quote');
function add_request_shipping_quote( $methods ) {
$methods['request_shipping_quote'] = 'WC_Request_Shipping_Quote_Method';
return $methods;
}
Code goes in function.php file of your active child theme (active theme).
Tested and works.
Here the shipping method selector now displays this "Request a shipping coast" method:
Once selected and added, it's created this time:
If you edit it:
So I have created an add on plugin for WooCommerce. I have a custom class to extend the 'cheque' payment gateway to allow a user to perform a wholesale checkout without payment. So far this functionality works perfect. The issue is I cannot get the custom email to work with this custom payment. I'm not sure if i'm connecting the two custom classes together. Am I missing something in my trigger or using the wrong hook for the trigger?
Right here I include the email class..
function add_dealer_invoice_woocommerce_email( $email_classes ) {
// include our custom email class
require_once( 'includes/class-wc-dealer-invoice-email.php' );
// add the email class to the list of email classes that WooCommerce loads
$email_classes['WC_Dealer_Invoice_Email'] = new WC_Dealer_Invoice_Email();
return $email_classes;
}
add_filter( 'woocommerce_email_classes', 'add_dealer_invoice_woocommerce_email' );
// Register new status for woocomerce 2.2+
function register_dealer_invoice_order_status() {
register_post_status( 'wc-dealer-invoice', array(
'label' => 'Dealer Invoice',
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'Awaiting payment <span class="count">(%s)</span>', 'Awaiting payment <span class="count">(%s)</span>' )
) );
}
add_action( 'init', 'register_dealer_invoice_order_status' );
And here is the custom email class that extends WC_Email
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class WC_Dealer_Invoice_Email extends WC_Email {
public function __construct() {
// set ID, this simply needs to be a unique name
$this->id = 'wc_dealer_invoice';
// this is the title in WooCommerce Email settings
$this->title = 'Dealer Invoice';
// this is the description in WooCommerce email settings
$this->description = 'Dealer Invoice Notification emails are sent when a customer places a wholesale order on consignment';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'Dealer Invoice Order';
$this->subject = 'Dealer Invoice Order';
// these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
$this->template_html = 'emails/admin-new-order.php';
$this->template_plain = 'emails/plain/admin-new-order.php';
// Trigger on new paid orders
add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_checkout_order_processed', array( $this, 'trigger' ) );
// Call parent constructor to load any other defaults not explicity defined here
parent::__construct();
// this sets the recipient to the settings defined below in init_form_fields()
$this->recipient = $this->get_option( 'recipient' );
// if none was entered, just use the WP admin email as a fallback
if ( ! $this->recipient )
$this->recipient = get_option( 'admin_email' );
}
/**
* Determine if the email should actually be sent and setup email merge variables
*
* #since 0.1
* #param int $order_id
*/
public function trigger( $order_id ) {
// bail if no order ID is present
if ( ! $order_id )
return;
// setup order object
$this->object = new WC_Order( $order_id );
// bail if shipping method is not expedited
if ( 'cheque' != get_post_meta( $order_id, '_payment_method', true ))
return;
// replace variables in the subject/headings
$this->find[] = '{order_date}';
$this->replace[] = date_i18n( woocommerce_date_format(), strtotime( $this->object->order_date ) );
$this->find[] = '{order_number}';
$this->replace[] = $this->object->get_order_number();
if ( ! $this->is_enabled() || ! $this->get_recipient() )
return;
// woohoo, send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
/**
* get_content_html function.
*
* #since 0.1
* #return string
*/
public function get_content_html() {
ob_start();
woocommerce_get_template( $this->template_html, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* get_content_plain function.
*
* #since 0.1
* #return string
*/
public function get_content_plain() {
ob_start();
woocommerce_get_template( $this->template_plain, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* Initialize Settings Form Fields
*
* #since 2.0
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => 'Enable/Disable',
'type' => 'checkbox',
'label' => 'Enable this email notification',
'default' => 'yes'
),
'recipient' => array(
'title' => 'Recipient(s)',
'type' => 'text',
'description' => sprintf( 'Enter recipients (comma separated) for this email. Defaults to <code>%s</code>.', esc_attr( get_option( 'admin_email' ) ) ),
'placeholder' => '',
'default' => ''
),
'subject' => array(
'title' => 'Subject',
'type' => 'text',
'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->subject ),
'placeholder' => '',
'default' => ''
),
'heading' => array(
'title' => 'Email Heading',
'type' => 'text',
'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->heading ),
'placeholder' => '',
'default' => ''
),
'email_type' => array(
'title' => 'Email type',
'type' => 'select',
'description' => 'Choose which format of email to send.',
'default' => 'html',
'class' => 'email_type',
'options' => array(
'plain' => __( 'Plain text', 'woocommerce' ),
'html' => __( 'HTML', 'woocommerce' ),
'multipart' => __( 'Multipart', 'woocommerce' ),
)
)
);
}
} // end \WC_Dealer_Invoice_Email class
I think you just need to add a code to your function.php
add_filter('woocommerce_cart_needs_payment', '__return_false');
to allow users to send their orders without proceeding with payment. The email notification you can setup from woocommerce settings.
I would like to disable wire transfer payment method (bacs gateway) for a specific shipping method. I want customers to pay for the shipping if they select Cash on Delivery payment method but I want them also to get free shipping if they select wire transfer method.
I was able to disable COD if they select free shipping, but was not able to disable wire transfer if they select not-free shipping.
How can I disable BACS for that one particular shipping method?
I already had installed the WooCommerce Custom Payment Gateways plugin. That activates some more gateway options so I was working with it and edited one of it's classes.
The following is my modified version of woocommerce-custom-payment-gateways/class-wc-custom_payment_gateway_5.php
<?php
/**
* WC wcCpg5 Gateway Class.
* Built the wcCpg5 method.
*/
class WC_Custom_Payment_Gateway_5 extends WC_Gateway_BACS {
/**
* Constructor for the gateway.
*
* #return void
*/
public function __construct() {
global $woocommerce;
$this->id = 'wcCpg5';
$this->icon = apply_filters( 'woocommerce_wcCpg5_icon', '' );
$this->has_fields = false;
$this->method_title = __( 'Bacs', 'woocommerce' );
// Load the settings.
$this->init_form_fields();
$this->init_settings();
// Define user set variables
$this->title = $this->get_option( 'title' );
$this->description = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions', $this->description );
$this->enable_for_methods = $this->get_option( 'enable_for_methods', array() );
// BACS account fields shown on the thanks page and in emails
$this->account_details = get_option( 'woocommerce_bacs_accounts',
array(
array(
'account_name' => $this->get_option( 'account_name' ),
'account_number' => $this->get_option( 'account_number' ),
'sort_code' => $this->get_option( 'sort_code' ),
'bank_name' => $this->get_option( 'bank_name' ),
'iban' => $this->get_option( 'iban' ),
'bic' => $this->get_option( 'bic' )
)
)
);
// Actions
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'save_account_details' ) );
add_action( 'woocommerce_thankyou_bacs', array( $this, 'thankyou_page' ) );
// Customer Emails
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
// Actions.
if ( version_compare( WOOCOMMERCE_VERSION, '2.0.0', '>=' ) )
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( &$this, 'process_admin_options' ) );
else
add_action( 'woocommerce_update_options_payment_gateways', array( &$this, 'process_admin_options' ) );
}
/* Admin Panel Options.*/
function admin_options() {
?>
<h3><?php _e('Custom Payment Gateways 5','wcwcCpg5'); ?></h3>
<table class="form-table">
<?php $this->generate_settings_html(); ?>
</table> <?php
}
/* Initialise Gateway Settings Form Fields. */
public function init_form_fields() {
$shipping_methods = array();
if ( is_admin() )
foreach ( WC()->shipping->load_shipping_methods() as $method ) {
$shipping_methods[ $method->id ] = $method->get_title();
}
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable Bank Transfer', 'woocommerce' ),
'default' => 'yes'
),
'title' => array(
'title' => __( 'Title', 'woocommerce' ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
'default' => __( 'Direct Bank Transfer', 'woocommerce' ),
'desc_tip' => true,
),
'description' => array(
'title' => __( 'Description', 'woocommerce' ),
'type' => 'textarea',
'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce' ),
'default' => __( 'Make your payment directly into our bank account. Please use your Order ID as the payment reference. Your order won\'t be shipped until the funds have cleared in our account.', 'woocommerce' ),
'desc_tip' => true,
),
'instructions' => array(
'title' => __( 'Instructions', 'woocommerce' ),
'type' => 'textarea',
'description' => __( 'Instructions that will be added to the thank you page and emails.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
),
'account_details' => array(
'type' => 'account_details'
),
'enable_for_methods' => array(
'title' => __( 'Enable for shipping methods', 'woocommerce' ),
'type' => 'multiselect',
'class' => 'chosen_select',
'css' => 'width: 450px;',
'default' => '',
'description' => __( 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', 'woocommerce' ),
'options' => $shipping_methods,
'desc_tip' => true,
'custom_attributes' => array(
'data-placeholder' => __( 'Select shipping methods', 'woocommerce' )
)
)
);
}
/**
* Check If The Gateway Is Available For Use
*
* #return bool
*/
public function is_available() {
$order = null;
if ( ! $this->enable_for_virtual ) {
if ( WC()->cart && ! WC()->cart->needs_shipping() ) {
return false;
}
if ( is_page( wc_get_page_id( 'checkout' ) ) && 0 < get_query_var( 'order-pay' ) ) {
$order_id = absint( get_query_var( 'order-pay' ) );
$order = wc_get_order( $order_id );
// Test if order needs shipping.
$needs_shipping = false;
if ( 0 < sizeof( $order->get_items() ) ) {
foreach ( $order->get_items() as $item ) {
$_product = $order->get_product_from_item( $item );
if ( $_product->needs_shipping() ) {
$needs_shipping = true;
break;
}
}
}
$needs_shipping = apply_filters( 'woocommerce_cart_needs_shipping', $needs_shipping );
if ( $needs_shipping ) {
return false;
}
}
}
if ( ! empty( $this->enable_for_methods ) ) {
// Only apply if all packages are being shipped via local pickup
$chosen_shipping_methods_session = WC()->session->get( 'chosen_shipping_methods' );
if ( isset( $chosen_shipping_methods_session ) ) {
$chosen_shipping_methods = array_unique( $chosen_shipping_methods_session );
} else {
$chosen_shipping_methods = array();
}
$check_method = false;
if ( is_object( $order ) ) {
if ( $order->shipping_method ) {
$check_method = $order->shipping_method;
}
} elseif ( empty( $chosen_shipping_methods ) || sizeof( $chosen_shipping_methods ) > 1 ) {
$check_method = false;
} elseif ( sizeof( $chosen_shipping_methods ) == 1 ) {
$check_method = $chosen_shipping_methods[0];
}
if ( ! $check_method ) {
return false;
}
$found = false;
foreach ( $this->enable_for_methods as $method_id ) {
if ( strpos( $check_method, $method_id ) === 0 ) {
$found = true;
break;
}
}
if ( ! $found ) {
return false;
}
}
return parent::is_available();
}
}
with this you have the option to enable bacs for shipping methods