Bulk Change Custom Order Statuses

Bulk set your custom order status Awaiting Shipment to orders.

You can find the tutorials, where new options for this dropdown select are added via jQuery – these tuts are outdated because since WordPress 3.5.0 you can do it using the hook bulk_actions-{screen_id}.

 * Add your custom bulk action in dropdown
 * @since 3.5.0
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_shipment'] = 'Mark awaiting shipment'; // <option value="mark_awaiting_shipment">Mark awaiting shipment</option>
	return $bulk_actions;


 * Bulk action handler
 * Make sure that "action name" in the hook is the same like the option value from the above function
add_action( 'admin_action_mark_awaiting_shipment', 'misha_bulk_process_custom_status' ); // admin_action_{action name}

function misha_bulk_process_custom_status() {

	// if an array with order IDs is not presented, exit the function
	if( !isset( $_REQUEST['post'] ) && !is_array( $_REQUEST['post'] ) )
	foreach( $_REQUEST['post'] as $order_id ) {
		$order = new WC_Order( $order_id );
		$order_note = 'That\'s what happened by bulk edit:';
		$order->update_status( 'misha-shipment', $order_note, true ); // "misha-shipment" is the order status name (do not use wc-misha-shipment)
	// of course using add_query_arg() is not required, you can build your URL inline
	$location = add_query_arg( array(
    		'post_type' => 'shop_order',
		'marked_awaiting_shipment' => 1, // markED_awaiting_shipment=1 is just the $_GET variable for notices
		'changed' => count( $_REQUEST['post'] ), // number of changed orders
		'ids' => join( $_REQUEST['post'], ',' ),
		'post_status' => 'all'
	), 'edit.php' );

	wp_redirect( admin_url( $location ) );


 * Notices
add_action('admin_notices', 'misha_custom_order_status_notices');

function misha_custom_order_status_notices() {
	global $pagenow, $typenow;
	if( $typenow == 'shop_order' 
	 && $pagenow == 'edit.php'
	 && isset( $_REQUEST['marked_awaiting_shipment'] )
	 && $_REQUEST['marked_awaiting_shipment'] == 1
	 && isset( $_REQUEST['changed'] ) ) {
		$message = sprintf( _n( 'Order status changed.', '%s order statuses changed.', $_REQUEST['changed'] ), number_format_i18n( $_REQUEST['changed'] ) );
		echo "<div class=\"updated\"><p>{$message}</p></div>";

Actually the replacements that must be made are on lines: 10 (bulk action label and value), 19 (action name in the hook) and 31 (your custom order status slug). Other changes are optional.

The code can be used in the functions.php or in your plugin files.

Order note from line 30 (you can find it on the edit order page):

Note that order status changed by bulk actions.

The notice after the bulk order status change has been processed:

The notice that appears when you change order statuses by bulk edit.

If you have any question – leave it in comments below, I will be glad to help you.

Misha Rudrastyh

Misha Rudrastyh

I develop websites since 2008, so it is total of 14 years of experience, oh my gosh. Most of all I love love love to create websites with WordPress and Gutenberg, some ideas and thoughts I share throughout my blog.

Need some developer help? Contact me

Follow me on Twitter