Custom Bulk Actions
Adding your own bulk action to dropdown list is much more easier than creating custom quick edit or bulk edit fields, so, actually this tutorial is for beginners.
This is how it looks:
I decided to add two custom bulk actions:
- the first one will operate with post statuses,
- the second one – with custom fields.
// if you want to add bulk actions to pages, use bulk_actions-edit-page
// for custom post types bulk_actions-edit-{CPT NAME}
// for custom taxonomies bulk_actions-edit-{TAXONOMY NAME}
// for Comments bulk_actions-edit-comments
// for Plugins bulk_actions-plugins
// for Users bulk_actions-users
// for Media bulk_actions-upload
add_filter( 'bulk_actions-edit-post', 'misha_my_bulk_actions' );
function misha_my_bulk_actions( $bulk_array ) {
$bulk_array['misha_make_draft'] = 'Make draft';
$bulk_array['misha_set_price_1000'] = 'Set price to $1000';
return $bulk_array;
}
Once you’ve added the code above to your theme functions.php
file or to your custom plugin, you should got the result below:
You do not have to create a callback for each bulk action, you can do it in a single handle_bulk_actions-{screen id}
hook. Just do not forget to replace {screen id}
below if you want to add bulk actions not for posts.
add_filter( 'handle_bulk_actions-edit-post', 'misha_bulk_action_handler', 10, 3 );
function misha_bulk_action_handler( $redirect, $doaction, $object_ids ) {
// let's remove query args first
$redirect = remove_query_arg( array( 'misha_make_draft_done', 'misha_bulk_price_changed' ), $redirect );
// do something for "Make Draft" bulk action
if ( $doaction == 'misha_make_draft' ) {
foreach ( $object_ids as $post_id ) {
wp_update_post( array(
'ID' => $post_id,
'post_status' => 'draft' // set status
) );
}
// do not forget to add query args to URL because we will show notices later
$redirect = add_query_arg(
'misha_make_draft_done', // just a parameter for URL (we will use $_GET['misha_make_draft_done'] )
count( $object_ids ), // parameter value - how much posts have been affected
$redirect );
}
// do something for "Set price to $1000" bulk action
if ( $doaction == 'misha_set_price_1000' ) {
foreach ( $object_ids as $post_id ) {
update_post_meta( $post_id, 'product_price', 1000 );
}
$redirect = add_query_arg( 'misha_bulk_price_changed', count( $object_ids ), $redirect );
}
return $redirect;
}
The last step – custom notices. You can use something like “The posts updated” or create a more detailed message with the help of _n
(for plural forms) and printf
functions.
No matter if you create a bulk action for comments or posts, the below code doesn’t require any specific replacements.
add_action( 'admin_notices', 'misha_bulk_action_notices' );
function misha_bulk_action_notices() {
// first of all we have to make a message,
// of course it could be just "Posts updated." like this:
if ( ! empty( $_REQUEST['misha_make_draft_done'] ) ) {
echo '<div id="message" class="updated notice is-dismissible">
<p>Posts updated.</p>
</div>';
}
// but you can create an awesome message
if( ! empty( $_REQUEST['misha_bulk_price_changed'] ) ) {
// depending on ho much posts were changed, make the message different
printf( '<div id="message" class="updated notice is-dismissible"><p>' .
_n( 'Price of %s product has been changed.',
'Price of %s products has been changed.',
intval( $_REQUEST['misha_bulk_price_changed'] )
) . '</p></div>', intval( $_REQUEST['misha_bulk_price_changed'] ) );
}
}
That’s how it looks:
Thanks for reading 🙏 If you have any questions, I will try to help you in comments.

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
wow. another impressive sharing ! thanks
Always welcome 🙂 thank you for your feedback!
Misha, I love your tutorials! Thanks a lot! I’d like to know if us use any online tool to create your animated gifs. I saw one with only 200kb. The gifs I try online all save above 1MB. :(
Hi Elisandro,
I use Photoshop 🙃
Cool. Thanks for the reply! :)
Perfect! Thanks Misha
Thank you so much for your code!
I’ve used it to bulk edit the “status” of a custom post type “Message”; messages are being generated with a front end form (powered by the Plugin “Advanced Custom Fields”) and the “status” (a custom field) helps us keep track of whether we already replied or not.
The code dynamically reads out all the available options for a message and creates a bulk edit option for each. I also added yet another request value so we can display the new status for our messages after bulk editing them. :-)
Hope this can help somebody else just like Misha’s code made my life much easier.
https://gist.github.com/d2fe594b8d392a262a3bb76088ac568b
Thank you! :)
Hi Misha,
Great tutorial. Thanks!
Do you know how to pass an POST ID variable to each item in a custom $bulk_array?
I’d like to link posts from a custom post type (which acts like categories in my system) to the posts to $bulk_array (easy with get_posts or WP_Query). Then in the do_action, I’d like to set update_post_meta( $post_id, ‘product_category’, POST_ID );
Using your example, I’d like to somehow add the variable POST_ID to $bulk_array[‘misha_set_category_to_tshirt’] = ‘Set category to tshirt’;
And then update_post_meta( $post_id, ‘product_category’, POST_ID );
Maybe a way is to make $bulk_array multidimensional?
$bulk_array[‘misha_set_category_to_tshirt’][POST_ID] = ‘Set category to tshirt’;
FYI: $bulk_array[‘set_category_test’] = array(‘Set category’, 233); didn’t work
:-)