Использование хука woocommerce_before_calculate_totals для динамического изменения цен в корзине WooCommerce

Диагностика задачи: зачем менять цену товара в корзине WooCommerce

В WooCommerce иногда возникает потребность динамически изменять цену товара уже после добавления в корзину. Типичные сценарии: скидка на основе пользовательских условий, добавление наценки или замена цены в зависимости от дополнительных параметров. Стандартными средствами настроить это нельзя — цены берутся из базы и фиксируются при добавлении товара в корзину. Для решения данной задачи используется хук woocommerce_before_calculate_totals.

Как работает хук woocommerce_before_calculate_totals

Этот хук вызывается перед пересчётом итогов корзины и позволяет программно изменять цены товаров в сессии пользователя. Его главное преимущество — изменения применяются только в текущем сеансе и не влияют на базовые данные товара в каталоге.

Подробности:

  • Вызывается с объектом корзины WC_Cart;
  • Применяется к каждому элементу корзины WC_Cart_Item;
  • Позволяет менять цену с помощью метода set_price() у товара в корзине.

Пошаговое решение: пример кода для скидки 10% на все товары в корзине

add_action('woocommerce_before_calculate_totals', 'wp24_apply_custom_discount', 20, 1);
function wp24_apply_custom_discount( $cart ) {
    if ( is_admin() && ! defined('DOING_AJAX') ) {
        return;
    }

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
        return; // предотвращаем повторное применение
    }

    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $original_price = $cart_item['data']->get_regular_price();
        $discounted_price = $original_price * 0.9; // скидка 10%
        $cart_item['data']->set_price( $discounted_price );
    }
}

Обратите внимание на проверки is_admin() и did_action(), чтобы избежать конфликтов и повторного применения скидок.

Проверка результата после внедрения

  • Добавьте товар в корзину на фронтенде;
  • Перейдите в корзину и проверьте цену товара — она должна быть уменьшена на 10% от базовой;
  • В админке заказов цена товара останется без изменений, так как корректировка происходит только в сессии;
  • Для проверки можно временно вывести цену в лог: error_log('Discounted price: ' . $discounted_price);.

Частые ошибки и как их исправить

  • Изменение цены не применяется: вероятно, функция не подключена к нужному хуку или работает в админке. Проверьте наличие проверки is_admin() и при необходимости добавьте ! defined('DOING_AJAX') для исключения админских вызовов.
  • Скидка применяется несколько раз: используйте did_action('woocommerce_before_calculate_totals'), чтобы ограничить применение функции одним вызовом за цикл.
  • Цена меняется для всех пользователей, включая админов: добавьте условие if ( is_admin() && ! defined('DOING_AJAX') ) return;.
  • В корзине цены выглядят правильно, но в заказе — нет: помните, что изменение цены в корзине не влияет на цену в базе и заказах, если не сохранять эту информацию дополнительно (например, в метаполях заказа).

Практические советы по безопасности и производительности

  • Избегайте тяжелых вычислений внутри функции, так как хук вызывается при каждом обновлении корзины;
  • Кэшируйте результаты вычислений, если они зависят от внешних данных;
  • Не меняйте цену напрямую в базе данных товара — используйте только set_price() объекта корзины;
  • При необходимости сохранения цены в заказе используйте хук woocommerce_checkout_create_order_line_item для передачи кастомных цен;
  • При работе с большими магазинами проверяйте нагрузку на сервер и оптимизируйте код.

Сравнение способов изменения цен в WooCommerce

МетодПлюсыМинусыКомпромисс
Изменение цены товара в базе данныхПостоянное изменение ценыРиски ошибок, мешает обновлениямИспользовать только если цена действительно меняется навсегда
Хук woocommerce_before_calculate_totalsДинамическое изменение цен для сессииЦена не сохраняется в заказе по умолчаниюИспользовать вместе с сохранением метаданных заказа для точности
Плагины для скидок и ценообразованияГотовые решения с интерфейсомМогут быть тяжелыми и не всегда гибкимиХорошо для стандартных сценариев без кастомного кода
Как удалить пустое метаполе в WooCommerce с помощью кода
15.05.2026
Как избежать ошибок WooCommerce при массовом изменении цен продуктов
18.05.2026
Как сделать многоязычный сайт на WordPress без плагинов
16.04.2026
Как использовать хук woocommerce_checkout_update_order_review в WooCommerce
21.05.2026
Удаление неиспользуемых метаданных в WooCommerce без плагинов: пошаговое руководство
03.05.2026