WooCommerce: Send a Custom Email on Order Status Change

If you use custom WooCommerce order statuses, sending emails is quite complex because you need to code a full custom email PHP class.

At least on paper!

In this workaround, we will actually “use” one of the existing email classes (note: it must be active in your WooCommerce email settings in order to work), change the subject and heading, and trigger it – like if it were a custom order status email.

Enjoy!

Send a custom email when an order is marked with custom status – WooCommerce

PHP Snippet: Send WooCommerce Email @ Custom Order Status

/**
 * @snippet       Send Formatted Email @ WooCommerce Custom Order Status
 * @how-to        businessbloomer.com/woocommerce-customization
 * @author        Rodolfo Melogli, Business Bloomer
 * @compatible    WooCommerce 8
 * @community     https://businessbloomer.com/club/
 */
 
// Targets custom order status "refused"
// Uses "'woocommerce_order_status_' . $status" hook
 
add_action( 'woocommerce_order_status_refused', 'bbloomer_status_custom_notification', 20, 2 );
 
function bbloomer_status_custom_notification( $order_id, $order ) {
     
    $subject = 'Order Refused';
    $heading = 'Sorry!';
 
    // Get WooCommerce email objects
    $mailer = WC()->mailer()->get_emails();
 
    // Use one of the active emails e.g. "Customer_Completed_Order"
    // Wont work if you choose an object that is not active
    // Assign heading & subject to chosen object
    $mailer['WC_Email_Customer_Completed_Order']->settings['heading'] = $heading;
    $mailer['WC_Email_Customer_Completed_Order']->settings['subject'] = $subject;
 
    // Send the email with custom heading & subject
    $mailer['WC_Email_Customer_Completed_Order']->trigger( $order_id );
 
    // To add email content use https://businessbloomer.com/woocommerce-add-extra-content-order-email/
    // You have to use the email ID chosen above and check that $order->get_status() == "refused"
     
}

Here’s a full list of default WooCommerce email classes you can use in the snippet above:

  1. WC_Email_New_Order: Sent to the store admin when a new order is created.
  2. WC_Email_Cancelled_Order: Sent to the store admin when an order is cancelled.
  3. WC_Email_Failed_Order: Sent to the store admin when an order fails.
  4. WC_Email_Customer_On_Hold_Order: Sent to the customer when an order is placed on hold.
  5. WC_Email_Customer_Processing_Order: Sent to the customer after payment and contains the order details.
  6. WC_Email_Customer_Completed_Order: Sent to the customer when the order is marked as completed.
  7. WC_Email_Customer_Refunded_Order: Sent to the customer when an order is refunded.
  8. WC_Email_Customer_Invoice: Sent to the customer with order details and payment link.
  9. WC_Email_Customer_Note: Sent to the customer when a customer note is added to their order.
  10. WC_Email_Customer_Reset_Password: Sent to the customer when they request a password reset.
  11. WC_Email_Customer_New_Account: Sent to the customer when a new account is created.

These classes are located in the includes/emails directory of the WooCommerce plugin. They can be extended or customized by creating new classes that extend these base classes if you need to modify the default email behavior.

Where to add custom code?

You should place custom PHP in functions.php and custom CSS in style.css of your child theme: where to place WooCommerce customization?

This code still works, unless you report otherwise. To exclude conflicts, temporarily switch to the Storefront theme, disable all plugins except WooCommerce, and test the snippet again: WooCommerce troubleshooting 101

Related content

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza. Follow @rmelogli

