Заметки

Хуки WooCommerce: как менять поведение магазина

M
Markabus
·8 сентября 2026 г.
Рабочее место разработчика ночью: на переднем мониторе — редактор с PHP-кодом, на втором — страница товара интернет-магазина; свет от экранов падает на клавиатуру и стол

Речь о WooCommerce — плагине интернет-магазина для WordPress, и о его точках расширения в PHP-коде. Хук (hook, «крючок») — это заранее объявленное место в коде, к которому можно прицепить свою функцию. Плагин доходит до этого места, видит, что кто-то подписался, и вызывает вашу функцию. Так магазин меняют, не трогая ни одного файла самого WooCommerce: обновление плагина приезжает — правки остаются на месте.

Это главное, ради чего вообще стоит разбираться с хуками. Правка шаблона «на живую» переживает ровно одно обновление, а функция в своей теме или своём плагине живёт годами. Ниже — как устроены хуки, где их искать, пять готовых рецептов и отдельно про ловушку 2026 года, из-за которой половина найденных в интернете сниппетов для оформления заказа просто не работает.

Действие и фильтр: два разных инструмента

Хуки бывают двух видов, и путать их не стоит.

Действие (action) — «сделай что-нибудь в этой точке». Ничего не возвращает, просто выполняется: выводит блок HTML, пишет в лог, отправляет письмо. Подключается через add_action().

Фильтр (filter) — «получи значение и верни изменённое». Ему передают данные, он обязан вернуть результат. Подключается через add_filter(). Забыли return — магазин получит null вместо цены, названия или списка полей, и что-нибудь сломается.

// Действие: вывести плашку под ценой товара
add_action( 'woocommerce_single_product_summary', 'my_delivery_note', 25 );
function my_delivery_note() {
    echo '<p class="delivery-note">Доставка по городу за один день</p>';
}

// Фильтр: поменять текст кнопки покупки
add_filter( 'woocommerce_product_single_add_to_cart_text', 'my_cart_button_text' );
function my_cart_button_text( $text ) {
    return 'Купить в один клик';
}

Механизм не woo-специфичный: это обычные хуки WordPress, WooCommerce лишь объявляет свои сотни точек поверх них. Официальная документация плагина описывает ровно эту схему и приводит как примеры woocommerce_thankyou, woocommerce_before_cart и woocommerce_sale_flash.

Куда писать код

Три рабочих варианта, по возрастанию надёжности:

  • functions.php дочерней темы — быстро и нормально для мелких правок оформления. Обязательно дочерней: в родительской правки затрёт обновление темы.
  • Плагин сниппетов (Code Snippets и аналоги) — удобно, когда правок много и их надо включать-выключать по одной. Минус — код лежит в базе, а не в репозитории.
  • Свой маленький плагин — правильный вариант для логики магазина. Папка wp-content/plugins/moy-magazin/, один PHP-файл с заголовком плагина, и вся кастомизация переезжает вместе с сайтом независимо от темы.

Чего делать не нужно никогда: редактировать файлы внутри wp-content/plugins/woocommerce/. Это не «быстрое решение», а гарантированная потеря правок при ближайшем автообновлении.

Карта хуков: где что находится

Страница товара

Почти вся страница товара собрана из одного действия — woocommerce_single_product_summary, к которому сам WooCommerce подключил свои функции с разными приоритетами:

  • 5 — заголовок товара
  • 10 — рейтинг и цена
  • 20 — краткое описание
  • 30 — форма «В корзину»
  • 40 — метаданные (артикул, категории)
  • 50 — блок «Поделиться»

Хотите вставить свой блок между кратким описанием и кнопкой покупки — берите приоритет 25. Между ценой и описанием — 15. Ниже по странице работает woocommerce_after_single_product_summary: вкладки (10), апсейлы (15), похожие товары (20).

Каталог

За шапку архива отвечает woocommerce_before_main_content (обёртка — 10, хлебные крошки — 20), за строку над сеткой товаров — woocommerce_before_shop_loop: счётчик результатов на приоритете 20 и селект сортировки на 30.

Корзина, оформление, письма

Классические точки: woocommerce_before_cart, woocommerce_check_cart_items (проверки перед оформлением), woocommerce_before_checkout_form, woocommerce_checkout_process (валидация), woocommerce_thankyou (страница «Спасибо за заказ»), woocommerce_email_order_meta (дописать данные в письмо). Про корзину и оформление читайте отдельный раздел ниже — там всё изменилось.

Приоритет и количество аргументов

У add_action() и add_filter() четыре параметра: имя хука, функция, приоритет (по умолчанию 10) и число аргументов (по умолчанию 1).

Приоритет — это порядок: меньше число, раньше вызов. Функции с одинаковым приоритетом выполняются в порядке подключения.

