15%

Сэкономьте 15% на всех хостинговых услугах

Проверьте свои навыки и получите скидку на любой тарифный план

Используйте код:

Skills
Начать
22.10.2024

WordPress Actions: Полное руководство разработчика по Hooks API

WordPress Actions — это основной компонент Hooks API, который позволяет разработчикам выполнять пользовательские функции в точно определённых точках жизненного цикла запроса WordPress — без изменения основных файлов. Когда срабатывает хук действия, каждая функция, зарегистрированная для этого хука, выполняется в порядке приоритета, обеспечивая модульную, удобную в обслуживании и безопасную при обновлениях настройку.

Если вы создаёте плагин, разрабатываете тему или управляете самостоятельно размещённой установкой WordPress в среде VPS Hosting, освоение Actions является обязательным. Именно на них построена архитектура самого WordPress — это не просто инструмент расширения для сторонних разработчиков.

Как WordPress Actions работают под капотом

WordPress поддерживает глобальный реестр $wp_filter, в котором хранятся все зарегистрированные хуки — как действия, так и фильтры. При вызове do_action() WordPress ищет запись этого хука в $wp_filter, сортирует зарегистрированные обратные вызовы по приоритету и выполняет их последовательно.

Критическое различие, которое многие руководства обходят стороной: Actions работают по принципу «выстрелил и забыл». Они выполняют обратные вызовы, но отбрасывают любые возвращаемые значения. Если вам нужно перехватить и изменить данные — это задача Filters, а не Actions. Путаница между ними — одна из наиболее распространённых архитектурных ошибок при разработке плагинов WordPress.

Поток выполнения выглядит следующим образом:

  1. Ядро WordPress (или плагин/тема) вызывает do_action( 'hook_name', ...$args ).
  2. WordPress разрешает все обратные вызовы, зарегистрированные для hook_name из $wp_filter.
  3. Обратные вызовы сортируются по значению $priority (по возрастанию — меньшие числа срабатывают первыми).
  4. Каждый обратный вызов вызывается с переданными аргументами.
  5. Возвращаемые значения молча игнорируются.
  6. Выполнение продолжается в исходном коде после возврата do_action().

Такая архитектура означает, что плохо написанный обратный вызов, зарегистрированный на ранний хук, например init, может заблокировать весь запрос. Всегда профилируйте обратные вызовы хуков на стейджинге перед развёртыванием в продакшн.

Регистрация Actions с помощью add_action()

Функция add_action() регистрирует PHP-callable для именованного хука действия. Её полная сигнатура:

add_action( string $hook_name, callable $callback, int $priority = 10, int $accepted_args = 1 ): true

