Диагностика проблемы: почему стандартный промокод не меняет цену товара динамически
В WooCommerce стандартные промокоды применяют скидку к общей сумме корзины, но не изменяют цену отдельного товара в списке товаров или на странице товара. Это ограничение мешает отображать корректную цену с учетом скидки и усложняет кастомизацию для бизнес-логики, требующей динамического изменения цены именно товара при вводе промокода.
Проверить, что происходит именно эта проблема, можно так:
- Примените промокод в корзине;
- Обратите внимание на цену товара в списке — она не меняется;
- Общая сумма корзины корректно пересчитывается со скидкой;
- Цена в виджетах товара и на страницах товаров остаётся без скидки.
Пошаговое решение: динамическое изменение цены товара при использовании промокода
1. Используем хук woocommerce_before_calculate_totals
Для изменения цены товара в корзине нам нужно перехватить расчет итогов корзины и изменить цену товара, если активен нужный промокод.
add_action('woocommerce_before_calculate_totals', 'custom_change_price_on_coupon', 20, 1);
function custom_change_price_on_coupon( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Проверяем, что корзина существует
if ( ! $cart || empty( $cart->get_cart() ) ) {
return;
}
// Проверяем наличие конкретного промокода
$target_coupon = 'specialdiscount'; // замените на ваш промокод
$applied_coupons = $cart->get_applied_coupons();
if ( ! in_array( $target_coupon, $applied_coupons ) ) {
return;
}
// Цикл по товарам в корзине
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Пример: для товара с ID 123 меняем цену
if ( $cart_item['product_id'] == 123 ) {
$original_price = $cart_item['data']->get_price();
$new_price = $original_price * 0.8; // скидка 20%
$cart_item['data']->set_price( $new_price );
}
}
}2. Добавляем проверку на AJAX и админку
Чтобы избежать нежелательных изменений цены в админке и при других запросах, мы добавили проверку is_admin() && ! defined( 'DOING_AJAX' ). Это стандартная практика для таких хуков.
3. Подключаем код в файл functions.php вашей темы или в кастомный плагин
Рекомендуется использовать дочернюю тему или собственный плагин, чтобы не потерять изменения при обновлении.
Проверка результата после внедрения
- Очистите кеш браузера и кеш сайта, если он используется.
- Добавьте в корзину товар с ID, указанным в коде (в примере 123).
- Примените промокод
specialdiscount. - Проверьте, что цена товара в корзине изменилась на 20% ниже исходной.
- Переходите на страницу оформления заказа и убедитесь, что итоговая сумма корректна.
Частые ошибки и как их исправить
- Промокод не применяется к цене товара: Проверьте, правильно ли указано имя промокода в переменной
$target_couponи совпадает ли регистр. - Цена меняется для всех товаров: Убедитесь, что условие
$cart_item['product_id'] == 123ограничивает применение скидки только к нужному товару. - Цена не обновляется при AJAX обновлении корзины: Проверьте, что хук
woocommerce_before_calculate_totalsподключен с приоритетом 20 или выше, и нет конфликтов с другими плагинами. - Цена меняется в админке: Добавьте проверку
is_admin() && ! defined('DOING_AJAX')для исключения админ-запросов.
Практические советы по безопасности и производительности
- Не меняйте цену товара глобально — только в корзине, чтобы не влиять на данные в базе и не создавать рассинхронизацию.
- Используйте кеширование с осторожностью: динамическая цена зависит от промокода, поэтому кеш страниц с корзиной должен быть отключен или использоваться с вариациями для разных пользователей.
- Проверяйте совместимость с другими плагинами, которые могут влиять на цену, например, плагины скидок или кэширования.
- Для сложных условий лучше использовать кастомные поля или метаданные продуктов, чтобы не хардкодить ID в коде.
Сравнение способов изменения цены товара при промокодах
| Метод | Преимущества | Недостатки | Пример |
|---|---|---|---|
Хук woocommerce_before_calculate_totals | Гибкий, без плагинов, точечное изменение цены в корзине | Требует навыков PHP, влияет только на корзину | Пример из статьи |
| Плагины скидок (например, WooCommerce Dynamic Pricing) | Удобный интерфейс, управление скидками без кода | Может влиять на производительность, лицензии | Clearfy Pro позволяет оптимизировать сайт, но не меняет цены напрямую |
| JS-решения на клиенте | Быстрая визуальная корректировка цены | Цена не меняется на сервере, риск рассинхронизации | Не рекомендуется для финальных расчетов |