Bulk Change Custom Order Status
A couple tutorials ago we created a custom order status. There were a lot of questions in comments section about adding it to bulk actions.
Let’s do it now.
To add anything into bulk actions dropdown we need to use bulk_action-{screen id}
. A little more details about it is in bulk actions tutorial. But now when we are going to use it for orders page, its screen id will be edit-shop_order
. So, the hook is going to be bulk_action-edit-shop_order
.
add_filter( 'bulk_actions-edit-shop_order', 'misha_register_bulk_action' ); // edit-shop_order is the screen ID of the orders page
function misha_register_bulk_action( $bulk_actions ) {
$bulk_actions[ 'mark_awaiting_shipping' ] = 'Change status to awaiting shipping'; // <option value="mark_awaiting_shipping">Change status to awaiting shipping</option>
return $bulk_actions;
}
Once you paste this code to your theme functions.php
file (I hope you know when to use or not use child themes), the option will appear in bulk dropdown.

But at this moment it is useless. I mean it does nothing when you select it from dropdown list and push the apply button.
In order to make it work we have to use another filter hook which is handle_bulk_actions-{screen id}
, so for WooCommerce orders we are using handle_bulk_actions-edit-shop_order
.
add_action( 'handle_bulk_actions-edit-shop_order', 'misha_bulk_process_custom_status', 20, 3 );
function misha_bulk_process_custom_status( $redirect, $doaction, $object_ids ) {
if( 'mark_awaiting_shipping' === $doaction ) {
// change status of every selected order
foreach ( $object_ids as $order_id ) {
$order = wc_get_order( $order_id );
$order->update_status( 'wc-misha-shipping' );
}
// do not forget to add query args to URL because we will show notices later
$redirect = add_query_arg(
array(
'bulk_action' => 'marked_awaiting_shipping',
'changed' => count( $object_ids ),
),
$redirect
);
}
return $redirect;
}
On line 10 above we are using a slug of a custom order status we created in this tutorial. It can be used with or without wc-
prefix by the way, $order->update_status( 'misha-shipping' )
is also ok.
The last thing – notices about changed orders.
add_action( 'admin_notices', 'misha_custom_order_status_notices' );
function misha_custom_order_status_notices() {
if(
isset( $_REQUEST[ 'bulk_action' ] )
&& 'marked_awaiting_shipping' == $_REQUEST[ 'bulk_action' ]
&& isset( $_REQUEST[ 'changed' ] )
&& $_REQUEST[ 'changed' ]
) {
// displaying the message
printf(
'<div id="message" class="updated notice is-dismissible"><p>' . _n( '%d order status changed.', '%d order statuses changed.', $_REQUEST[ 'changed' ] ) . '</p></div>',
$_REQUEST[ 'changed' ]
);
}
}
Works perfectly.


Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
This is awesome! I wish Woocommerce tutorials were even 1/4 as close to your detailed explanation! God bless you, Misha!
Please keep up the good work of helping people!
Thank you very much :)
Thanks! You are awesome!
Can this be used to add tracking numbers of multiple orders at once?
This tutorial should help you.
Thank you very much
I was wondering if this snippet would work for “Change status to cancelled”
Specifically, I was wondering about “action_name” in line 19.
Hi,
Yes, everything should be Ok.
Action name on line 19 is the array key from line 10.
Hi Misha,
Below attempt to use your code to “Bulk change Status to Cancelled” did not have any effect.
Comments?
Bart
Hi Bart,
Exactly what I mean, you use
$bulk_actions['mark_change_status_to_cancelled'] = ....
, so your action name must beadmin_action_mark_change_status_to_cancelled
Hey thanks a lot! This snippet is exactly what i need and it works awesome.
Hi Misha,
I have a custom action on a custom status change, but when I change to this status in a bulk, this action only exec in the first element that I selected, did you know why?
Hi Juan,
Didn’t you forget about foreach?
I, thanks for reply, the foreach is the same that you have in your code (“foreach( $_REQUEST[‘post’] as $order_id )”), and this take every post_id that I selected with checkboxes.
Hmmm… Strange. Please contact me by email and let’s figure it out.
Hi Misha,
Is it possible to change the order of the items in the bulk actions dropdown? I would like to move the custom status below wc-processing.
Thank you so much!
Hey Eve,
Yes, it is possible with
array_slice()
function. Example:Hi Misha,
Thanks for this awesome code! Is there a way to reorder all the statuses in the bulk change list?
Thanks again!
Hi Jeanie,
You can redefine the array inside the
bulk_actions-edit-shop_order
filter hook.To view it, you can
print_r( $bulk_actions )
, and then create a new one from it, like this:Hi Misha
Where abouts do I add this code snippets please?
Thanx
Hi Paul,
functions.php
of your theme will be ok. But if you theme receive updates, then better use child theme or a custom plugin.Thanks Misha
Hi Misha
I am trying to add a bulk action to Woocommerce subscriptions to update the subscription notes.
We offer a monthly subscription service and want to be able to add a note each month to say that the orders have been shipped (in our case we call it “printed”
I have adapted the code as follows but it causes the website to crash. Any help would be much appreciated.
Hi Paul,
I think it is a syntax error somewhere. Try to change in
wp-config.php
file this line todefine('WP_DEBUG', true);
Hello Misha,
First of all, great tutorial up there.
I do have a question though. If I want to have multiple custom order statuses, is there a way I can do that without having to
Thanks for sharing.
It was very helpful.
Great post!
Love from Brazil <3
Thanks <3