Bulk Actions

Bulk actions – is a part of WordPress admin interface, that allows you to select multiple elements like posts, terms, users and perform any action to all of them.

It is very handy because for example it allows you to remove let’s say hundreds of posts in just three clicks and saves you tons of time. Check the screenshot below to see how it works.

WordPress Bulk Actions

In this tutorial I am going to talk about how to remove default bulk actions and how to create a custom one. But first of all we will take a look at the hooks.

Maybe it is also worth noticing that bulk actions API is available for us since WordPress 4.7 version.

Bulk Action Hooks

The whole bulk action coding thing comes down to 2 action hooks:

  • bulk_actions-{screen id} – allows to remove default bulk action options and to add a custom one into the dropdown.
  • handle_bulk_actions-{screen id} – when creating a custom bulk action, you have to process elements somehow. And you can do it inside this hook.

As you can see, both hooks have a screen ID as a part of it. You can find out it on every WordPress admin page by yourself using get_current_screen() function but you can also take a look at the table below.

HooksAdmin pages
Media (List view)
bulk_actions-edit-{CPT name}
handle_bulk_actions-edit-{CPT name}
Custom post types
bulk_actions-edit-{Taxonomy name}
handle_bulk_actions-edit-{Taxonomy name}
Custom taxonomies

Remove Default Bulk Actions

Before creating our custom bulk actions let’s try to remove some of the default ones. You can do it with the help of the first one in the pair of hooks I mentioned before – bulk_actions-{screen id}, inside the hook we are going to operate with an array of bulk actions. In order to remove a bulk action we just have to remove it from the array.

 * Remove a Default Bulk Action
 * @author Misha Rudrastyh
 * @link https://rudrastyh.com/wordpress/custom-bulk-actions.html#remove-bulk-actions
add_action( 'bulk_actions-edit-post', 'rudr_remove_default_bulk_actions' );

function rudr_remove_default_bulk_actions( $bulk_array ) {
	unset( $bulk_array[ 'edit' ] );
	return $bulk_array;

A couple of moments:

  • If you don’t know where to insert the code from this tutorial, you can paste it into your current theme functions.php file. But in case you theme receive updates, consider a Child theme’s functions.php or a custom plugin.
  • You might ask where did I get $bulk_array[ 'edit' ] in the code above? You can find it out by inspecting the bulk actions dropdown in your browser or just use print_r() function to inspect $bulk_array array.

There we go:

remove default bulk actions in WordPress
So, we removed “Edit” default bulk action for Posts here.

Create Custom Bulk Actions

Good news for you guys, I decided to add two custom bulk actions:

  • the first one will operate with post statuses,
  • the second one – with custom fields.
 * Create Custom Bulk Actions for WordPress Posts
 * @author Misha Rudrastyh
 * @link https://rudrastyh.com/wordpress/custom-bulk-actions.html
// add to dropdown
add_filter( 'bulk_actions-edit-post', 'rudr_my_bulk_actions' );
function rudr_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;


// process the action
add_filter( 'handle_bulk_actions-edit-post', 'rudr_bulk_action_handler', 10, 3 );
function rudr_bulk_action_handler( $redirect, $doaction, $object_ids ) {

	// let's remove query args first
	$redirect = remove_query_arg(
		array( 'bulk_make_draft', 'bulk_price_changed' ),

	// do something for "Make Draft" bulk action
	if ( 'misha_make_draft' === $doaction ) {

		foreach ( $object_ids as $post_id ) {
					'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(
			'bulk_make_draft', // just a parameter for URL
			count( $object_ids ), // how many posts have been selected


	// do something for "Set price to $1000" bulk action
	if ( 'misha_set_price_1000' === $doaction ) {
		foreach ( $object_ids as $post_id ) {
			update_post_meta( $post_id, 'product_price', 1000 );
		$redirect = add_query_arg(
			count( $object_ids ),

	return $redirect;


// display messages
add_action( 'admin_notices', 'rudr_bulk_action_notices' );
function rudr_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[ 'bulk_make_draft' ] ) ) {
			<div class="updated notice is-dismissible">
				<p>Posts updated.</p>

	// but you can create an awesome message
	if( ! empty( $_REQUEST[ 'bulk_price_changed' ] ) ) {

		$count = (int) $_REQUEST[ 'bulk_price_changed' ];
		// depending on ho much posts were changed, make the message different
		$message = sprintf(
				'Price of %d product has been changed.',
				'Price of %d products has been changed.',

		echo "<div class=\"updated notice is-dismissible\"><p>{$message}</p></div>";



Some notes:

  • 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.
  • When creating admin notices, you can use something like “The posts updated” or create a more detailed message with the help of _n() (for plural forms) and sprintf() functions.

That’s how it looks:

custom bulk actions in WordPress
We created two custom bulk actions here.
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