skip to Main Content

I’ve registered custom order statuses in a plugin I’m working on, but I can’t get emails to fire when moving in or out of one of these statuses. (including to/from a core status, ie. the processing/completed emails don’t fire when moving from a custom status).

I’ve registered every possible combination of actions I can think of (excluding on-hold and pending, based on our use case)

Can anyone tell me what I’m missing please?

Initial class:

<?php
/**
 * @author BAKKBONE Australia
 * @package Bkf_WC_Email
 * @license GNU General Public License (GPL) 3.0
**/

if ( ! defined( 'ABSPATH' ) ) {
    return;
}

/**
 * Class Bkf_WC_Email
 */
class Bkf_WC_Email {

    /**
     * Bkf_WC_Email constructor.
     */
    public function __construct() {
        add_action( 'woocommerce_email_classes', array( $this, 'bkf_register_email' ), 90, 1 );
        define( 'CUSTOM_WC_EMAIL_PATH', plugin_dir_path( __FILE__ ) );
        add_filter('woocommerce_email_actions', array($this, 'bkf_woocommerce_email_actions'), 10, 1);
    }

    /**
     * @param array $emails
     *
     * @return array
     */
    public function bkf_register_email( $emails ) {
        $emails['WC_Email_Customer_Scheduled_Order'] = include __DIR__ . 'emails/class-wc-customer-scheduled-order.php';
        $emails['WC_Email_Customer_Prepared_Order'] = include __DIR__ . 'emails/class-wc-customer-made-order.php';
        $emails['WC_Email_Customer_Out_for_Delivery_Order'] = include __DIR__ . 'emails/class-wc-customer-out-order.php';

        return $emails;
    }

