WooCommerce: Set Custom Order Status for New Orders

All WooCommerce orders go to either “processing”, “completed”, “on-hold” and other default order statuses based on the payment method and product type.

Sometimes these statuses are not enough. For example, you might need to mark certain orders in a different way for tracking, filtering, exporting purposes. Or you might want to disable default emails by bypassing the default order status changes.

Either way, setting a custom order status automatically once the order is processed is quite easy. And today we’ll see which PHP snippets you need in order to make this work!

WooCommerce: set a custom order status during checkout

PHP Snippet: Assign Custom Order Status during WooCommerce Checkout Process

* @snippet       Set Custom Order Status during Checkout
* @how-to        Watch tutorial @ https://businessbloomer.com/?p=19055 
* @sourcecode    https://businessbloomer.com/?p=77911
* @author        Rodolfo Melogli 
* @compatible    WooCommerce 3.5.4
* @donate $9     https://businessbloomer.com/bloomer-armada/

// ---------------------
// 1. Register Order Status

add_filter( 'woocommerce_register_shop_order_post_statuses', 'bbloomer_register_custom_order_status' );

function bbloomer_register_custom_order_status( $order_statuses ){
	// Status must start with "wc-"
	$order_statuses['wc-custom-status'] = array(											
	'label'                     => _x( 'Custom Status', 'Order status', 'woocommerce' ),
	'public'                    => false,											
	'exclude_from_search'       => false,											
	'show_in_admin_all_list'    => true,											
	'show_in_admin_status_list' => true,											
	'label_count'               => _n_noop( 'Custom Status <span class="count">(%s)</span>', 'Custom Status <span class="count">(%s)</span>', 'woocommerce' ),										
	return $order_statuses;

// ---------------------
// 2. Show Order Status in the Dropdown @ Single Order and "Bulk Actions" @ Orders

add_filter( 'wc_order_statuses', 'bbloomer_show_custom_order_status' );

function bbloomer_show_custom_order_status( $order_statuses ) {	   
	$order_statuses['wc-custom-status'] = _x( 'Custom Status', 'Order status', 'woocommerce' );       
	return $order_statuses;

add_filter( 'bulk_actions-edit-shop_order', 'bbloomer_get_custom_order_status_bulk' );

function bbloomer_get_custom_order_status_bulk( $bulk_actions ) {
	// Note: "mark_" must be there instead of "wc"
	$bulk_actions['mark_custom-status'] = 'Change status to custom status';
	return $bulk_actions;

// ---------------------
// 3. Set Custom Order Status @ WooCommerce Checkout Process

add_action( 'woocommerce_thankyou', 'bbloomer_thankyou_change_order_status' );

function bbloomer_thankyou_change_order_status( $order_id ){
	if( ! $order_id ) return;
	$order = wc_get_order( $order_id );

	// Status without the "wc-" prefix
	$order->update_status( 'custom-status' );

Where to add this code?

You can place PHP snippets at the bottom of your child theme functions.php file (before "?>" if you have it). CSS, on the other hand, goes in your child theme style.css file. Make sure you know what you are doing when editing such delicate files - if you need more guidance, please take a look at my free WooCommerce Customization video tutorial.

Does this snippet still work?

Please let me know in the comments if everything worked as expected. I would be happy to revise the snippet if you report otherwise (please provide screenshots). I have tested this code with Storefront theme, the WooCommerce version listed above and a WordPress-friendly hosting on PHP 7.

If you think this code saved you time & money, please join other Business Bloomer supporters and avail of 365 days of WooCommerce benefits. Thank you in advance :)

Need Help with WooCommerce?

Check out these free videos, tutorials and tips!

  • how-to-edit-woocommerce-with-php-snippets
  • woocommerce-hooks-add_action-list-visual
  • woocommerce-customize-single-product-page-PHP
  • woocommerce-customize-shop-page-PHP
  • woocommerce-advanced-customization
  • how-to-edit-woocommerce-cart
  • woocommerce-customize-checkout-page-PHP
  • woocommerce-email-customization
  • woocommerce-conditional-logic

Rodolfo Melogli

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as a 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.

35 thoughts on “WooCommerce: Set Custom Order Status for New Orders

  1. Hi Rodolfo!

    This looks great, exactly what I was looking for.

    Just a small additional question; is it possible to add a custom order status to order from specific countries? I’m based in the EU, so i need a custom order status for order from U.S. & Canada for the logistic party to pick it up.

    Hopefully, there’s a way… I’ve tried everything. Thank you in advance. ๐Ÿ™‚

    Kind Regards,

    Jeroen Feron

    1. Hello Jeroen, 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!

  2. Hi
    I am new to Woocommerce, but I am familiar with PHP
    I want to set status=on hold on all new orders IF customer wrote an order note.

    so i imagine that the logic should look something like this

    if ($order-&gt;get_customer_note()){
        $order-&gt;update_status( 'pending' ); // is "on hold" = pending???

    Thank You ๐Ÿ™‚

    1. would this do the trick???? (youre welcome to copy)

      // ---------------------
      // Set Order Status Pending If Customer Wrote A Note @ WooCommerce Checkout Process
      add_action( 'woocommerce_thankyou', 'bbloomer_thankyou_change_order_status' );
      function bbloomer_thankyou_change_order_status( $order_id ){
          if( ! $order_id ) return;
          $order = wc_get_order( $order_id );
          if ($order-&gt;get_customer_note()){
              // Status with or without the "wc-" prefix ??????
              $order-&gt;update_status( 'pending' ); //wc-pending
    2. Hey Michael, thanks for your comment! Did you test it?

  3. It works great, TYVM for this. Can this code be used to do two or more custom order status’?

    1. Excellent! Yes it can ๐Ÿ™‚

  4. Hi, every thing seems to be working correctly. But I am facing with this strange thing, that if order has this new custom status and I change the status to “Processing” then the email for processing status is not sent. But if the status is “Pending” and you change to “Processing” then everything works correctly. Do you have any ideas about this issue?

    1. Hello Kipras, thanks so much for your comment! Unfortunately this looks like custom troubleshooting work and I cannot help here via the blog comments. Thanks a lot for your understanding! ~

  5. Hi Rodolfo,

    following your code, i had an issue with admin order list page. When i open this page i can’t see previous orders anymore because of the ‘wc_order_statuses’ filter, with your structure.
    I had to set my code like this in order to work:

    function register_new_wc_order_statuses() {
        $order_statuses = array(
            'wc-first' =&gt; array(
                'label'                     =&gt; _x( 'Status 1', 'Order status', 'woocommerce' ),
                'public'                    =&gt; true,
                'exclude_from_search'       =&gt; false,
                'show_in_admin_all_list'    =&gt; true,
                'show_in_admin_status_list' =&gt; true,
                /* translators: %s: number of orders */
                'label_count'               =&gt; _n_noop( 'Status 1 (%s)', 'Status 1 (%s)', 'woocommerce' ),
            'wc-second' =&gt; array(
                'label'                     =&gt; _x( 'Status 2', 'Order status', 'woocommerce' ),
                'public'                    =&gt; true,
                'exclude_from_search'       =&gt; false,
                'show_in_admin_all_list'    =&gt; true,
                'show_in_admin_status_list' =&gt; true,
                /* translators: %s: number of orders */
                'label_count'               =&gt; _n_noop( 'Status 2 (%s)', 'Status 2 (%s)', 'woocommerce' ),
        foreach ( $order_statuses as $order_status =&gt; $values ) :
            register_post_status( $order_status, $values );
    add_action( 'init', 'register_new_wc_order_statuses' );
    function show_new_wc_order_statuses( $order_statuses ) {
        $order_statuses['wc-first']  = _x( 'Status 1', 'WooCommerce Order status', 'woocommerce' );
        $order_statuses['wc-second'] = _x( 'Status 2', 'WooCommerce Order status', 'woocommerce' );
        return $order_statuses;
    add_filter( 'wc_order_statuses', 'show_new_wc_order_statuses' );


    1. Thanks ๐Ÿ™‚

  6. Good day,
    Pls how can i set custom order status for a particular payment gateway, example i want all orders made using a particular payment gateway to be in waiting payment status or pending quote status uisng the yith woocommerce request quote plugin..
    Please how can i do this?

    1. Hey Chris, thanks so much for your comment! Yes, this is possible – unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. Thanks a lot for your understanding! ~R

  7. Is it possible to use a snippet:

    When shipping an order:
    order has balance outstanding ($ owing)
    update status to custom status: account receivable
    send different email than status completed email. eg ac-rec invoice

    — Moving from Drupal.. so its a bit of a learning curve.
    Cheers for the tips!

    1. Hey Crab, thanks so much for your comment! Yes, this is possible – unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding! ~R

  8. Hi

    Great tip, thanks very much. One question, is it possible to have two custom statuses, by doing a modification of your code?

    Reason for asking; we want to use the commerce engine primarily for quotes. by having two statuses we would have one for “quote in progress” and quote sent. Both without sending any mails (which is great).


    1. Hey Knut, thanks so much for your comment! Yes, this is possible – just add another $order_statuses[‘another-status’] array to the same function ๐Ÿ™‚

  9. Hi!

    Great guide and contribution!

    How can i add so that it only changes to this order-status for product with a specific custom field?

    For example:
    Custom field name is “Paymentdetails” and value is “teacher”

    Best regards

    1. Hey Adam, thanks for your comment! I suggest you take a look at “conditional logic”: https://businessbloomer.com/conditional-logic-woocommerce-tutorial/ and https://businessbloomer.com/woocommerce-conditional-logic-ultimate-php-guide/. Let me know ๐Ÿ™‚

  10. Hi Rodolfo

    cam across your excellent mod here this morning. Have but one question.

    is it possible to add another custom status with no mail sending?

    Reason for asking, we’ll use woocommerce primarily for quotes, with the quote plugin. Thus it would be practical to have two custom statuses, one for quote in progress, and another for quote completed.


    1. Hey Knut, thanks for your comment! Yes, of course, you can ๐Ÿ™‚

  11. The code removes “Processing” and “Complete” from the quick-view when clicking the “eye”. Any fix for that?

    1. Hey Bjornen, thanks for your comment. Screenshot please?

  12. Hi,
    Can we have more than one custom status from same function ? pl advice.


    1. Hey Kumar – yes you can ๐Ÿ™‚ But I can’t share this here – thanks for the understanding.

  13. This article was super helpful! We use woocommerce for our sales and checkouts for out website. With so many backend details it’s hard to know what changes what, unless your an expert!

    1. Cool ๐Ÿ™‚

  14. It worked on single order page drop down. Thanks.

    Is there is way it also can work on order page (dropdown Bulk Actions)

    1. Hey Mark – thanks so much for your comment! Part #2 does that already ๐Ÿ™‚

    2. Hi ,
      It’s visible only inside single order page. It doesn’t display (drop down) on order page .
      Pl check and advice.

    3. Fixed ๐Ÿ™‚

  15. It Worked . But all new orders are getting custom status . How do we keep it on manual basis? I want to keep as processing Status for all new orders.

    Also – Moment I removed Snippet from function file . All orders with custom status disappeared from order management page .
    Pl check

    1. Hey Kumar ๐Ÿ™‚

      1) Just delete snippet part #3
      2) Reactivate the snippet – change the order status to e.g. Processing – disable the snippet

      Hope this helps ๐Ÿ™‚

  16. Was Waiting for This .. Can i change keyword from custom to SHIPPED ?
    Pl advice. Thanks.

    1. Of course Kumar! Just change all “custom status” occurrences to “shipped” ๐Ÿ™‚

Questions? Feedback? Support? Leave your Comment Now!

If you are writing code, please wrap it between: [php]code_here[/php]. Failure to complying with this (as well as going off topic) will result in comment deletion. You should expect a reply in about a week - this is a popular blog but I need to get paid work done first. Please consider joining #BloomerArmada to ask me 1-to-1 WooCommerce questions. Thank you :)

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.