Using Custom Bulk Actions

Sorry it’s been such a long time since my last blog!

I’m happy to tell you that in WordPress 4.7, developers can register their own bulk actions on list table screens.


Let’s walk through the steps required to add one.

An option in the dropdown

To add an option in the Bulk Actions dropdown HTML element, register a callback on the bulk_actions-{screen_id} filter that adds the new option onto the array. Replace {screen_id} with the ID of the admin screen to offer the bulk action on.

To add a bulk action “Email to Eric,” we could use the following code:

add_filter( 'bulk_actions-edit-post', 'register_my_bulk_actions' );

function register_my_bulk_actions($bulk_actions) {
  $bulk_actions['email_to_eric'] = __( 'Email to Eric', 'email_to_eric');
  return $bulk_actions;

Handling the form submission

To handle a bulk action form submission, register a callback on the handle_bulk_actions-{screen_id} filter for the corresponding screen. The filter expects the redirect URL to be modified, so be sure to modify the passed $redirect_url. This allows us to carry success or failure state into the next request to display a notice to the user. The other callback arguments will differ depending on the screen here to include contextually relevant data.

To add a bulk action handler for emailing the selected posts, we could use the following code:

add_filter( 'handle_bulk_actions-edit-post', 'my_bulk_action_handler', 10, 3 );

function my_bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
  if ( $doaction !== 'email_to_eric' ) {
    return $redirect_to;
  foreach ( $post_ids as $post_id ) {
    // Perform action for each post.
  $redirect_to = add_query_arg( 'bulk_emailed_posts', count( $post_ids ), $redirect_to );
  return $redirect_to;

Showing notices

We could use the existing notice hooks to let the user know what happened, depending on the state we set in the URL:

add_action( 'admin_notices', 'my_bulk_action_admin_notice' );

function my_bulk_action_admin_notice() {
  if ( ! empty( $_REQUEST['bulk_emailed_posts'] ) ) {
    $emailed_count = intval( $_REQUEST['bulk_emailed_posts'] );
    printf( '<div id="message" class="updated fade">' .
      _n( 'Emailed %s post to Eric.',
        'Emailed %s posts to Eric.',
      ) . '</div>', $emailed_count );

For the curious, see the related changeset and Trac ticket.