    public function bkf_woocommerce_email_actions($actions)
    {
$actions[] = 'woocommerce_order_status_scheduled';
$actions[] = 'woocommerce_order_status_made';
$actions[] = 'woocommerce_order_status_out';
$actions[] = 'woocommerce_order_status_relay';
$actions[] = 'woocommerce_order_status_processing';
$actions[] = 'woocommerce_order_status_completed';
$actions[] = 'woocommerce_order_status_scheduled_to_made';
$actions[] = 'woocommerce_order_status_scheduled_to_out';
$actions[] = 'woocommerce_order_status_scheduled_to_relay';
$actions[] = 'woocommerce_order_status_scheduled_to_processing';
$actions[] = 'woocommerce_order_status_scheduled_to_completed';
$actions[] = 'woocommerce_order_status_made_to_scheduled';
$actions[] = 'woocommerce_order_status_made_to_out';
$actions[] = 'woocommerce_order_status_made_to_relay';
$actions[] = 'woocommerce_order_status_made_to_processing';
$actions[] = 'woocommerce_order_status_made_to_completed';
$actions[] = 'woocommerce_order_status_out_to_scheduled';
$actions[] = 'woocommerce_order_status_out_to_made';
$actions[] = 'woocommerce_order_status_out_to_relay';
$actions[] = 'woocommerce_order_status_out_to_processing';
$actions[] = 'woocommerce_order_status_out_to_completed';
$actions[] = 'woocommerce_order_status_relay_to_scheduled';
$actions[] = 'woocommerce_order_status_relay_to_made';
$actions[] = 'woocommerce_order_status_relay_to_out';
$actions[] = 'woocommerce_order_status_relay_to_processing';
$actions[] = 'woocommerce_order_status_relay_to_completed';
$actions[] = 'woocommerce_order_status_processing_to_scheduled';
$actions[] = 'woocommerce_order_status_processing_to_made';
$actions[] = 'woocommerce_order_status_processing_to_out';
$actions[] = 'woocommerce_order_status_processing_to_relay';
$actions[] = 'woocommerce_order_status_processing_to_completed';
$actions[] = 'woocommerce_order_status_completed_to_scheduled';
$actions[] = 'woocommerce_order_status_completed_to_made';
$actions[] = 'woocommerce_order_status_completed_to_out';
$actions[] = 'woocommerce_order_status_completed_to_relay';
$actions[] = 'woocommerce_order_status_completed_to_processing';
        $bkfoptions = get_option("bkf_options_setting");
        if($bkfoptions["bkf_petals"] == "1") {
$actions[] = 'woocommerce_order_status_new';
$actions[] = 'woocommerce_order_status_accept';
$actions[] = 'woocommerce_order_status_reject';
$actions[] = 'woocommerce_order_status_scheduled_to_new';
$actions[] = 'woocommerce_order_status_scheduled_to_accept';
$actions[] = 'woocommerce_order_status_scheduled_to_reject';
$actions[] = 'woocommerce_order_status_made_to_new';
$actions[] = 'woocommerce_order_status_made_to_accept';
$actions[] = 'woocommerce_order_status_made_to_reject';
$actions[] = 'woocommerce_order_status_out_to_new';
$actions[] = 'woocommerce_order_status_out_to_accept';
$actions[] = 'woocommerce_order_status_out_to_reject';
$actions[] = 'woocommerce_order_status_relay_to_new';
$actions[] = 'woocommerce_order_status_relay_to_accept';
$actions[] = 'woocommerce_order_status_relay_to_reject';
$actions[] = 'woocommerce_order_status_processing_to_new';
$actions[] = 'woocommerce_order_status_processing_to_accept';
$actions[] = 'woocommerce_order_status_processing_to_reject';
$actions[] = 'woocommerce_order_status_completed_to_new';
$actions[] = 'woocommerce_order_status_completed_to_accept';
$actions[] = 'woocommerce_order_status_completed_to_reject';
$actions[] = 'woocommerce_order_status_new_to_scheduled';
$actions[] = 'woocommerce_order_status_new_to_made';
$actions[] = 'woocommerce_order_status_new_to_out';
$actions[] = 'woocommerce_order_status_new_to_relay';
$actions[] = 'woocommerce_order_status_new_to_processing';
$actions[] = 'woocommerce_order_status_new_to_completed';
$actions[] = 'woocommerce_order_status_new_to_accept';
$actions[] = 'woocommerce_order_status_new_to_reject';
$actions[] = 'woocommerce_order_status_accept_to_scheduled';
$actions[] = 'woocommerce_order_status_accept_to_made';
$actions[] = 'woocommerce_order_status_accept_to_out';
$actions[] = 'woocommerce_order_status_accept_to_relay';
$actions[] = 'woocommerce_order_status_accept_to_processing';
$actions[] = 'woocommerce_order_status_accept_to_completed';
$actions[] = 'woocommerce_order_status_accept_to_new';
$actions[] = 'woocommerce_order_status_accept_to_reject';
$actions[] = 'woocommerce_order_status_reject_to_scheduled';
$actions[] = 'woocommerce_order_status_reject_to_made';
$actions[] = 'woocommerce_order_status_reject_to_out';
$actions[] = 'woocommerce_order_status_reject_to_relay';
$actions[] = 'woocommerce_order_status_reject_to_processing';
$actions[] = 'woocommerce_order_status_reject_to_completed';
$actions[] = 'woocommerce_order_status_reject_to_new';
$actions[] = 'woocommerce_order_status_reject_to_accept';
        }
        return $actions;
    }
  
}

new Bkf_WC_Email();

Specific email’s class:

<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

if ( ! class_exists( 'WC_Email' ) ) {
    return;
}

/**
 * Class WC_Email_Customer_Out_for_Delivery_Order
 */
class WC_Email_Customer_Out_for_Delivery_Order extends WC_Email {

    /**
     * Create an instance of the class.
     *
     * @access public
     * @return void
     */
    function __construct() {

        $this->id          = 'customer_out_order';
        $this->title       = __( 'Order Out for Delivery', 'woocommerce' );
        $this->description = __( 'An email sent to the customer when an order is out for delivery.', 'woocommerce' );
        $this->customer_email = true;
        $this->heading     = __( 'Order Out for Delivery', 'woocommerce' );
        $this->subject     = sprintf( _x( '[%s] Order Out for Delivery', 'default email subject for out for delivery emails', 'woocommerce' ), '{blogname}' );

        $this->template_html  = 'emails/customer-out-order.php';
        $this->template_plain = 'emails/plain/customer-out-order.php';
        $this->template_base  = CUSTOM_WC_EMAIL_PATH . 'templates/';

        add_action( 'woocommerce_order_status_out', array( $this, 'trigger' ) );

        parent::__construct();
    }

    /**
     * Trigger Function that will send this email to the customer.
     *
     * @access public
     * @return void
     */
    function trigger( $order_id ) {
        $this->object = wc_get_order( $order_id );

        if ( version_compare( '3.0.0', WC()->version, '>' ) ) {
            $order_email = $this->object->billing_email;
        } else {
            $order_email = $this->object->get_billing_email();
        }

        $this->recipient = $order_email;


        if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
            return;
        }

