We’d previously written about how to create a custom WooCommerce order status, but this tutorial has become outdated with the WooCommerce 2.2 release. Since some of our readers asked for an update, we’ve re-written this tutorial to reflect how to add a custom order status, WooCommerce 2.2-style.

If you’re using WooCommerce 2.1.12 or earlier, you’ll want to check out our previous tutorial to do so. This tutorial will focus on creating WooCommerce 2.2-compatible custom order statuses.

WooCommerce Custom Order Status


While WooCommerce includes several different order statuses, these may not fit the flow for your shop. With WooCommerce core, you can mark orders with one of the following statuses:

  • Completed
  • Processing
  • Pending payment
  • On hold

  • Refunded
  • Cancelled
  • Failed

However, some shops need more order statuses, such as “Awaiting shipment”, “Building”, or others to fit their fulfillment needs. You can easily add these yourself with a tiny bit of custom code.

Let’s go over how to both add a WooCommerce custom order status and to remove an order status.

Adding a WooCommerce Custom Order Status

In WooCommerce 2.1 or earlier, order statuses were stored as a taxonomy for the “Order” post type. WordPress taxonomies are categorizations, such as post categories and tags. However, WooCommerce 2.2 required a change to the order structure to support partial and automatic refunds from the WooCommerce admin. Order statuses are now saved as a custom post status, just like draft, scheduled, or published for posts.

Adding a custom post status necessitates a bit more code now than it did for WooCommerce 2.1, but this is actually a bit more straight-forward from a development perspective (you don’t have to run the code once then delete it). Be sure to properly add this code to your site – I’d recommend creating a plugin or using the Code Snippets plugin. I wrote tutorials on how to add custom code to your site in this post and in this one.

Let’s start with the full snippet for you impatient folks πŸ™‚ . This will add an “Awaiting shipment” order status to your shop. I’ll then break it down to explain what each part of this snippet does.

Explanation: what does this code do?

Let’s start with the first function in this code:

// Register new status
function register_awaiting_shipment_order_status() {
    register_post_status( 'wc-awaiting-shipment', array(
        'label'                     => 'Awaiting shipment',
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop( 'Awaiting shipment <span class="count">(%s)</span>', 'Awaiting shipment <span class="count">(%s)</span>' )
    ) );
}
add_action( 'init', 'register_awaiting_shipment_order_status' );

This function is registering our custom status as a post status in WordPress. You can rename the function to suit your needs, but we’re going to build an “Awaiting shipment” order status, so we’ve called it register_awaiting_shipment_order_status() to reflect this.

We then build the post status using the WordPress register_post_status() function. Notice that the first thing in this function is the slug for our order status, prefixed by “wc-” for “WooCommerce”. If you want a different name for your order status, you’ll want to change this to a hyphenated, all lower-cased slug, such as wc-building or wc-packing-order.

Your custom status slug can only be a maximum of 20 characters, including dashes (as per the codex on register_post_status), so you need to be aware of this when creating your own slug.

We then create an array, which is a set of data that defines our custom post status. The label is what will be displayed, so you can change that to the exact name of your order status. You’ll then also want to insert this in the label_count instead of “Awaiting shipment”, but leave the rest of this array unchanged.

Finally, the action at the end runs this function and adds this order status to WordPress as our custom post status.

Now let’s talk about the second part:

