WooCommerce многое делает без перезагрузки страницы: товар уходит в корзину по Ajax, мини-корзина обновляется сама, итоги чекаута пересчитываются при смене способа доставки. Из-за этого привычный подход «навесил обработчик на кнопку при загрузке страницы» ломается — после Ajax-обновления DOM подменяется, и обработчик перестаёт срабатывать.
Решение WooCommerce предлагает своё: набор собственных событий, которые магазин рассылает в ключевые моменты. Подписавшись на них, можно выполнить свой код ровно тогда, когда нужно.
Как устроены события WooCommerce
Почти все события WooCommerce отправляются на document.body, а не на конкретный элемент. Это сделано намеренно: тело документа при Ajax-обновлениях не подменяется, поэтому обработчик переживает любые перерисовки корзины.
Базовый шаблон подписки выглядит так:
jQuery( document.body ).on( 'added_to_cart', function () {
// код, который выполнится после добавления товара в корзину
} );
Обратите внимание на две детали. Во-первых, слушать нужно именно document.body — попытка навесить обработчик на саму кнопку сработает один раз и перестанет после первого же обновления фрагментов. Во-вторых, в WordPress используется jQuery, а не короткий $: сокращённый алиас по умолчанию отключён.
Событие added_to_cart и его данные
Самое востребованное событие — добавление товара в корзину. Оно приходит с четырьмя аргументами: объектом события, фрагментами разметки для обновления, хешем корзины и ссылкой на кнопку, по которой кликнули. Именно из кнопки удобнее всего доставать данные о товаре:
( function ( $ ) {
$( document.body ).on( 'added_to_cart', function ( event, fragments, cart_hash, button ) {
var product_id = button.data( 'product_id' ), // идентификатор товара
product_qty = button.data( 'quantity' ), // количество
product_sku = button.data( 'product_sku' ), // артикул
product_name = button.data( 'product_name' ), // название
product_price = button.data( 'product_price' ), // цена
currency = button.data( 'currency' ); // валюта
// Пример: отправляем событие в аналитику через dataLayer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push( {
event: 'add_to_cart',
item_id: product_id,
item_name: product_name,
quantity: product_qty,
price: product_price,
currency: currency
} );
// Для отладки: посмотреть все доступные данные кнопки
console.log( button.data() );
} );
} )( jQuery );
Строка с console.log( button.data() ) — самый быстрый способ понять, что вообще доступно в конкретной теме: набор атрибутов зависит от шаблона кнопки и установленных плагинов. Посмотрели в консоли, забрали нужное, строку удалили.
Отправлять данные можно куда угодно — в dataLayer для Google Tag Manager, в Яндекс.Метрику через ym() или в собственный эндпоинт. Принцип один: событие даёт вам момент и данные, дальше решаете вы.
Полный список событий
Ниже — события, сгруппированные по месту, где они возникают. Все слушаются на document.body, если не указано иное.
Добавление товара и фрагменты корзины
adding_to_cart | сразу после клика по кнопке, до ответа сервера. Аргументы: кнопка, данные запроса |
added_to_cart | товар добавлен. Аргументы: фрагменты, хеш корзины, кнопка |
removed_from_cart | товар удалён. Аргументы те же |
wc_cart_button_updated | кнопка добавления обновлена. Аргумент: кнопка |
wc_fragment_refresh | фрагменты нужно обновить |
wc_fragments_loaded | фрагменты загружены (например, мини-корзина) |
wc_fragments_refreshed | фрагменты обновлены |
Страница корзины
updated_wc_div | блок корзины перерисован |
updated_cart_totals | итоги корзины пересчитаны |
cart_totals_refreshed | итоги обновлены |
cart_page_refreshed | страница корзины обновлена |
wc_cart_emptied | корзина опустошена |
applied_coupon | купон применён. Аргумент: код купона |
removed_coupon | купон снят. Аргумент: купон |
updated_shipping_method | изменён способ доставки |
country_to_state_changed | изменена страна, перестроен список регионов |
Оформление заказа
init_checkout | пользователь открыл страницу оформления |
update_checkout | чекаут нужно пересчитать |
updated_checkout | чекаут пересчитан — момент, когда безопасно трогать разметку |
checkout_error | при оформлении возникла ошибка |
payment_method_selected | выбран способ оплаты |
applied_coupon_in_checkout | купон применён на чекауте |
removed_coupon_in_checkout | купон снят на чекауте |
Карточка товара
found_variation | выбрана вариация товара. Аргумент: объект вариации |
Важно: блочные корзина и чекаут
Это главное, что изменилось за последние годы и о чём молчит большинство старых подборок. В современных версиях WooCommerce корзина и оформление заказа собираются на блоках, а не на классических шорткодах. Блоки построены на React и не используют jQuery, поэтому привычные события чекаута там попросту не приходят.
Вместо них блоки рассылают нативные DOM-события с префиксом wc-blocks_:
document.body.addEventListener( 'wc-blocks_added_to_cart', function ( event ) {
console.log( 'товар добавлен', event.detail );
} );
Документированы три таких события: wc-blocks_adding_to_cart — запрос на добавление отправлен, wc-blocks_added_to_cart — товар успешно добавлен, wc-blocks_removed_from_cart — товар удалён. Для совместимости WooCommerce переводит свои классические jQuery-события в нативные через внутреннюю функцию translatejQueryEventToNative(), поэтому базовые сценарии с добавлением товара продолжают работать в обоих мирах.
У события wc-blocks_added_to_cart есть параметр preserveCartData: он говорит блокам не перезапрашивать данные корзины, если код, вызвавший событие, уже их обновил. Мелочь, которая экономит лишний запрос.
Практический вывод простой. Перед тем как писать обработчик, посмотрите, на чём собран ваш чекаут. Если на шорткодах — работает весь список выше. Если на блоках — рассчитывайте на wc-blocks_*, а классические события чекаута проверяйте отдельно.
Куда положить код
Скрипт правильнее подключать отдельным файлом с явной зависимостью от jQuery, а не вставлять в подвал темы:
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_script(
'shop-events',
get_stylesheet_directory_uri() . '/js/shop-events.js',
array( 'jquery' ),
'1.0.0',
true
);
} );
Зависимость array( 'jquery' ) здесь обязательна: без неё файл может загрузиться раньше самой библиотеки, и обработчик молча не навесится.
Частые ошибки
Обработчик на элементе вместо body. Классика: код срабатывает один раз, а после первого Ajax-обновления перестаёт. Причина в том, что элемент, на который вешали обработчик, уже заменён новым.
Код выполняется до готовности WooCommerce. Если скрипт подключён без зависимости от jQuery или выполняется слишком рано, подписка не создастся. Ошибки в консоли при этом может не быть вовсе.
Двойное срабатывание. Если подписку создавать внутри обработчика другого события — например, внутри updated_checkout, — при каждом пересчёте будет добавляться ещё один обработчик. Через несколько обновлений код выполнится десяток раз. Подписывайтесь один раз при загрузке страницы.
Проверка не на том типе страницы. События корзины не приходят на чекауте и наоборот. Если событие «не работает», сначала убедитесь, что вы на той странице, где оно вообще возникает.
Коротко
События WooCommerce — это способ выполнить свой код в нужный момент работы магазина, не гадая, когда закончится Ajax-запрос. Достаточно запомнить три вещи: слушать document.body, брать данные из аргументов события, а не из DOM, и проверить, на чём собраны ваши корзина и чекаут — на шорткодах или на блоках. От последнего зависит, какой набор событий вам вообще доступен.
Частые вопросы
Скорее всего, он навешен на конкретный элемент. WooCommerce при Ajax-обновлении заменяет разметку, и старый элемент вместе с обработчиком исчезает. Подписывайтесь на document.body — он при обновлениях не подменяется.
Вероятно, у вас блочный чекаут. Блоки построены на React и не используют jQuery, поэтому классические события вроде updated_checkout там не приходят. Для блоков есть нативные события с префиксом wc-blocks_.
Выведите в консоль данные кнопки: console.log( button.data() ) внутри обработчика added_to_cart. Набор атрибутов зависит от темы и плагинов, поэтому проверять нужно на своём магазине.
Обычно потому, что подписка создаётся внутри другого обработчика — например, внутри updated_checkout. При каждом пересчёте добавляется ещё один обработчик. Подписывайтесь один раз при загрузке страницы.
Источники
- 1.DOM events — официальная документация разработчика WooCommercehttps://developer.woocommerce.com/docs/block-development/extensible-blocks/cart-and-checkout-blocks/dom-events/
- 2.WooCommerce jQuery Events — справочник событийhttps://amirhp-com.github.io/woocommerce-jquery-events/
- 3.WooCommerce JavaScript events — сводный списокhttps://gist.github.com/ValeriiVasyliev/acc2b80d9c55fd465093124de29b0512

