remove_action が効かない原因と対処|優先度・タイミング・クラス

結論

remove_action() が効かないときの原因は、ほぼ次の4つに絞れます。

  1. 優先度が一致していない(追加側が 20 なのに、削除側は省略=10)
  2. 削除を書いた場所が早すぎる(追加される前に実行している)、または遅すぎる(フックがすでに実行された後)
  3. クラスメソッドを、インスタンスではなく文字列のクラス名で指定している
  4. クロージャ(無名関数)で追加されている

remove_action() は、外せなかったときに警告もエラーも出さず、戻り値 false を返すだけです。そのため、「書いたのに何も起きない」状態になりやすいのが特徴です。

原因・仕組み

remove_action() は remove_filter() の別名で、内部では「フック名・コールバック・優先度」の3つがすべて一致する登録を探して削除します(公式リファレンスにも、優先度は追加時と完全に一致させる旨の記載があります)。つまり「だいたい合っている」では外れません。

また、WordPress のフックは「登録された順に配列へ入れ、実行時にその配列を回す」仕組みです。登録されていないものは外せませんし、すでに実行済みのフックから外しても、その回の処理には間に合いません。

手順(サンプルコード)

1. 優先度を合わせる

function greet() { echo "hellon"; }
add_action( 'demo_hook', 'greet', 20 );

remove_action( 'demo_hook', 'greet' );      // 優先度10と解釈され、外れない(false)
remove_action( 'demo_hook', 'greet', 20 );  // 追加時と同じ20なので外れる(true)

相手のコードで優先度が分からないときは、has_action( 'demo_hook', 'greet' ) を使います。登録されていればその優先度の数値が、なければ false が返ります。

2. 登録の後・実行の前に外す

// 外したい側(テーマやプラグイン)
add_action( 'after_setup_theme', function () {
    remove_action( 'wp_head', 'wp_generator' ); // wp_head が実行される前に外す
} );

追加元が plugins_loaded や init で登録している場合は、それより後のフック(もしくは同じフックで大きい優先度)で外します。

add_action( 'init', function () {
    remove_action( 'template_redirect', 'plugin_redirect_func', 10 );
}, 99 );

3. クラスメソッドはインスタンスで指定する

class Plugin_X {
    public function __construct() { add_action( 'demo_hook2', array( $this, 'run' ) ); }
    public function run() { echo "runn"; }
}
$GLOBALS['plugin_x'] = new Plugin_X();

remove_action( 'demo_hook2', array( 'Plugin_X', 'run' ) );            // false:外れない
remove_action( 'demo_hook2', array( $GLOBALS['plugin_x'], 'run' ) );  // true:外れる

インスタンスをグローバル変数や静的プロパティで参照できない場合は、自分でそのコードを書き換えるのではなく、作者が用意しているフィルターや設定項目がないかを先に探します。

4. クロージャは基本的に外せない

クロージャは毎回別のオブジェクトになるため、同じ見た目の無名関数を書いても外れません。最終手段として remove_all_actions( 'フック名' )(優先度の指定も可)がありますが、他のコールバックも消えるため、影響範囲を確認してから使います。

動作確認(検証環境と結果)

WordPress 7.1.2(ja)、PHP 8.2.12 の CLI テスト環境で実行しました(C:Tempwp-testrun.php に上記のコードを渡して実行)。

  • 登録前の remove_action を書いた後に add_action(..., 20) → has_action は 20(まだ登録されている)
  • 優先度省略の remove_action → false、has_action は 20 のまま
  • 優先度 20 を指定 → true、has_action は false
  • クラス名文字列での指定 → false、インスタンス指定 → true
  • 別のクロージャで外そうとした → false、remove_all_actions → 全削除
  • 別のフック(timing_a)のコールバックで demo_late の登録を、do_action( 'demo_late' ) の前に外した → 外れて実行されなかった

詳細ログは testsremove-action-not-working.md に保存しています。

remove_action が効かない原因と対処の注意点

  • 他人のコードに remove_action を使うと、プラグインの更新で優先度が変わった際に、気付かないまま外れなくなることがあります。更新後の確認を習慣にしてください。
  • has_action() で事前に確認してから外すと、デバッグしやすくなります。
  • 管理画面専用のフックなど、実行される場面が限られるものは、そのコンテキストの中で外します。

remove_action が効かない原因と対処でよくあるミス

  • functions.php の最上部で、読み込み順の関係から、まだ追加されていないフックを外そうとする。
  • 追加側の優先度を確認せずに、既定値のまま外そうとする。
  • array( 'クラス名', 'メソッド' ) で外そうとする(静的メソッドでない限り無効)。
  • すでに実行された後のフック(例:wp_head の中から wp_head の登録を外す)に対して外そうとする。

remove_action が効かない原因と対処のチェックリスト

  • [ ] 追加側のコードで、フック名・関数名・優先度を確認したか
  • [ ] has_action() が、削除前に数値を返すことを確認したか
  • [ ] 削除コードは、追加の後・フックの実行前に動くか
  • [ ] クラスの場合は、インスタンスで指定しているか
  • [ ] remove_action() の戻り値を、デバッグ時に確認したか

remove_action が効かない原因と対処のFAQ(よくある質問)

Q. 戻り値が true なのに、まだ動いているのはなぜですか?
A. 同じ処理が別のフックや、別の優先度から二重に登録されている可能性があります。has_action() を複数のフックで確認してください。

Q. フィルターの場合も同じですか?
A. 同じです。remove_filter() を使い、考え方(優先度の一致・タイミング)は共通です。

Q. 子テーマで親テーマのフックを外すには?
A. 親テーマは先に読み込まれるため、子テーマの functions.php から after_setup_theme などで外します。

筆者の見解(remove_action が効かない原因と対処)

remove_action() が失敗しても何も言ってくれない点が、一番のつまずきどころだと考えます。まず has_action() で「今どの優先度で登録されているか」を表示して、数値を目で確認する方法が、遠回りに見えて最も早いと思います。なお、クロージャで書かれたコードは「外されないことを前提にした作り」とも読めるため、無理に外さず、設定項目やフィルターでの調整を探すのが穏当と私見では考えます。

remove_action が効かない原因と対処の関連項目

出典(一次情報)

タイトルとURLをコピーしました