// Add to list of WC Order statuses
function add_awaiting_shipment_to_order_statuses( $order_statuses ) {
 
    $new_order_statuses = array();
 
    // add new order status after processing
    foreach ( $order_statuses as $key => $status ) {
 
        $new_order_statuses[ $key ] = $status;
 
        if ( 'wc-processing' === $key ) {
            $new_order_statuses['wc-awaiting-shipment'] = 'Awaiting shipment';
        }
    }
 
    return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_awaiting_shipment_to_order_statuses' );

The add_awaiting_shipment_to_order_statuses() function is going to add this new custom post status into the list of available order statuses within the WooCommerce “Orders” and “Edit Orders” pages so that we can actually use it. We want to pass in the current order statuses so that we can go through them and insert our order status into the list where we’d like it.

We create an array for our new order statuses first, which will be our final product. We’ll then go through all order statuses and insert our own, so that by the time we spit out the new order statuses into the list, our new one is included.

The foreach loop here goes through the list of current order statuses until we find the one we want. In this case, I’m going to insert “Awaiting shipment” after the “Processing” order status. That’s what the if() part is doing here – we say, “If the order status is ‘processing’, add in ‘Awaiting shipment’ here, then continue going through order statuses.”

Notice that I use the slug and label I created in the first function to add this order status. I’ll now have “Awaiting shipment” displayed after “Processing” for my orders:

WooCommerce Custom Order Status

You can insert your new status after any of the existing statuses – you can find a list of them here. For example, I could have looked for wc-pending instead and added my status after that.

That’s it! You can now add your own status and insert it anywhere into the order status list.

Removing a WooCommerce Order Status

If you’d like to remove your custom order status, you only have to remove this code from your site. If you’re using the Code Snippets plugin, you can simply deactivate the snippet. If you do so, your order statuses will default to “Pending payment”.

However, orders using your new status may not appear in your orders list when the code is removed since they’re using an unrecognized post status. I’d recommend changing the order statuses to a core status before deactivating or removing this snippet. The orders will still exist regardless, and you could navigate to them directly using the post id, but they won’t be recognized in the Orders list without this code unless they use a core order status.

I’m not going to go over how to remove any of the core order statuses, because this is a very bad idea. Even if you think you may not use any of them, most plugins (especially payment gateways or other plugins that tie to orders), expect them to be there.

For example, you may not think you’ll need the “Pending payment” status, but this is actually used by most gateways as the default order status until a valid payment is confirmed. For example, PayPal or other gateways that use IPNs to notify your site that a payment has been completed use “Pending payment”, then the status is updated to processing once the payment is received. For many extensions to work correctly, these core statuses must all be available – even if you don’t actively use them in your fulfillment cycle.

Read More


That’s all there is to adding a WooCommerce custom order status! Credit goes to Max Rice for most of the code, and to me for explaining it πŸ™‚ . If you want to see a slightly simpler approach, here’s another snippet that will help you achieve this from one of the WooCommerce lead developers, Claudio Sanches.

Articles you may also like:

Posted by Beka Rice

Beka Rice manages the direction of Sell with WP content and writes or edits most of our articles to share her interests in eCommerce. Or she just writes as an excuse to spend more time jamming out to anything from The Clash to Lady Gaga. Who knows.

58 Comments

  1. Thanks for this update! However, I’ve run into some serious issues implementing it.

    I made two new order statuses. They show up in my list, but I’m having trouble saving the orders with them. It’s somehow overloading the memory (the error is different everytime – the wp-includes/plugin.php got blamed once and then wp-includes/cache.php got blamed another time) and then when I try to go back, the order has disappeared entirely! It’s happening on my local setup as well as (unfortunately) my client’s page. I know the orders have not disappeared from the database, but for some reason WooCommerce isn’t registering them as orders anymore.

    I can’t make new orders with those order statuses either.

    I thought it might be my caching plugin, and I deactivated that, but no dice so far. Any help would be appreciated!

    1. Actually I figured it out – I had to deactivate all of my plugins first, then reactivate them to load the custom order statuses correctly. Weird!

      I also had to find my lost orders in the wp_posts table in the database via phpMyAdmin, then change them manually to a default order status to get them to show up again. I was then able to save them with my custom status. What a pain, haha.

      1. I’m currently experiencing this same issue. Thanks for telling how you fixed it, I would have searched around for hours!

        1. Nope, tried deactivating and reactivating all of my plugins but it’s not working. The order no longer shows up in the list and if I refresh the View Order page, it shows the slug, not the label, as the order status.

          Any ideas?

    2. Hey Anita, sounds like you may be experiencing something related to this potential bug. Sounds like it will be patched soon, but I’d keep an eye on that issue πŸ™‚ .

      1. SOLVED – – – – – – – – – – –

        So evidently, as someone mentioned below, the post type cannot exceed a certain number of characters (mine was cutting off at 17). I had to change “wc-awaiting-shipment” to “wc-shipped” and I also shortened the function names. I did also have to go into PHP MyAdmin to find the orders that got labeled wrong from the first time and change their statuses manually.

        In any case, there’s no icon (will look at this other post for that), but it’s working.

        I have one more question though:
        Is there a way to add a button to the Actions column of the main orders list? It would be nice not to have to actually go into each order just to mark them as “Shipped.”

        Thanks, hope this helps anyone else with this trouble.

  2. Any chance you can show us how to add multiple custom statuses? Not sure which parts I should duplicate.

    1. Hey Indira, you can duplicate the parts within each function – it would look something like this: https://gist.github.com/bekarice/a8954958eb9b6af52713

  3. Thanks for posting this. The timing was perfect as I am just getting ready to deal with this on a site.

    Any thoughts as to the best strategy for upgrading a site to WC 2.2 that has existing custom order statuses?

    1. Hey Doug, the best way to do it would probably be to do an upgrade routine to convert old taxonomies to new post statuses. I updated custom orders in my test site before doing this to see if they’d blow up, and thankfully they didn’t πŸ™‚ . The post status is listed as “publish” rather than as an order status, so you can still access orders and change to a core status, but I think an upgrade routine instead would work well here. I plan on messing around and writing one if I find some free time this week – I’ll add a link if I do.

  4. Hi,
    Thanks for your post. I want that if I change the order status to “Awaiting Shipment”, an email should be sent to the customer as an email sent when we change the order status to “Completed”. I mean to say that it should be custom order status with email notification to customer.

    Please solve the issue asap.
    Thanks again

  5. Hi Beka,

    I was wondering if you have any ideas on how to add custom statuses to the “mark as” action drop down. All orders are now marked as “Published”, but I want to mark as my custom statuses.

    1. Hey Indira, bulk actions are far more complicated to add. This tutorial on adding bulk actions is probably a good place to start, though you’ll have to use the shop order post type instead.

  6. I’m getting a 500 Internal Server Error when I try to save an order status in admin with the custom order status. It makes the server unresponsive for about 30 seconds then gives the error.

    Also, how would I send an email, similar to the shipping email? This is for a Partially Shipped status.

    1. Hey David, this sounds like there’s a plugin/server conflict somewhere, as I’ve not seen this on any test / live site. I’d recommend deactivating plugins then activating one-by-one to see where the conflict comes from.

      As for emails, that becomes more complicated. We’ve just begun building a plugin to add statuses + linked emails for a status to do this since you’re not the first person to have that question πŸ™‚ .

  7. Hi,

    Is it possible to hook up a custom status to send an email to the customer?

    1. Possible, not something easy to cover in a tutorial. See this comment πŸ™‚ .

    2. Hey Michael, in case you’re still looking for this see my comment below — there’s now a plugin that will do this for you.

  8. Hi Beka!
    I placed an order manually.
    Total is equal to zero €.
    This happened because I set it as “Awaiting payment”, but after a few hours woocommerce set it as “expired”.
    Useless to say that I hate this thing…
    Is there a way to change order totals?
    I hope so… πŸ™‚

    1. My guess would be that it’s because your inventory is set to expire and thus cancel the order – trying changing it under your inventory settings to leave it blank: https://cldup.com/-uzeKC1Yok.png

  9. Very well written. Thank you.

  10. […] So, that’s pretty cool. You could even just change the completed part to be another order status, like ‘processing’ or even a custom one. […]

  11. Thanks for the post, This saved a lot time.

    I have one question, how can we put action on order status change to this new custom status?

    I am currently catching all order status change action like below.
    add_action( ‘woocommerce_order_status_completed’, ‘mysite_woocommerce_order_status_completed’ );

    I am not sure if I can add action for this status like below.
    add_action( ‘woocommerce_order_status_awaiting_shipment’, ‘mysite_woocommerce_order_status_awaiting_shipment’ );

    Will this work when any order is changed to ‘Awaiting Shipment’?

  12. Thanks for this tutorial. Works perfectly!

    I’m wondering is there an easy way to add a custom icon to the admin columns thru css, like the other order statuses have (blue tick etc). There is a unique class in the tr for the new status I have created but is there an easy way to load in some custom css to style it?

    Thanks

      1. Thank you (twice) πŸ™‚ …

        1. No problem! Glad it helped πŸ™‚

  13. Thank you.

    I’ve used this as well as the pretty icon tutorial in conjunction with your code-snippets plugin.

    I’d been using an “On-hold” status for a yarn club that runs quarterly, so the orders aren’t “on hold”, just not dyed and shipped yet! πŸ™‚

    Job jobbed. πŸ™‚

    1. woohoo! Glad to hear it’s worked out πŸ™‚ . The company I work for has also just released a plugin that will do this (add statuses, icons, and order status actions) as well for those of you that don’t want to add any code / want a more integrated order status workflow: WooCommerce Order Status Manager.

  14. Be careful with post type length
    It cannot exceed 20 characters

  15. This does not seem to work anymore.

    After adding above code, list is empty:

    https://www.dropbox.com/s/3cj0waio5kffg06/Screenshot%202015-02-12%2019.01.36.png?dl=0

    1. can’t see your screenshot, but this is definitely still working for me. I’d double check the second function in the snippet to make sure nothing was missed, as that’s where the status is inserted into the list (slug is right, no missing semicolons, etc).

  16. Hi Beka
    amazing

    it’s possible to make a custom “delivered” with same abilities as statut β€˜completed’ for review? in my website, only customer bought product can leave a review.
    in woocommerce the review is only avaible with the statut β€˜completed’ when you check “only customer can review”
    i want add a statut β€˜delivered’ and want this statut can be set to allow member to review product.

    1. Hi there, I’m afraid that this setting is hard coded to only processing and completed orders, so other statuses can’t be used aside from these two to allow only verified reviews.

  17. Hi Beka

    Thanks for tutorial. Works great. I used it to create a status after “completed” status. But now an amount od order does not count in reports. Do you have any advice?

    Martin

    1. Hey Martin, I’d recommend checking out this plugin, as the order statuses you add can be added to reports, have custom icons, be used in emails, etc., as the code to include them in reports is a bit more involved.

  18. Hi Beka

    Thanks for a wonderful code, it is wroking fine for single order status, I want to create atleast 10 custom order status, so i am thinking instead of writing it 10 times can we manage it in single function? so that we can create multiple order status.

    Thanks in advance.

  19. This function doesn’t seem to work with WC 2.3. The custom order statuses just don’t show up.

    Any ideas on how to get it working with 2.3? Or is there any one else that did get it working?

    1. works for me with 2.3, perhaps there’s a plugin / theme conflict?

  20. Thanks for such a great turorial! So with this new Woocommerce, when stock is managed the order status is cancelled if unpaid within a specific time.

    I created a ‘Deposit Paid’ order status and after a few hours it is overridden by cancelled – how do I overcome such without disabling the inventory management or hold stock.

  21. Great tutorial. Trying to get this working for the Latest version. Is there a plugin that does this automatically?

    Also I was wondering if its possible to add buttons instead of drop down menu’s for custom statuses. What would be the code for that?

    1. Hey Ali, there is a plugin that will do this for you: WooCommerce Order Status Manager.

      wondering if its possible to add buttons instead of drop down menus for custom statuses.

      The code for that is more complicated, but the plugin does this for you.

  22. Is it possible to add this custom status at “bulk action” drop down? I know this can be achieved by using Order Status Manager plugin, but it is not free, I hope to save money if possible.

  23. Hi!
    Is it possible for a store admin to receive email notification upon order delivered?

    Thanks in advance

  24. Great line of code, I have managed to add the custom status. How can I add the following functions to the status;

    reduce stock when status is set
    add status icon in admin list

  25. Hi Beka Rice,

    Is it possible to send custom status to send an email to the customer regarding that custom order status? i am read so many tutorial but i can’t find any solutions.

    I have also purchase “WooCommerce Order Status Change Notifier” plugin to send email notification with order status. But this plugin not send mail when i select your provide above code develop custom status.

    If you have any idea regarding my requirement then please replay me.

    Thanks,
    Ketan.

    1. I’d recommend the Order Status Manager plugin instead, as it’s designed to do just that (you can probably exchange the license)

  26. Hi, for non-ecommerce scenarios (manufacturing, digital printing house) would it be possible to implement:

    a) separate statuses for financial status (waiting for offer, waiting for invoice, invoiced etc), and production related statuses (ordered, under manufacturing, finished)

    b)work and calculate with dimensions (lenth x height = area etc)

    Thanks for any input, Zoltan

    1. a) This isn’t really possible at present, nor is it something that a plugin should change since it’s a massive departure from core behavior that would affect payment gateways, shipping, etc. We’ve suggested this set up in the past, and I’d recommend keeping an eye on this issue.
      b) Sure, this article will probably be helpful πŸ™‚

  27. It works. Sort of. How to set an icon for new order status? For hold there is – in circle, for completed there is check in circle. For new one there is nothing.
    What is more important – how to make custom email for this status because in WC options there is none after using this code.

    1. Hey Piotr, you’d need a lot more code around this to trigger emails and fully integrate custom statuses, not something I’m going to cover in tutorials. I’d recommend checking out the Order Status Manager plugin ($49), which does all of what you’re asking.

      1. Thanks for a reply.

        That’s what I thought. So I will try to change one of the unused statuses (and email templates) to fill my needs πŸ™‚

  28. I have made my custom order status thanks to your tutorial:D,
    but i need to have an automated email notification(actually the customer invoice email action) when the order changes to my_custom_order_status.
    I have found this snippet but it does not work.

    function sendinvoice($orderid)
    {
    $email = new WC_Email_Customer_Invoice();
    $email->trigger($orderid);
    }

    add_action(‘woocommerce_order_status_my_custom_order_status_notification’,’sendinvoice’);

    How can i resolve it and when i change to my custom status an automated invoice email will be fired up?

    Thanks in advance,
    czafir

  29. Hi I followed this tutorial to create awaiting shipment custom status and it worked perfectly. However, when I added another custom status (Partially Refunded), I can see it in the drop down menu on the order page, but if I try and save the order with this new status, the status goes back to Complete upon save… Any ideas or advise why this might be? Thanks

    1. Hey Juliette, I’d wager it’s your slug length. See this note from the article above and give that a check:

      Your custom status slug can only be a maximum of 20 characters, including dashes (as per the codex on register_post_status), so you need to be aware of this when creating your own slug.

      1. Hi Beka, You are right, I had 21 characters and miscounted! Works perfectly now, plus it gives us a chance to track partially refunded orders (we get them a lot)! Thanks again for a fast reply

  30. Is there a way to get this to the top of the list? I need it to be the default.

It's been over 2 years since this post was published, so comments have been closed. Thanks for reading!