Число аргументов — частая причина «фатальной ошибки» на ровном месте. Если функция принимает два параметра, а вы не указали четвёртый аргумент, PHP получит только один и упадёт:

add_filter( 'woocommerce_product_get_price', 'my_price', 10, 2 );
function my_price( $price, $product ) {
    if ( $product->is_on_sale() ) {
        return $price;
    }
    return $price;
}

remove_action: убрать штатный вывод

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

add_action( 'init', 'my_remove_related' );
function my_remove_related() {
    remove_action(
        'woocommerce_after_single_product_summary',
        'woocommerce_output_related_products',
        20
    );
}

Обратите внимание на обёртку в init: если вызвать remove_action() раньше, чем WooCommerce успел подключить свою функцию, снимать будет нечего. Это ошибка номер один при работе с удалением хуков.

Пять рабочих рецептов

1. Плашка «осталось мало» при низком остатке.

add_action( 'woocommerce_single_product_summary', 'my_low_stock', 25 );
function my_low_stock() {
    global $product;
    $qty = $product->get_stock_quantity();
    if ( $qty && $qty <= 3 ) {
        echo '<p class="low-stock">Осталось ' . intval( $qty ) . ' шт.</p>';
    }
}

2. Минимальная сумма заказа.

add_action( 'woocommerce_check_cart_items', 'my_min_order' );
function my_min_order() {
    $min = 2000;
    if ( WC()->cart->get_cart_contents_total() < $min ) {
        wc_add_notice(
            'Минимальная сумма заказа — ' . $min . ' ₽',
            'error'
        );
    }
}

3. Спрятать способ оплаты для дорогих заказов.

add_filter( 'woocommerce_available_payment_gateways', 'my_hide_cod' );
function my_hide_cod( $gateways ) {
    if ( is_admin() || ! WC()->cart ) {
        return $gateways;
    }
    if ( WC()->cart->get_cart_contents_total() > 50000 ) {
        unset( $gateways['cod'] );
    }
    return $gateways;
}

4. Дописать данные в письмо покупателю.

add_action( 'woocommerce_email_order_meta', 'my_email_note', 10, 3 );
function my_email_note( $order, $sent_to_admin, $plain_text ) {
    if ( $sent_to_admin ) {
        return;
    }
    echo '<p>Вопросы по заказу — на shop@example.ru</p>';
}

5. Своё действие после оформления заказа — отправить данные в CRM, поставить задачу, дёрнуть внешний сервис:

add_action( 'woocommerce_thankyou', 'my_after_order' );
function my_after_order( $order_id ) {
    $order = wc_get_order( $order_id );
    // отправка в CRM, запись в лог и т.п.
}

Главная ловушка: блочные «Корзина» и «Оформление заказа»

Начиная с блочных шаблонов корзины и чекаута, классические хуки на этих двух страницах не вызываются вообще. Блоки рендерятся на React через Store API, PHP-шаблонов там нет — а значит, нечему и срабатывать. Актуально для всей линейки WooCommerce 11.x (на сентябрь 2026 в репозитории WordPress.org — версия 11.1.0, требования: WordPress 7.0+ и PHP 7.4+).

Официальная документация WooCommerce ведёт отдельный список несовместимых хуков. Не работают, в частности:

  • woocommerce_before_cart, woocommerce_after_cart, woocommerce_cart_contents;
  • woocommerce_before_checkout_form, woocommerce_checkout_billing, woocommerce_checkout_shipping;
  • woocommerce_checkout_process, woocommerce_checkout_create_order;
  • woocommerce_cart_item_name, woocommerce_cart_item_quantity, woocommerce_cart_total;
  • woocommerce_gateway_icon, woocommerce_gateway_description.

Чем их заменяют:

  • Свои поля на чекауте — Additional Checkout Fields API вместо woocommerce_checkout_fields.
  • Логика после оформления — серверные хуки Store API: woocommerce_store_api_checkout_order_processed, woocommerce_store_api_checkout_update_order_meta.
  • Свой блок в вёрстке — Slot/Fill на JavaScript (например, ExperimentalOrderShippingPackages) либо просто вложенный блок в редакторе.
  • Платёжные методы — регистрация через JS-интеграцию блоков, а не через PHP-фильтры иконок и описаний.

Практический вывод: прежде чем гуглить сниппет для чекаута, посмотрите, что стоит на странице — классический шорткод [woocommerce_checkout] или блок «Оформление заказа». От этого зависит, какой половиной документации пользоваться.

Как найти нужный хук

