Что делает хук woocommerce_before_calculate_totals и зачем он нужен
Этот хук вызывается перед подсчетом общей суммы корзины в WooCommerce. Он позволяет программно изменить цены товаров в корзине до применения всех остальных расчетов, включая налоги и скидки. Чаще всего его используют для динамического изменения стоимости товаров в зависимости от условий — например, для акций, скидок, изменений цен по пользователям или по времени.
Диагностика: почему не меняются цены через этот хук
Если вы пытаетесь изменить цены товаров через woocommerce_before_calculate_totals, но в корзине цена не меняется, проверьте следующие моменты:
- Вы изменяете цену именно в объекте
$cart_item['data'], а не в копии. - Изменения делаете при каждой загрузке, а не только один раз — иначе корзина может не обновиться.
- Нет конфликтов с другими плагинами, которые могут переопределять цены после вашего хука.
- Вы не кэшируете страницы с корзиной или кэш очищается при изменении корзины.
Пошаговое решение: пример кода для динамического снижения цены на 10%
Добавьте следующий код в functions.php вашей темы или в кастомный плагин:
add_action('woocommerce_before_calculate_totals', 'custom_dynamic_price_adjustment', 20, 1);
function custom_dynamic_price_adjustment( $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 ) {
$product = $cart_item['data'];
$original_price = $product->get_regular_price();
$new_price = $original_price * 0.9; // Снижение на 10%
$product->set_price( $new_price );
}
}Объяснение:
- Проверяем, что код не срабатывает в админке вне AJAX.
- Избегаем повторного применения изменения цен.
- Идем по всем товарам в корзине и уменьшаем цену на 10% от регулярной цены.
Как изменить цену только для определённой категории товаров
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
if ( has_term( 'sale-category', 'product_cat', $product->get_id() ) ) {
$original_price = $product->get_regular_price();
$new_price = $original_price * 0.85; // 15% скидка на категорию
$product->set_price( $new_price );
}
}Проверка результата: как убедиться, что цены изменились
- Добавьте в корзину товары, подходящие под условия.
- Перейдите на страницу корзины — цены должны измениться на указанный процент.
- Используйте инструменты разработчика браузера, чтобы проверить итоговую цену товара в DOM.
- Включите режим отладки WooCommerce
define( 'WP_DEBUG', true );и посмотрите, нет ли ошибок.
Частые ошибки при использовании woocommerce_before_calculate_totals
- Изменение цены не на объекте продукта: нужно менять цену через
$cart_item['data']->set_price(), иначе изменения не применятся. - Повторное срабатывание хука: если не ограничить вызов, цена может уменьшаться много раз, что приведет к неверным итогам.
- Изменение цены в админке без AJAX: это может испортить данные при редактировании заказа.
- Кэширование страницы корзины: если включено кэширование, изменения могут не отражаться. Рекомендуется исключить страницу корзины из кэша.
Практические советы по безопасности и производительности
- Избегайте тяжелых запросов и сложных вычислений в этом хуке — он вызывается при каждой загрузке корзины.
- Кэшируйте результаты, если делаете запросы к базе или внешним API.
- Используйте проверки
is_admin()иDOING_AJAX, чтобы не менять цены в админке без необходимости. - При необходимости используйте пользовательские мета-поля для хранения условий скидок, чтобы не захламлять код.
Сравнение способов изменения цены в WooCommerce
| Метод | Плюсы | Минусы | Когда применять |
|---|---|---|---|
Хук woocommerce_before_calculate_totals | Гибкий, позволяет менять цену динамически, работает с корзиной | Требует аккуратности, возможны баги при неправильном использовании | Динамические скидки, акции, специальные цены |
| Использование плагинов скидок | Простота настройки, готовые решения | Может быть тяжёлым, ограниченная кастомизация | Стандартные скидки без кастома |
| Изменение цены в базе или через meta поля | Постоянное изменение цены товара | Менее гибко, влияет на все заказы | Если цена должна меняться для всех покупателей |