Описание параметров:

    $hook_name — Точный строковый идентификатор хука действия (например, wp_login, save_post).
    $callback — Любой допустимый PHP callable: именованная функция, анонимная функция, статический метод array( 'MyClass', 'method' ) или метод объекта array( $object, 'method' ).
    $priority — Порядок выполнения относительно других обратных вызовов на том же хуке. По умолчанию 10. Обратные вызовы с одинаковым приоритетом выполняются в порядке регистрации.
    $accepted_args — Количество аргументов из do_action(), передаваемых в ваш обратный вызов. По умолчанию 1. Необходимо задать это значение корректно, иначе обратный вызов получит усечённый список аргументов.
    
    Базовый пример: подключение к wp_login
    function notify_admin_on_login( string $user_login, WP_User $user ): void {
        $admin_email = get_option( 'admin_email' );
        $subject     = 'Login Alert: ' . $user_login;
        $message     = sprintf(
            'User "%s" (ID: %d) logged in at %s.',
            $user_login,
            $user->ID,
            current_time( 'mysql' )
        );
        wp_mail( $admin_email, $subject, $message );
    }
    
    // wp_login passes two arguments: $user_login (string) and $user (WP_User object)
    add_action( 'wp_login', 'notify_admin_on_login', 10, 2 );
    Обратите внимание, что accepted_args установлен в 2. Если опустить это и оставить значение по умолчанию 1, ваш обратный вызов получит только $user_login и никогда не увидит объект WP_User — это скрытая ошибка, которую крайне сложно отследить.
    Использование методов объектов и замыканий
    Современная разработка под WordPress предпочитает инкапсуляцию логики внутри классов:
    class My_Plugin {
    
        public function __construct() {
            add_action( 'init', array( $this, 'register_post_types' ) );
            add_action( 'save_post', array( $this, 'handle_save' ), 20, 3 );
        }
    
        public function register_post_types(): void {
            register_post_type( 'product', array( /* args */ ) );
        }
    
        public function handle_save( int $post_id, WP_Post $post, bool $update ): void {
            if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
                return;
            }
            // Custom save logic here
        }
    }
    
    new My_Plugin();
    Анонимные замыкания тоже работают, но их нельзя удалить с помощью remove_action() позднее, поскольку PHP не может надёжно сравнивать ссылки на анонимные функции. Используйте именованные методы, когда вам нужна возможность отмены регистрации.
    Удаление Actions с помощью remove_action()
    Вы можете отменить регистрацию любого обратного вызова — включая добавленные другими плагинами или темами — с помощью remove_action(). Приоритет должен точно совпадать с тем, что использовалось в add_action():
    remove_action( 'wp_head', 'wp_generator' ); // Removes WordPress version meta tag
    Для методов объектов вам нужна ссылка на тот же экземпляр объекта:
    // Inside a plugin that exposes its instance
    global $my_plugin_instance;
    remove_action( 'save_post', array( $my_plugin_instance, 'handle_save' ), 20 );
    Распространённая ловушка: вызов remove_action() до того, как исходный add_action() выполнился. Всегда подключайте удаление к действию, которое срабатывает после загрузки целевого плагина — как правило, plugins_loaded или after_setup_theme.
    Справочник основных хуков действий WordPress
    В следующей таблице представлены наиболее операционно значимые хуки действий, контекст их срабатывания и практические варианты использования.
    
    
    
    
    Название хука
    Срабатывает когда
    Типичные варианты использования
    Передаваемые аргументы
    
    
    
    
    muplugins_loaded
    Загружены must-use плагины
    Ранняя начальная загрузка, константы
    0
    
    
    plugins_loaded
    Загружены все плагины
    Проверки совместимости между плагинами
    0
    
    
    init
    После загрузки WP, до отправки заголовков
    Регистрация CPT, таксономий, правил перезаписи
    0
    
    
    wp_loaded
    После init, всё загружено
    Регистрация REST API, поздние задачи инициализации
    0
    
    
    wp_enqueue_scripts
    Загрузка ресурсов на фронтенде
    Подключение CSS/JS для тем и плагинов
    0
    
    
    wp_head
    Внутри тега <head>
    Мета-теги, встроенные стили, фрагменты аналитики
    0
    
    
    wp_footer
    Перед </body>
    Отложенные скрипты, пиксели отслеживания
    0
    
    
    admin_init
    Загрузка страниц администратора
    Регистрация Settings API, проверки прав доступа
    0
    
    
    admin_enqueue_scripts
    Загрузка ресурсов администратора
    Подключение CSS/JS только для админки
    1 ($hook_suffix)
    
    
    save_post
    Запись сохранена или обновлена
    Обновление мета-данных, синхронизация с внешним API, уведомления
    3
    
    
    wp_login
    Пользователь аутентифицируется
    Журналирование аудита, управление сессиями
    2
    
    
    user_register
    Создан новый пользователь
    Приветственные письма, синхронизация с CRM, назначение ролей
    1 ($user_id)
    
    
    wp_logout
    Пользователь выходит из системы
    Очистка сессий, аналитические события
    1 ($user_id)
    
    
    switch_theme
    Изменяется активная тема
    Очистка кэша, миграция настроек
    2
    
    
    wp_trash_post
    Запись перемещена в корзину
    Очистка связанных данных, внешняя синхронизация
    1 ($post_id)
    
    
    rest_api_init
    Инициализация REST API
    Регистрация пользовательских маршрутов REST
    0
    
    
    template_redirect
    Перед загрузкой шаблона
    Перенаправления, контроль доступа
    0
    
    
    
    
    do_action() vs do_action_ref_array(): когда применять каждую
    Обе функции запускают хук действия, но различаются способом передачи аргументов.
    do_action()
    Стандартная функция. Аргументы передаются по значению — обратные вызовы получают копии.
    do_action( 'my_plugin_after_import', $import_id, $result_count, $errors );
    do_action_ref_array()
    Аргументы передаются в виде массива, а объекты внутри этого массива передаются по ссылке (объекты PHP всегда передаются по ссылке по умолчанию начиная с PHP 5). Это в первую очередь полезно для обеспечения совместимости с устаревшим кодом или когда вам явно нужно, чтобы обратные вызовы изменяли общую структуру данных.
    $context = array(
        'post_id' => 42,
        'meta'    => array(),
    );
    
    do_action_ref_array( 'my_plugin_process_context', array( &$context ) );
    
    // $context['meta'] may now be populated by hooked callbacks
    Практическое руководство: В современном PHP (7.4+) поведенческое различие между ними минимально для объектов. Используйте do_action() по умолчанию. Прибегайте к do_action_ref_array() только при интеграции с устаревшим кодом, который явно ожидает его, или когда вам нужно, чтобы обратные вызовы изменяли примитивное значение (например, целое число), переданное по ссылке.
    Создание и документирование пользовательских хуков действий
    При создании плагина или темы, предназначенных для расширения другими разработчиками, вы должны определять собственные хуки действий. Именно так вы открываете API-поверхность, не предоставляя сторонним разработчикам прямой доступ к вашим внутренним компонентам.
    /**
     * Fires after a custom import process completes.
     *
     * @since 1.0.0
     *
     * @param int   $import_id    The ID of the completed import batch.
     * @param int   $record_count Total number of records processed.
     * @param array $errors       Array of WP_Error objects, empty on full success.
     */
    do_action( 'my_plugin_import_complete', $import_id, $record_count, $errors );
    Всегда документируйте свои хуки с помощью DocBlock непосредственно над do_action(). Именно это питает генератор документации для разработчиков WordPress и делает ваш плагин профессионального уровня. Сторонние разработчики смогут подключаться к нему чисто:
    add_action( 'my_plugin_import_complete', function( int $import_id, int $count, array $errors ) {
        if ( ! empty( $errors ) ) {
            // Log errors to an external monitoring service
            error_log( "Import {$import_id} completed with " . count( $errors ) . ' errors.' );
        }
    }, 10, 3 );
    Actions vs Filters: исчерпывающее сравнение
    Это наиболее важное концептуальное различие во всём Hooks API WordPress.
    
    
    
    
    Параметр
    Actions
    Filters
    
    
    
    
    Основное назначение
    Выполнение побочных эффектов в определённой точке
    Перехват и изменение данных
    
    
    Возвращаемое значение
    Полностью игнорируется
    Должно возвращать (изменённое) значение
    
    
    Основная функция
    do_action()
    apply_filters()
    
    
    Регистрация
    add_action()
    add_filter()
    
    
    Типичное использование
    Отправка email, запись в БД, подключение ресурсов
    Изменение содержимого записей, изменение аргументов запроса
    
    
    Может прервать выполнение?
    Нет (все обратные вызовы всегда выполняются)
    Нет (но можно выйти раньше внутри обратного вызова)
    
    
    Изменение данных
    Не предусмотренный паттерн
    Основное назначение
    
    
    
    
    Ключевое архитектурное правило: Если вы используете add_filter(), но не возвращаете значение из обратного вызова, вы внесли ошибку — отфильтрованное значение станет null или false в зависимости от контекста. И наоборот, если вы используете add_action() и полагаетесь на возвращаемое значение, вы неправильно используете API.
    Конфликты приоритетов и порядок выполнения
    Управление приоритетами становится критически важным в сложных экосистемах плагинов. Рассмотрим сценарий, где WooCommerce, плагин кэширования и ваш пользовательский код подключаются к save_post:
    // WooCommerce hooks at priority 10 (default)
    // Your inventory sync needs WooCommerce data to already be saved
    add_action( 'save_post_product', 'sync_inventory_to_erp', 99 );
    
    // A cache purge should happen last, after all data is written
    add_action( 'save_post', 'purge_varnish_cache', 9999 );
    Граничные случаи, которые нужно знать:
    
    Отрицательные приоритеты допустимы в WordPress. add_action( 'init', 'my_func', -1 ) срабатывает раньше всего с приоритетом 0 или 10.
    Одинаковый приоритет, несколько обратных вызовов — они выполняются в порядке вызова add_action(). Порядок загрузки плагинов (определяемый алфавитно по имени файла или плагинами Plugin Order) поэтому влияет на поведение.
    Рекурсивные хуки — вызов do_action() для того же хука внутри обратного вызова этого хука технически возможен, но создаёт бесконечные циклы. WordPress не защищает от этого.
    Поздняя регистрация хука — если вы вызываете add_action( 'init', ... ) после того, как init уже сработал, ваш обратный вызов никогда не выполнится в этом запросе. Это частый источник ошибок в коде, который выполняется условно.
    
    Реальные производственные паттерны
    Паттерн 1: Развязанная система событий
    Используйте пользовательские действия для развязки компонентов плагина, избегая прямых вызовов функций между модулями:
    // In your order processing module
    do_action( 'my_shop_order_paid', $order_id, $payment_method, $amount );
    
    // In your email module (separate file, no direct dependency)
    add_action( 'my_shop_order_paid', 'send_payment_confirmation_email', 10, 3 );
    
    // In your analytics module (separate file, no direct dependency)
    add_action( 'my_shop_order_paid', 'track_conversion_event', 20, 3 );
    Этот паттерн означает, что вы можете полностью отключить модуль аналитики, не затрагивая код обработки заказов.
    Паттерн 2: Условная регистрация хуков
    Избегайте безусловной регистрации хуков на верхнем уровне. Ограничивайте их контекстом, в котором они нужны:
    add_action( 'admin_init', function() {
        // Only register these hooks in the admin context
        add_action( 'admin_enqueue_scripts', 'my_plugin_admin_assets' );
        add_action( 'save_post', 'my_plugin_validate_custom_fields', 10, 2 );
    } );
    Паттерн 3: Одноразовые действия с remove_action() внутри обратного вызова
    function my_plugin_run_once(): void {
        // Do something that must only happen once per request
        update_option( 'my_plugin_initialized', true );
    
        // Deregister itself to prevent re-execution if the hook fires again
        remove_action( 'wp_loaded', 'my_plugin_run_once' );
    }
    
    add_action( 'wp_loaded', 'my_plugin_run_once' );
    Соображения производительности в управляемых средах
    На высоконагруженных установках WordPress — будь то план VPS Hosting или Dedicated Server — совокупные затраты плохо оптимизированных хуков поддаются измерению.
    Инструменты профилирования:
    
    Плагин Query Monitor: показывает каждый сработавший хук, каждый выполненный обратный вызов и время выполнения каждого обратного вызова.
    Xdebug + KCacheGrind: для глубокого профилирования путей выполнения обратных вызовов.
    New Relic APM: для мониторинга производительности хуков на уровне продакшна.
    
    Принципы оптимизации:
    
    Перенесите ресурсоёмкие операции (запросы к базе данных, HTTP-запросы, файловый ввод-вывод) из хуков, срабатывающих при каждой загрузке страницы (init, wp_head), в хуки, срабатывающие только при необходимости (save_post, user_register).
    Используйте транзиенты или кэширование объектов для мемоизации результатов ресурсоёмких вычислений внутри обратных вызовов хуков.
    Избегайте безусловной регистрации сотен вызовов add_action() при загрузке плагина. Регистрируйте хуки лениво только тогда, когда активна соответствующая страница администратора или контекст.
    На серверах с включённым OPcache (который должен быть на всех правильно настроенных PHP-средах) накладные расходы на саму регистрацию хуков незначительны — затраты связаны с тем, что *делают* обратные вызовы, а не с регистрацией.
    
    Если вы управляете собственным стеком WordPress, обеспечение работы сервера на PHP 8.1+ с OPcache, кэшем байткода и кэшем объектов, таким как Redis или Memcached, окажет значительно большее влияние на производительность, чем микрооптимизация приоритетов хуков.
    WordPress Actions в контексте разработки плагинов и тем
    При разработке плагина для репозитория WordPress.org или коммерческого распространения использование Hooks API напрямую определяет качество кода и рейтинги совместимости.
    Лучшие практики для использования хуков производственного уровня:
    
    Всегда проверяйте DOING_AUTOSAVE внутри обратных вызовов save_post, чтобы избежать выполнения ресурсоёмкой логики при автосохранениях.
    Проверяйте nonce и права доступа внутри любого обратного вызова хука, обрабатывающего данные, отправленные пользователем. Никогда не полагайтесь на то, что сам хук обеспечивает безопасность.
    Используйте current_action(), чтобы определить, какой именно хук запустил ваш обратный вызов, когда одна функция зарегистрирована для нескольких хуков.
    Используйте пространство имён для пользовательских хуков, чтобы избежать коллизий: my_plugin_event_name, а не event_name.
    Версионируйте свои хуки в документации, чтобы разработчики знали, когда хук был введён и когда он может быть устаревшим.
    
    Для команд, развёртывающих WordPress на инфраструктуре с VPS Control Panels, поддержание стейджинг-сред, зеркалирующих продакшн, необходимо для безопасного тестирования взаимодействий хуков перед развёртыванием.
    Защита установки WordPress наряду с пользовательскими Actions
    Пользовательские хуки действий, обрабатывающие внешние данные, управляющие событиями аутентификации или взаимодействующие с файловой системой, расширяют поверхность атаки. Сочетайте разработку хуков с надлежащим образом защищённой хостинговой средой.
    Убедитесь, что ваша установка WordPress использует HTTPS — SSL Certificate обязателен для любого сайта, обрабатывающего аутентификацию пользователей или отправку форм. Обратные вызовы хуков, срабатывающие на wp_login или user_register, обрабатывают конфиденциальные данные по сети; без TLS эти данные открыты независимо от того, насколько хорошо написан ваш PHP-код.
    Кроме того, если ваш плагин использует wp_mail() внутри обратных вызовов действий (распространённый паттерн для уведомлений), конфигурация почты вашего сервера и его репутация напрямую влияют на доставляемость. Рассмотрите выделенное решение Email Hosting с надлежащими записями SPF, DKIM и DMARC вместо использования sendmail на уровне сервера.
    Матрица технических решений и ключевые выводы
    Используйте этот контрольный список при реализации WordPress Actions в любом проекте:
    Регистрация хуков:
    
    Явно задавайте $accepted_args всякий раз, когда хук передаёт более одного аргумента
    Используйте значения приоритета осознанно — документируйте, почему выбраны нестандартные приоритеты
    Регистрируйте хуки внутри конструкторов классов или выделенных методов register_hooks(), но никогда в глобальной области видимости файла плагина
    Ограничивайте регистрацию хуков контекстом, в котором они нужны (администратор, фронтенд, REST API)
    
    Реализация обратных вызовов:
    
    Всегда проверяйте DOING_AUTOSAVE, DOING_CRON и wp_is_json_request() там, где это уместно
    Проверяйте nonce с помощью check_admin_referer() или check_ajax_referer() перед обработкой любых пользовательских данных
    Никогда не полагайтесь на возвращаемые значения от do_action() — используйте фильтры, если вам нужны данные обратно
    Используйте current_action(), когда один обратный вызов обслуживает несколько хуков
    
    Проектирование пользовательских хуков:
    
    Используйте пространство имён для всех пользовательских хуков с префиксом вашего плагина/темы
    Документируйте каждый пользовательский хук полным DocBlock над do_action()
  • Передавайте достаточно аргументов, чтобы хук был полезным, не раскрывая внутреннее состояние без необходимости
  • Предпочитайте do_action() вместо do_action_ref_array(), если у вас нет конкретной причины

