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.

add custom bulk action for shop orders

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.

WooCommerce bulk change custom order status
Misha Rudrastyh

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

Follow me on X