32 thoughts on “WooCommerce: Send a Custom Email on Order Status Change

  1. Hi Rodolfo,

    Just wanted to ask what is the best way to apply this PHP code if my theme is deactivated because I am using Oxygen Builder.?

    Many Thanks,
    oli

    1. Use the Code Snippets plugin

  2. Hi there,
    I have a status using this plugin named “reminder”. Now I have also created email template for that reminder as well.
    Now I want to add this email as trigger in processing order email. I mean to say that whenever I change status from reminder to processing. The processing email should be sent to customer. It is not sending right now.
    How can I achieve this?
    Thanks

    1. Hi Mujahid thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  3. Hi, how can I change the snippet to send emails for 2 different custom order statuses? Thanks

    1. Hi Radek, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  4. Hi, We used a plugin to add custom “shipped” status to order and used your snippet to send customer email with customized heading and subject. It works perfectly for a while, and we only noticed a problem since this morning:

    the email can still be send out after changing order status to “shipped”(that means it still triggers the action),
    but the custom subject and headings are gone, our customers are getting “Order completed email” including heading and subject.

    Any updated from WordPress or Woocommerce that caused the issue? what other way to change subject or heading of the email?

    Thanks a lot

    1. Hi Damon, that’s weird. To troubleshoot, disable all plugins but WooCommerce and also switch temporarily to “Twentytwenty” theme (load the snippet there in functions.php) as explained here: https://www.businessbloomer.com/lesson/trwm4l01/

      Once you do that, does it work? If yes, you have a problem with your current theme or one of the plugins.

      Hope this helps!

  5. Hi Rodolfo ,

    I have put a comment here before but it doesn’t seem to have been approved…

    Everything works wonderfully well but it will only send the email if it specifies the WC_Email_Customer_Completed_Order email. If you try and specify one that is unused such as ‘On Hold’ and use the correct hooks, it fails and won’t finish the cycle. Change it back to the completed order email and works again without issue.

    Any thoughts why this may be? The email is turned on, not used for anything else and I have re-created this on two different sites? Thank you

    1. Sorry I have no idea. Sure the On Hold is enabled?

  6. Hi Rodolfo, it’s not working on my website…

    1. function wpblog_wc_register_post_statuses() {
      register_post_status( 'wc-shipped', array(
      'label' => _x( 'Shipped', 'WooCommerce Order status', 'text_domain' ),
      'public' => true,
      'exclude_from_search' => false,
      'show_in_admin_all_list' => true,
      'show_in_admin_status_list' => true,
      'label_count' => _n_noop( 'Approved (%s)', 'Approved (%s)', 'text_domain' )
      ) );
      }
      add_filter( 'init', 'wpblog_wc_register_post_statuses' );
      
      function wpblog_wc_add_order_statuses( $order_statuses ) {
      $order_statuses['wc-shipped'] = _x( 'Shipped', 'WooCommerce Order status', 'text_domain' );
      return $order_statuses;
      }
      add_filter( 'wc_order_statuses', 'wpblog_wc_add_order_statuses' );
      
      /**
       * @snippet       Send Formatted Email @ WooCommerce Custom Order Status
       * @how-to        businessbloomer.com/woocommerce-customization
       * @sourcecode    https://businessbloomer.com/?p=91907
       * @author        Rodolfo Melogli, Business Bloomer
       * @compatible    WooCommerce 3.5.7
       * @community     https://businessbloomer.com/club/
       */
        
      // Targets custom order status "shipped"
      // Uses 'woocommerce_order_status_' hook
        
      add_action( 'woocommerce_order_status_shipped', 'bbloomer_status_custom_notification', 20, 2 );
        
      function bbloomer_status_custom_notification( $order_id, $order ) {
            
          $heading = 'Order Shipped';
          $subject = 'Order Shipped';
        
          // Get WooCommerce email objects
          $mailer = WC()->mailer()->get_emails();
        
          // Use one of the active emails e.g. "Customer_Completed_Order"
          // Wont work if you choose an object that is not active
          // Assign heading & subject to chosen object
          $mailer['WC_Email_Customer_Completed_Order']->heading = $heading;
          $mailer['WC_Email_Customer_Completed_Order']->settings['heading'] = $heading;
          $mailer['WC_Email_Customer_Completed_Order']->subject = $subject;
          $mailer['WC_Email_Customer_Completed_Order']->settings['subject'] = $subject;
        
          // Send the email with custom heading & subject
          $mailer['WC_Email_Customer_Completed_Order']->trigger( $order_id );
        
          // To add email content use https://businessbloomer.com/woocommerce-add-extra-content-order-email/
          // You have to use the email ID chosen above and also that $order->get_status() == "shipped"
            
      }
      
      1. Sure “shipped” is the correct email ID?

        1. I’m sorry but what do you mean by email ID? Completely new to PHP πŸ™

          1. Hi it’s now working! There’s conflict with my other plugin.

            1. The only problem is it doesn’t send email to gmail or yahoo. I can only receive notification from the custom status if sending to my own email domain.

              1. Not sure Jackie, but well done for figuring that out

  7. Hi it’s not working for me πŸ™ I’ve changed “refused” to “shipped”.

  8. Hey! How can I get a webhook for a custom order status and By replacing the webhook of refuse from the above code, will It work as same

    1. Hi Mudit, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  9. Hi,

    I’m looking to create 2 Order Statuses for Preorders.

    Preorder On-hold (Before Payment) –> Copy Email template from On-Hold
    Preorder Processing (Confirmed after Payment) –> Copy Email template from Processing

    There will be a Preorder Stock status as well, how can I create that using functions.php too?

    Preorder On-hold will be triggered when Customer buys a Preorder product(Preorder stock status), and pends for BACS payment like the rest of the normal instock items.

    Preorder Processing will be manually triggered by myself when Customer made payment.

    I actually see that its possible to create using your above coding but got confused…… I supposed the Order status should be separately created? (Your Order Status here is Refused)

    Thanks.

    1. Yes

  10. How to get custom mails as admin for order payment finished via PayPal? When you don’t use the PayPal notifications because it’s the secondary PayPal mail.

    1. Hi Andre, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  11. Hey, where am I supposed to include the custom status slug/name? I see you commented that I should include “$order->get_status() == “refused” ” but where? Cheers!

    1. Hey Joao! Just change “refused” with your custom order slug here:

      add_action( 'woocommerce_order_status_refused'
  12. Hi, thank you for this information. I’m interested in the following. After a payment is made in Woocommerce we place the order into ‘Processing’ than 5 business days later we change the status to ‘Awaiting Shipping’, using the following plugin to add a custom email then after the item ships we mark the order status as ‘Completed’.

    We would like to automate the part that changes the status to ‘Awaiting Shipping’. Is that possible? So after 5 business days, the order status updates automatically to Awaiting Shipping.

    1. Hi there, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  13. Hey, will this allow my website to send “delivery on route” emails? Also are these emails automatic after installing your code ?

    1. Hello Jacqui, yes & yes πŸ™‚

  14. Where do I add content from https://businessbloomer.com/woocommerce-add-extra-content-order-email/
    Within same function ?
    Pl advice with example. thanks.

    1. Hey Kumar, it’s explained in the snippet comments. Unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. Thanks a lot for your understanding! ~R

Questions? Feedback? Customization? Leave your comment now!
_____

If you are writing code, please wrap it like so: [php]code_here[/php]. Failure to complying with this, as well as going off topic or not using the English language will result in comment disapproval. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining the Business Bloomer Club to get quick WooCommerce support. Thank you!

Your email address will not be published. Required fields are marked *