Производительность и обслуживание:

  • Профилируйте обратные вызовы хуков с помощью Query Monitor перед развёртыванием в продакшн
  • Избегайте запросов к базе данных внутри хуков, срабатывающих при каждом запросе
  • Используйте remove_action() для очистки сторонних хуков, конфликтующих с вашей реализацией
  • Тестируйте взаимодействия хуков в стейджинг-среде, зеркалирующей производственную инфраструктуру

FAQ

В чём разница между add_action() и add_filter() в WordPress?

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

Почему мой обратный вызов add_action() не срабатывает?

Наиболее распространённые причины: (1) имя хука написано с ошибкой, (2) add_action() вызывается после того, как хук уже сработал в текущем запросе, (3) $accepted_args слишком мало, и обратный вызов получает неверные данные, вызывая скрытую ошибку PHP, или (4) условная проверка внутри обратного вызова предотвращает выполнение. Используйте Query Monitor, чтобы проверить, сработал ли хук и был ли зарегистрирован ваш обратный вызов.

Можно ли использовать add_action() внутри другого обратного вызова действия?

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

Что на самом деле контролирует параметр $priority?

Он контролирует порядок, в котором выполняются несколько обратных вызовов, зарегистрированных для одного хука. Меньшие числа срабатывают первыми. По умолчанию 10. Допустимы отрицательные целые числа. Когда два обратных вызова имеют одинаковый приоритет, они выполняются в порядке регистрации через add_action().

Как безопасно удалить действие, добавленное сторонним плагином?

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

15%

Сэкономьте 15% на всех хостинговых услугах

Проверьте свои навыки и получите скидку на любой тарифный план

Используйте код:

Skills
Начать