☰
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.

  • Для методу об’єкта потрібен той самий instance.
  • Для статичного методу використовуйте [ 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(). Так код буде зрозумілішим і менш схильним до помилок.

Ключове значення має не назва функції видалення, а точна відповідність hook name, callback і пріоритету. Якщо callback було додано на filter, перевіряйте саме цей filter і не плутайте його з action із подібною назвою.

Параметр accepted_args не потрібно передавати в remove_action() або remove_filter(). Для пошуку callback WordPress використовує hook, callable і пріоритет.

  • Перевірте, чи не переплутано назви схожих хуків.
  • Не намагайтеся видалити filter через інший hook із таким самим 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. У будь-якому разі мають збігатися hook, callback і пріоритет.

Висновок

remove_action() працює лише за точного збігу всіх параметрів і правильного моменту виконання. Перевірте оригінальний add_action(), пріоритет, тип callback і конкретний instance об’єкта.

Якщо callback уже спрацював, його видалення не скасує виконану дію. Тому головне під час діагностики — визначити не лише що саме потрібно видалити, а й коли це потрібно зробити.

← Усі матеріали WordPress