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:

Bulk actions for WordPress posts.

I decided to add two custom bulk actions:

// 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:

We added two new custom bulk actions to the dropdown list.

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>

	// 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:

Custom notice after the bulk action is performed.

Thanks for reading 🙏 If you have any questions, I will try to help you in comments.

Misha Rudrastyh

Misha Rudrastyh

I develop websites since 2008, so it is total of 13 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