add_filter( 'bulk_actions-edit-shop_order', 'wdo_register_bulk_action' ); // edit-shop_order is the screen ID of the orders page function wdo_register_bulk_action( $bulk_actions ) { $bulk_actions['mark_cancel_order'] = 'Mark Order Cancel'; // return $bulk_actions; } add_action( 'admin_action_mark_cancel_order', 'wdo_bulk_process_custom_status' ); // admin_action_{action name} function wdo_bulk_process_custom_status() { // if an array with order IDs is not presented, exit the function if( !isset( $_REQUEST['post'] ) && !is_array( $_REQUEST['post'] ) ) return; foreach( $_REQUEST['post'] as $order_id ) { $order = new WC_Order( $order_id ); $order_note = 'That\'s what happened by bulk edit:'; $order->update_status( 'cancelled', $order_note, true ); // "cancelled" is the order status name (do not use wc-cancelled) } // of course using add_query_arg() is not required, you can build your URL inline $location = add_query_arg( array( 'post_type' => 'shop_order', 'cancelled_awaiting_shipment' => 1, // cancelled_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 ) ); exit; } add_action('admin_notices', 'wdo_custom_order_status_notices'); function wdo_custom_order_status_notices() { global $pagenow, $typenow; if( $typenow == 'shop_order' && $pagenow == 'edit.php' && isset( $_REQUEST['cancelled_awaiting_shipment'] ) && $_REQUEST['cancelled_awaiting_shipment'] == 1 && isset( $_REQUEST['changed'] ) ) { $message = sprintf( _n( 'Order status changed.', '%s order statuses changed.', $_REQUEST['changed'] ), number_format_i18n( $_REQUEST['changed'] ) ); echo ""; } }{$message}