Три способа, от быстрого к точному:

  1. Визуальные карты хуков. Готовые схемы страницы товара, каталога и корзины с подписанными точками — быстрее, чем читать исходники.
  2. Grep по исходникам. Точки объявлены прямо в коде плагина: grep -rn "do_action( 'woocommerce_" wp-content/plugins/woocommerce/templates/. Регистрация штатных функций собрана в includes/wc-template-hooks.php — там же видны и приоритеты, нужные для remove_action().
  3. Официальный Code Reference — полный список хуков ядра с указанием файла и строки.

Частые ошибки

  • Фильтр без return — самая массовая. Действие ничего не возвращает, фильтр обязан.
  • Забытый четвёртый аргумент — функция ждёт три параметра, а получает один, и PHP падает с fatal error.
  • remove_action() с другим приоритетом — снятие молча не срабатывает, ошибки нет, блок остаётся на месте.
  • Тяжёлый код в хуке цикла. Функция на woocommerce_before_shop_loop_item вызывается для каждого товара: запрос к базе внутри превращается в десятки запросов на страницу. Если магазин тормозит, начните с чек-листа ускорения WordPress и индексов MySQL.
  • Прямой вывод в письма без экранирования — данные заказа прогоняйте через esc_html(). Общие правила — в гайде по безопасности WordPress.

Вывод

Хуки — это штатный, а не «хакерский» способ менять магазин. Схема простая: найти точку, выбрать действие или фильтр, подобрать приоритет, положить функцию в свой плагин или дочернюю тему. Три вещи, которые экономят часы: всегда возвращать значение из фильтра, всегда сверять приоритет при remove_action() и всегда проверять, классическая перед вами страница или блочная.

Дальше от простых правок обычно идут к автоматизации: генерации alt-текстов нейросетью и подключению ИИ к магазину через MCP — там те же хуки, только как точки входа для внешних сервисов. А если магазин большой, к скорости добавьте объектный кеш на Redis.

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

Q.Чем действие (action) отличается от фильтра (filter)?

Действие выполняет код в определённой точке и ничего не возвращает — например, выводит блок HTML на странице товара. Фильтр получает значение, изменяет его и обязан вернуть результат через return: текст кнопки, цену, список полей. Если из фильтра забыть return, магазин получит null вместо данных, и страница сломается.

Q.Куда добавлять код с хуками — в functions.php темы или в отдельный плагин?

Для мелких правок оформления подойдёт functions.php дочерней темы. Логику магазина лучше выносить в свой небольшой плагин: тогда правки переживут смену темы и переедут вместе с сайтом. Файлы внутри папки самого WooCommerce редактировать нельзя — обновление их затрёт.

Q.Почему мой хук не срабатывает на странице оформления заказа?

Скорее всего, на странице стоит блок «Оформление заказа», а не классический шорткод. В блочных корзине и чекауте PHP-шаблонов нет — рендер идёт на JavaScript через Store API, поэтому классические хуки вроде woocommerce_before_checkout_form или woocommerce_checkout_process не вызываются. Замены: Additional Checkout Fields API для полей, серверные хуки woocommerce_store_api_* для логики заказа, Slot/Fill для вёрстки.

Q.Как узнать приоритет, с которым WooCommerce подключил свою функцию?

Посмотреть файл includes/wc-template-hooks.php в папке плагина — там собраны все штатные add_action с приоритетами. Например, блок похожих товаров подключён к woocommerce_after_single_product_summary с приоритетом 20, и remove_action без этого же числа не сработает.

Источники

Предыдущая
WP-CLI: команды на каждый день

Читайте также

Тёмный рабочий стол разработчика крупным планом: экран ноутбука с открытым терминалом и командной строкой, рядом механическая клавиатура, кабель и сетевой коммутатор в расфокусеЗаметки
7 сентября 2026 г.

WP-CLI: команды на каждый день

Рабочий набор команд WP-CLI для повседневного обслуживания сайтов: установка, обновления ядра и плагинов, дампы базы, замена домена без порчи сериализованных данных, пользователи, медиа, кеш, cron, алиасы для нескольких окружений — и грабли, на которые наступают чаще всего.

Читать →
Тёмный рабочий стол разработчика крупным планом: монитор с планом выполнения SQL-запроса в терминале, рядом механическая клавиатура и стойка с индикаторамиЗаметки
4 сентября 2026 г.

Индексы MySQL: как ускорить запросы

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

Читать →
Монитор на тёмном рабочем столе показывает длинный технический документ, разбитый на выделенные цветом блоки с перекрытиями, рядом — терминал, SSD и мини-ПК в расфокусеЗаметки
3 сентября 2026 г.

Чанкинг документов для RAG: как правильно резать текст

В RAG качество ответов зависит не от модели, а от того, как вы порезали документы на фрагменты. Разбираем четыре стратегии чанкинга, рабочие размеры чанка и перекрытия, контекстное обогащение и late chunking — и как замерить, что стало лучше.

Читать →