☰
WORDPRESS / PRACTICE

Почему remove_action() не работает в WordPress и как правильно удалить callback

Почему remove_action() не работает в WordPress и как правильно удалить callback

Функция remove_action() позволяет отключить callback, ранее добавленный с помощью add_action(). Это полезно, когда нужно изменить поведение плагина или темы без редактирования их файлов.

На практике remove_action() часто «не работает», потому что WordPress ищет callback по точному набору параметров: имени хука, функции или методу, приоритету и моменту выполнения. Если хотя бы один элемент не совпадает, удаление не произойдёт.

Как работает remove_action()

При вызове add_action() WordPress сохраняет callback во внутреннем списке конкретного хука. В этой записи учитываются имя хука, callback и его приоритет. remove_action() не удаляет «похожую» функцию, а ищет именно ту запись, которая была добавлена ранее.

Сигнатура функции выглядит так:

  • имя хука должно полностью совпадать;
  • функция, метод или объект должны совпадать;
  • приоритет должен быть таким же, как в add_action();
  • удаление нужно выполнить после регистрации callback, но до его фактического запуска.
remove_action( string $hook_name, callable $callback, int $priority = 10 ): bool;

Неправильный приоритет — самая распространённая причина

Если при добавлении callback был указан приоритет 20, удалить его с приоритетом 10 нельзя. Значение по умолчанию в remove_action() равно 10, поэтому отсутствие третьего аргумента часто становится причиной ошибки.

Важно также различать момент регистрации и момент выполнения. В примере ниже callback регистрируется на init с приоритетом 20, а удаляется на том же хуке с приоритетом 30. При первом запуске init callback с приоритетом 20 уже успеет выполниться. Удаление повлияет только на следующие вызовы этого хука, если они вообще произойдут.

  • Чтобы callback не выполнился, его нужно удалить до того, как WordPress дойдёт до его приоритета.
  • Если сторонний код добавляет callback во время init, удаление с более высоким приоритетом не отменит уже выполненное действие.
  • Для одноразовых хуков, таких как init, удаление с опозданием обычно не даёт ожидаемого результата.
add_action( 'init', 'plugin_register_post_type', 20 );

// Этот код выполнится после callback с приоритетом 20.
add_action( 'init', function () {
    remove_action( 'init', 'plugin_register_post_type', 20 );
}, 30 );

Проверьте, когда именно добавляется callback

Вызов remove_action() должен произойти после add_action(), иначе в WordPress ещё не будет записи, которую нужно удалить. В то же время удаление должно выполняться достаточно рано, чтобы callback не успел сработать.

Например, плагин может регистрировать свой callback на plugins_loaded, init, wp_loaded или специальном хуке. Если ваш код выполняется раньше, callback ещё не существует. Если значительно позже — он уже мог сработать.

Лучший подход — найти в коде плагина строку add_action() и определить всю цепочку: где она выполняется, какой у неё приоритет и на каком хуке можно безопасно вмешаться.

  • Если callback добавляется во время plugins_loaded, код для его удаления должен выполниться после этого момента.
  • Если callback добавляется на init, удаление на init с более высоким приоритетом может оказаться запоздалым для текущего запуска.
  • Если действие уже изменило данные или зарегистрировало тип записи, remove_action() не вернёт систему в предыдущее состояние — он лишь предотвратит будущие вызовы.
add_action( 'plugins_loaded', function () {
    remove_action( 'some_hook', 'plugin_callback', 10 );
}, 20 );

Как проверить, зарегистрирован ли callback

Для быстрой проверки используйте has_action(). Функция возвращает приоритет callback, если он найден, или false, если такой записи нет. Поскольку add_action() в WordPress работает через тот же внутренний механизм, has_action() подходит и для диагностики action.

Проверку лучше выполнять непосредственно перед remove_action(), а результат записывать в журнал. Это помогает отличить неправильный callback от проблемы с моментом выполнения.

  • Значение false означает, что callback с таким описанием не найден.
  • Число означает фактически зарегистрированный приоритет.
  • Если приоритет отличается от ожидаемого, передайте в remove_action() фактический приоритет.
$priority = has_action( 'init', 'plugin_register_post_type' );
error_log( var_export( $priority, true ) );

if ( false !== $priority ) {
    remove_action( 'init', 'plugin_register_post_type', $priority );
}

Методы объектов и анонимные функции

Callback часто принадлежит не глобальной функции, а объекту. В таком случае нужно передать тот же экземпляр объекта. Создание нового экземпляра того же класса и метода не поможет: для WordPress это другой callable.

Для статического метода используется другой синтаксис, чем для метода конкретного объекта. Также нужно учитывать пространства имён: имя функции может содержать префикс namespace.

  • Для метода объекта требуется тот же экземпляр.
  • Для статического метода используйте [ ClassName::class, 'method' ] или соответствующую строку.
  • Анонимную функцию можно удалить только в том случае, если при регистрации она была сохранена в переменной.
  • Создать новую closure с идентичным кодом недостаточно: это будет другой объект функции.
