Диагностика проблемы с пересчетом стоимости в WooCommerce
В стандартной работе WooCommerce при каждом обновлении корзины происходит автоматический пересчет стоимости товаров. Это мешает, если нужно динамически изменить цену товара в корзине (например, добавить скидку или наценку), но при этом сохранить остальной функционал без вызова повторного пересчета или конфликта с другими плагинами.
Типичные симптомы:
- Изменения цены не сохраняются после обновления страницы корзины;
- Автоматический пересчет сбрасывает вашу модификацию;
- Ошибки в логах или некорректное отображение итоговой суммы.
Пошаговое решение: изменение цены товара в корзине без пересчета
1. Использование хука woocommerce_before_calculate_totals
Для корректной и безопасной модификации стоимости товаров в корзине нужно использовать хук woocommerce_before_calculate_totals. Он вызывается перед подсчетом итогов и позволяет изменить цену «на лету».
Основной момент — не менять стоимость напрямую в метаданных товара, а только в объекте корзины WC_Cart.
add_action('woocommerce_before_calculate_totals', 'custom_change_cart_item_price', 20, 1);
function custom_change_cart_item_price($cart_object) {
if (is_admin() && !defined('DOING_AJAX')) return;
foreach ($cart_object->get_cart() as $cart_item_key => $cart_item) {
// Пример: уменьшаем цену на 10% для товара с ID 123
if ($cart_item['product_id'] === 123) {
$original_price = $cart_item['data']->get_price();
$new_price = $original_price * 0.9;
$cart_item['data']->set_price($new_price);
}
}
}2. Обеспечиваем стабильность изменения
Важно, чтобы цена изменялась только один раз и не накладывалась повторно при каждом вызове — иначе итог может стать некорректным. Для этого можно добавить проверку метки в объект товара.
add_action('woocommerce_before_calculate_totals', 'custom_change_cart_item_price_once', 20, 1);
function custom_change_cart_item_price_once($cart_object) {
if (is_admin() && !defined('DOING_AJAX')) return;
foreach ($cart_object->get_cart() as $cart_item_key => $cart_item) {
if (isset($cart_item['custom_price_applied'])) continue;
if ($cart_item['product_id'] === 123) {
$original_price = $cart_item['data']->get_price();
$new_price = $original_price * 0.9;
$cart_item['data']->set_price($new_price);
$cart_item['custom_price_applied'] = true;
}
}
}Как проверить, что решение сработало
- Добавьте в корзину товар с ID 123;
- Откройте страницу корзины — цена товара должна быть уменьшена на 10%;
- Обновите страницу — цена должна остаться изменённой, не вернуться к оригинальной;
- Проверьте итоговую сумму заказа — она должна правильно отражать новые цены;
- Если включен кэш, очистите его и проверьте повторно.
Частые ошибки и их исправление
- Ошибка: Цена меняется на странице корзины, но возвращается к старой после обновления.
Причина: изменение цены происходит вне хука или не учитывается повторный вызов.
Исправление: использоватьwoocommerce_before_calculate_totalsс проверкой флага изменения. - Ошибка: Конфликты с другими плагинами, меняющими цены.
Причина: хук вызывается в неправильном приоритете.
Исправление: изменить приоритет вызова (например, 20 или выше) для правильного порядка. - Ошибка: Изменения не применяются при AJAX обновлении корзины.
Причина: проверкаis_admin()или некорректные условия.
Исправление: убедиться, что код не блокируется при AJAX-запросах.
Практические советы по производительности и безопасности
- Не меняйте цену в базе или метаданных товара — используйте только временное изменение в объекте корзины.
- Проверяйте условия, чтобы не применять изменения ко всем товарам без необходимости.
- Используйте кэширование и очистку кэша, если применяете динамические скидки, чтобы избежать рассинхронизации.
- Тестируйте изменения на тестовом стенде перед внедрением в продакшн.
Сравнение способов изменения цены в корзине
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
| Изменение метаданных товара | Менять цену в базе или через метаполя | Постоянное изменение | Нарушает логику WooCommerce, сбрасывается при обновлении |
Хук woocommerce_before_calculate_totals | Изменение цены в объекте корзины | Безопасно, временно, совместимо с ядром и плагинами | Требует правильной реализации и проверки |
| Использование плагинов для скидок | Готовые решения для динамических изменений цены | Просто внедрять, много функций | Может быть избыточным, влияет на производительность |