        $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
    }

    /**
     * Get content html.
     *
     * @access public
     * @return string
     */
    public function get_content_html() {
        return wc_get_template_html( $this->template_html, array(
            'order'         => $this->object,
            'email_heading' => $this->get_heading(),
            'additional_content' => $this->get_additional_content(),
            'sent_to_admin' => false,
            'plain_text'    => false,
            'email'         => $this
        ), '', $this->template_base );
    }

    /**
     * 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(),
            'additional_content' => $this->get_additional_content(),
            'sent_to_admin' => false,
            'plain_text'    => true,
            'email'         => $this
        ), '', $this->template_base );
    }

}

return new WC_Email_Customer_Out_for_Delivery_Order();

I welcome any ideas 🙂

2

Answers


  1. I think you are missing the triggers. Try to hook into woocommerce_order_status_changed action and fire your e-mails as you wish based on $from and $to statuses.

    Here’s a preview with 3 examples:

    function custom_woocommerce_order_status_changed( $order_id, $from, $to, $order ) {
    
        // Get all WC mailer emails
        $wc_emails = WC()->mailer()->get_emails();
    
        // Example A: Handle (from) 'my-custom-status' triggers
        if( $from == 'my-custom-status' ) {
    
            // Trigger 'completed' e-mail if changing to 'completed'
            if( $to == 'completed' ) {
                $wc_emails['WC_Email_Customer_Completed_Order']->trigger( $order_id );
            }
        }
    
        // Example B: Handle (from) 'processing' triggers
        if( $from == 'processing' ) {
    
            // Trigger 'my-custom-status' e-mail if changing to 'my-custom-status'
            if( $to == 'my-custom-status' ) {
                $wc_emails['WC_Email_Customer_My_Custom_Status_Order']->trigger( $order_id );
            }
        }
    
        // Example C: Handle (to) 'my-custom-status' triggers
        // This will fire the email for every order changed to this status (whatever the $from status is)
        if( $to == 'my-custom-status' ) {
            $wc_emails['WC_Email_Customer_My_Custom_Status_Order']->trigger( $order_id );
        }
    }
    add_action( 'woocommerce_order_status_changed', 'custom_woocommerce_order_status_changed', 20, 4 );
    

    Note: Try to write these conditions as simply and straightforward as you can. Remember that if your order change scenario will be a duplicate, the e-mail will be also triggered (sent) multiple times.

    Login or Signup to reply.
  2. Seems like you forgot to add "_notification" suffix to your email action hook call, so in your case:

    add_action( 'woocommerce_order_status_out_notification', array( $this, 'trigger' ) );
    

    For anybody else trying to figure out what all needs to be set up for the action hooks only, I’ll try to summ up here what I found today:

    Class WC_Emails actually contains own set of action hooks (see WC_Emails::init_transactional_emails()) for which it is allowed to send "notifications".

    If you want to send email using your own custom action hook you defined somewhere before in the WordPress, you need to first add it to WC_Emails registered hooks using the woocommerce_email_actions filter.

    function add_custom_hook_actions ($email_actions) {
        $email_actions[] = 'woocommerce_order_status_your-own-status';
        $email_actions[] = 'another_random_action_hook';
        return $email_actions;
    };
    add_filter('woocommerce_email_actions', 'add_custom_hook_actions');
    

    These WC_Emails registered action hooks then can be used in your WC_Email extending template class, calling defined WC_Email registered hook with "_notification" suffix.

    class WC_Email_Awesome_Custom_Template extends WC_Email
    {
    
        /**
         * Class constructor.
         */
        public function __construct()
        {
            // ... some code to define email template
    
            // Triggers for this email.
            add_action(
                'woocommerce_order_status_your-own-status_notification', 
                array($this, 'trigger'),
                10,
                1
            );
            add_action(
                'another_random_action_hook_notification', 
                array($this, 'trigger'),
                10,
                1
            );
            
            // ... rest of the constructor
        }
    
        // ... rest of the class
    }
    

    Or you can call it using the mailer directly wherever needed, similarly to the way already described here by others.

    WC()->mailer()->emails['WC_Email_Awesome_Custom_Template']->trigger($order->get_id(), $order, true);
    

    Hopefully it saves someone time.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search