$plugin_object = new Plugin_Class();

add_action( 'init', [ $plugin_object, 'register' ], 10 );

// Требуется именно тот же $plugin_object.
remove_action( 'init', [ $plugin_object, 'register' ], 10 );

$callback = function () {
    // Действие.
};

add_action( 'init', $callback, 10 );
remove_action( 'init', $callback, 10 );

Action и filter: что именно нужно удалять

В WordPress add_action() и add_filter() используют общий внутренний механизм. Однако на уровне API всё же стоит применять соответствующую пару: callback, добавленный через add_action(), удаляйте с помощью remove_action(), а callback из add_filter() — с помощью remove_filter(). Так код будет понятнее и менее подвержен ошибкам.

Ключевое значение имеет не название функции удаления, а точное совпадение имени хука, callback и приоритета. Если callback был добавлен на filter, проверяйте именно этот filter и не путайте его с action с похожим названием.

Параметр accepted_args не нужно передавать в remove_action() или remove_filter(). Для поиска callback WordPress использует хук, callable и приоритет.

  • Проверьте, не перепутаны ли названия похожих хуков.
  • Не пытайтесь удалить filter через другой хук с тем же callback.
  • Если callback добавляется несколько раз с разными приоритетами, каждую запись нужно удалять отдельно.
add_filter( 'the_content', 'plugin_modify_content', 20 );

remove_filter( 'the_content', 'plugin_modify_content', 20 );

Практический алгоритм диагностики

Если remove_action() не даёт результата, не стоит сразу менять приоритет наугад. Последовательная проверка поможет быстрее найти причину.

  • Найдите исходный вызов add_action() в коде плагина или темы.
  • Скопируйте точное имя хука и callback.
  • Проверьте приоритет — если он не указан, это 10.
  • Определите, является ли callback обычной функцией, методом объекта, статическим методом или closure.
  • Проверьте, выполняется ли ваш код после регистрации callback, но до его запуска.
  • Используйте has_action() и проверьте его результат.
  • Убедитесь, что действие не успело выполниться раньше и изменить состояние системы.
  • После тестирования ограничьте удаление нужным условием, окружением или конкретным контекстом.
add_action( 'wp_loaded', function () {
    $priority = has_action( 'some_hook', [ $same_object, 'method' ] );

    error_log( 'Callback priority: ' . var_export( $priority, true ) );

    if ( false !== $priority ) {
        remove_action( 'some_hook', [ $same_object, 'method' ], $priority );
    }
}, 20 );

Безопасное использование remove_action()

Глобальное удаление callback может повлиять на все страницы и функции сайта. Перед изменением проверьте, зачем нужно это действие, не зависит ли от него другой код и в каком контексте его требуется отключить.

Если изменение необходимо только для административной части, конкретного типа записи или отдельного шаблона, добавьте соответствующее условие. Это снизит риск побочных эффектов после обновления плагина.

  • Не редактируйте файлы стороннего плагина — вынесите код в собственный плагин или тему.
  • Тестируйте изменения на staging-среде.
  • Во время диагностики записывайте результат проверки в журнал, но не оставляйте лишнее логирование в production.
  • После обновления плагина повторно проверьте имя callback, приоритет и способ его регистрации.
add_action( 'wp', function () {
    if ( ! is_singular( 'product' ) ) {
        return;
    }

    remove_action( 'some_hook', 'plugin_callback', 10 );
}, 20 );

Частые вопросы

Можно ли вызвать remove_action() до add_action()?

Обычно нет. Если callback ещё не зарегистрирован, WordPress не найдёт его и ничего не удалит. При этом недостаточно вызвать remove_action() после add_action() — нужно сделать это до фактического запуска callback.

Почему remove_action() возвращает true, но действие всё равно выполняется?

Чаще всего callback был добавлен несколько раз, например с разными приоритетами, или он уже успел выполниться до удаления. Проверьте все регистрации и момент вызова.

Можно ли удалить метод объекта, создав новый экземпляр класса?

Нет. Для обычного метода нужен тот же экземпляр, который был передан в add_action(). Новый объект с тем же классом и методом имеет другую идентичность.

Как удалить анонимную функцию?

Нужно сохранить closure в переменной во время регистрации, а затем передать эту же переменную в remove_action(). Повторно объявленная анонимная функция не будет тем же callback.

Можно ли использовать remove_action() для callback, добавленного через add_filter()?

Внутренне эти API используют общий механизм, но для ясности кода применяйте remove_filter() для filter и remove_action() для action. В любом случае должны совпадать хук, callback и приоритет.

Вывод

remove_action() работает только при точном совпадении всех параметров и правильном моменте выполнения. Проверьте исходный add_action(), приоритет, тип callback и конкретный экземпляр объекта.

Если callback уже сработал, его удаление не отменит выполненное действие. Поэтому при диагностике важно определить не только то, что нужно удалить, но и момент, когда это нужно сделать.

← Все материалы WordPress