2026年9月19日
2026年9月19日
WordPressの一括操作(bulk_actions)にカスタムアクションを追加する方法
WordPressの投稿一覧などにある「一括操作」のメニューには、bulk_actions-{画面ID} フィルターで独自の項目を追加し、handle_bulk_actions-{画面ID} フィルターでその処理を書くことができます。この記事では、投稿一覧に「おすすめに設定」という一括操作を追加する例を使って、項目の追加・処理・完了メッセージの表示までを、権限チェックやつまずきやすい点と合わせて説明します。
コードは子テーマの functions.php、または mu-plugin(wp-content/mu-plugins/ に置くPHPファイル)に書きます。本番に入れる前に、ステージング環境で動作を確認し、データを書き換える処理を試す前にはバックアップを取ってください。
仕組み:2つのフィルターと画面ID
一括操作の追加には、次の2つのフィルターを使います。どちらもWordPress 4.7で追加されたもので、現在も同じ名前で使えます(2026年10月現在)。
bulk_actions-{画面ID}:一括操作のドロップダウンに表示する項目の配列を受け取り、項目を追加・削除して返すhandle_bulk_actions-{画面ID}:選んだ操作が実行されたとき、リダイレクト先URL・操作名・選択された項目のID配列を受け取り、処理後のリダイレクト先URLを返す
{画面ID} は管理画面の種類ごとに決まっています。
- 投稿一覧:
edit-post - 固定ページ一覧:
edit-page - カスタム投稿タイプ(例:
book)の一覧:edit-book - ユーザー一覧:
users - メディアライブラリ(リスト表示):
upload
画面IDを間違えると、何も起きずエラーも出ないため、最初につまずきやすい点です。分からないときは、対象の画面で get_current_screen()->id を確認します。
手順1:一括操作の項目を追加する
投稿一覧のドロップダウンに「おすすめに設定」を追加します。配列のキーが操作名(プログラム側で使う識別子)、値が画面に表示される名前です。
add_filter( 'bulk_actions-edit-post', function ( $actions ) {
$actions['my_mark_featured'] = __( 'おすすめに設定', 'my-site' );
return $actions;
} );
操作名には、他のプラグインやWordPress本体と重ならないよう接頭辞(ここでは my_)を付けます。本体の操作名である trash や edit と同じ名前にすると、本体の処理が先に動いてしまいます。
手順2:選択された項目を処理する
次に、操作が実行されたときの処理を書きます。ここでは、選択された投稿にカスタムフィールド _my_featured を設定します。
add_filter( 'handle_bulk_actions-edit-post', function ( $redirect_url, $action, $post_ids ) {
if ( 'my_mark_featured' !== $action ) {
return $redirect_url;
}
$done = 0;
foreach ( $post_ids as $post_id ) {
$post_id = (int) $post_id;
// 投稿ごとに編集権限を確認する
if ( ! current_user_can( 'edit_post', $post_id ) ) {
continue;
}
update_post_meta( $post_id, '_my_featured', 1 );
$done++;
}
$redirect_url = remove_query_arg( 'my_featured_done', $redirect_url );
return add_query_arg( 'my_featured_done', $done, $redirect_url );
}, 10, 3 );
ポイントは3つあります。
1つ目は、自分の操作名以外のときは受け取ったURLをそのまま返すことです。このフィルターには他のプラグインの一括操作も流れてくるため、条件分岐を忘れると他の機能を壊します。
2つ目は、権限の確認です。投稿一覧などの標準の画面では、WordPress本体が一括操作用の nonce を検証してからこのフィルターを呼び出します。一方、「その投稿を編集してよいか」は投稿ごとに異なるため、current_user_can( 'edit_post', $post_id ) で1件ずつ確認します。他人の投稿を編集できない「投稿者」権限のユーザーでも一括操作のメニュー自体は見えるので、この確認を省くと権限を越えた書き換えが起きます。
3つ目は、戻り値です。このフィルターはリダイレクト先のURLを返す必要があり、処理件数などの結果はURLのクエリ引数に載せて次の画面に渡します。何も返さないと一覧画面に正しく戻れません。
手順3:完了メッセージを表示する
リダイレクト後の画面で、クエリ引数を読み取ってメッセージを表示します。
add_action( 'admin_notices', function () {
if ( ! isset( $_GET['my_featured_done'] ) ) {
return;
}
$screen = get_current_screen();
if ( ! $screen || 'edit-post' !== $screen->id ) {
return;
}
$count = absint( $_GET['my_featured_done'] );
printf(
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
esc_html( sprintf( '%d件の投稿をおすすめに設定しました。', $count ) )
);
} );
// メッセージ表示後、URLからクエリ引数を取り除く
add_filter( 'removable_query_args', function ( $args ) {
$args[] = 'my_featured_done';
return $args;
} );
URLの値は利用者が書き換えられるため、absint() で整数にし、出力時は esc_html() でエスケープします。removable_query_args フィルターに登録しておくと、表示後にブラウザのアドレス欄から引数が消え、再読み込みでメッセージが繰り返し出ることを防げます。
手順4:カスタム投稿タイプやユーザー一覧に広げる
複数の投稿タイプに同じ操作を追加したい場合は、画面IDを変えて同じ関数を登録します。
foreach ( array( 'post', 'page', 'book' ) as $post_type ) {
add_filter( "bulk_actions-edit-{$post_type}", 'my_add_featured_action' );
add_filter( "handle_bulk_actions-edit-{$post_type}", 'my_handle_featured_action', 10, 3 );
}
この場合は手順1・2の無名関数を my_add_featured_action などの名前付き関数に書き換え、完了メッセージの画面IDの判定も対象の画面に合わせて変更します。
ユーザー一覧(画面ID users)では、3つ目の引数がユーザーIDの配列になります。権限の確認は current_user_can( 'edit_user', $user_id ) を使います。メディアライブラリはリスト表示のときだけ一括操作のメニューが使え、グリッド表示では動作が異なる点に注意してください。
つまずきやすい点と確認方法
- 項目が出ない:画面IDの綴り(
edit-postのハイフン)と、フィルター名の綴りを確認する。コードが読み込まれているかは、子テーマが有効か、mu-plugin のファイルが直下に置かれているかで確認する - 処理が動かない:
handle_bulk_actions-の画面IDと操作名が手順1と一致しているか、add_filterの第4引数(受け取る引数の数)が3になっているかを確認する - 一部の投稿だけ処理されない:権限の確認で除外されている可能性がある。処理件数と除外件数を分けてメッセージに出すと原因を追いやすい
- 大量の投稿で止まる:一括操作の対象は、一覧に表示されている1ページ分だけです。表示件数を増やして数百件を一度に処理すると、時間切れになることがあります。重い処理や大量のデータには、WP-CLI のコマンドや、バックグラウンドで順に処理する仕組み(「Action Scheduler」など)を使う方が安全です
動作確認では、管理者だけでなく、編集者や投稿者など権限の異なるユーザーでもログインして試してください。
まとめ
- 項目の追加は
bulk_actions-{画面ID}、処理はhandle_bulk_actions-{画面ID}フィルターで行う - 処理側では自分の操作名だけを扱い、他の操作のときは受け取ったURLをそのまま返す
- nonce の検証は標準の一覧画面では本体が行うが、項目ごとの権限は
current_user_can()で自分で確認する - 結果はクエリ引数で渡し、
absint()とesc_html()を通して表示する。removable_query_argsで後始末をする - 大量処理は一括操作ではなく WP-CLI やバックグラウンド処理に任せる