Диагностика задачи: зачем менять товары в корзине динамически
В стандартном WooCommerce корзина обновляется только при добавлении или удалении товара вручную пользователем. Однако часто возникает необходимость динамически менять содержимое корзины — например, добавлять бесплатный подарок при покупке определённого товара, автоматически менять количество или заменять товар на акционный аналог.
Без правильного использования хуков попытки изменить корзину могут привести к ошибкам, дублированию или некорректному отображению данных.
Какие хуки WooCommerce отвечают за изменение корзины
Для динамических изменений в корзине используются следующие основные хуки:
woocommerce_before_calculate_totals— вызывается перед пересчетом стоимости корзины, идеально подходит для изменения цены или количества товаров.woocommerce_cart_loaded_from_session— срабатывает после загрузки корзины из сессии, полезно для проверки и корректировки содержимого.woocommerce_add_to_cartиwoocommerce_remove_cart_item— для действий при добавлении и удалении товаров.
Пошаговое решение: добавление бесплатного подарка при покупке определённого товара
Задача: при добавлении в корзину товара с ID 123 автоматически добавлять в корзину бесплатный товар с ID 456, если его там ещё нет.
1. Проверяем наличие подарка и товара-активации
function add_free_gift_to_cart() {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$gift_product_id = 456;
$trigger_product_id = 123;
$found_trigger = false;
$found_gift = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( $cart_item['product_id'] == $trigger_product_id ) {
$found_trigger = true;
}
if ( $cart_item['product_id'] == $gift_product_id ) {
$found_gift = true;
}
}
if ( $found_trigger && ! $found_gift ) {
WC()->cart->add_to_cart( $gift_product_id );
}
if ( ! $found_trigger && $found_gift ) {
// Удаляем подарок, если товар-триггер удалён
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( $cart_item['product_id'] == $gift_product_id ) {
WC()->cart->remove_cart_item( $cart_item_key );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'add_free_gift_to_cart' );2. Обеспечиваем бесплатность подарка
function make_gift_free( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$gift_product_id = 456;
foreach ( $cart_object->get_cart() as $cart_item ) {
if ( $cart_item['product_id'] == $gift_product_id ) {
$cart_item['data']->set_price( 0 );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'make_gift_free', 20 );Как проверить, что решение работает
- Добавьте в корзину товар с ID 123 (можно использовать ссылку
/product/slug/?add-to-cart=123). - Перейдите в корзину и убедитесь, что автоматом добавился товар с ID 456 с ценой 0.
- Удалите товар с ID 123 из корзины — товар 456 должен автоматически исчезнуть.
- Обновите страницу корзины, проверьте, что состояние сохраняется.
Частые ошибки и их исправление
- Подарок добавляется несколько раз
Причина: не проверяется наличие подарка перед добавлением. Решение — всегда проверять флаг$found_gift. - Подарок не исчезает после удаления основного товара
Причина: не реализована логика удаления подарка при отсутствии триггера. Решение — добавить удаление подарка, как показано выше. - Изменения не сохраняются после обновления корзины
Причина: изменение цены и добавление товара должны происходить на хуках, вызывающихся до пересчёта корзины. - Ошибки при ajax-обновлении корзины
Решение: добавить проверки наis_admin()иDOING_AJAXдля исключения выполнения в админке.
Практические советы по оптимизации и безопасности
- Используйте минимальное количество операций в хук
woocommerce_before_calculate_totals, так как он вызывается часто. - Для сложных условий применяйте кеширование результатов проверки наличия товаров в корзине.
- Не изменяйте глобальные переменные напрямую, используйте методы WC_Cart.
- Проверяйте ошибки при добавлении товаров в корзину, чтобы избежать сбоев.
- Обязательно тестируйте на разных версиях WooCommerce и с включёнными плагинами кэширования.
Сравнение вариантов реализации
| Метод | Плюсы | Минусы |
|---|---|---|
Добавление подарка через woocommerce_before_calculate_totals | Прямой контроль, можно менять цену | Нужно аккуратно проверять условия, возможны дубли |
| Использование плагинов "подарков" (например, WooCommerce Gift Plugin) | Готовые функции, удобный интерфейс | Часто платные, могут конфликтовать с темой |
| JS-скрипты для динамического добавления в корзину | Быстрая реализация на фронтенде | Не надёжно, легко обойти, не влияет на серверные расчёты |