Что такое хук woocommerce_before_calculate_totals и зачем он нужен
В WooCommerce хук woocommerce_before_calculate_totals вызывается перед подсчётом итоговой стоимости корзины. С помощью этого хука можно программно изменить цену товаров, добавить скидки, наценки или динамически корректировать стоимость в зависимости от условий. Это особенно полезно, когда стандартные купоны или скидки WooCommerce не подходят под бизнес-логику.
Диагностика задачи: когда нужно менять цены в корзине через этот хук
Типичные сценарии использования:
- Изменение цены товара в зависимости от роли пользователя.
- Добавление скидок на определённые категории товаров.
- Применение динамических наценок или скидок, основанных на пользовательских метаполях.
- Учет дополнительных параметров, переданных через форму на странице товара.
Если вы пробовали менять цену товара в корзине через woocommerce_cart_item_price или woocommerce_get_price, но итоговая сумма не меняется — вероятно, вы не используете woocommerce_before_calculate_totals, который именно отвечает за обновление цен перед расчетом.
Пошаговое решение: пример изменения цены для определенной роли пользователя
Рассмотрим пример, когда для пользователей с ролью subscriber нужно сделать скидку 10% на все товары в корзине.
add_action('woocommerce_before_calculate_totals', 'custom_discount_for_subscribers', 10, 1);
function custom_discount_for_subscribers($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
if (did_action('woocommerce_before_calculate_totals') >= 2) return;
if (current_user_can('subscriber')) {
foreach ($cart->get_cart() as $cart_item) {
$original_price = $cart_item['data']->get_regular_price();
$discounted_price = $original_price * 0.9; // скидка 10%
$cart_item['data']->set_price($discounted_price);
}
}
}
Объяснение:
- Проверяем, что действие не выполняется в админке и не дважды подряд.
- Проверяем роль пользователя через
current_user_can(). - Проходимся по всем товарам в корзине и устанавливаем новую цену через
set_price().
Как проверить, что решение сработало
- Залогиньтесь под пользователем с ролью
subscriber. - Добавьте в корзину товары.
- Перейдите в корзину и убедитесь, что цены уменьшились ровно на 10%.
- Залогиньтесь под другим пользователем без роли
subscriberи проверьте, что цены не изменились.
Для дополнительной проверки можно временно включить вывод цены в консоль, добавив error_log('Цена товара: '.$cart_item['data']->get_price()); внутри цикла.
Частые ошибки при использовании woocommerce_before_calculate_totals
- Изменение цены вне хука: попытка изменить цену в других хуках, где итоговая сумма уже посчитана, не даст эффекта.
- Двойной вызов: неиспользование
did_actionприводит к бесконечным циклам и ошибкам. - Изменение цены в админке: без проверки
is_adminможно сломать работу админ-панели. - Неправильное получение цены: использование
get_price()вместоget_regular_price()может привести к неверным расчетам.
Практические советы по производительности и безопасности
- Всегда проверяйте роль или условия, чтобы не выполнять ненужные операции на каждом обновлении корзины.
- Избегайте тяжелых запросов и сложной логики внутри хука, так как это может замедлить процесс подсчета корзины.
- Внимательно тестируйте работу на разных типах товаров (простой, вариативный, с акциями).
- Используйте
did_actionдля предотвращения рекурсий.
Сравнение способов изменения цены в WooCommerce
| Метод | Где применяется | Плюсы | Минусы |
|---|---|---|---|
Хук woocommerce_before_calculate_totals | Изменение цены перед расчетом корзины | Надежно меняет итоговую цену, работает с любыми товарами | Требует правильной реализации, чтобы избежать рекурсий |
Фильтр woocommerce_get_price | Вывод цены товара | Позволяет менять цену на фронтенде | Не меняет итоговую сумму в корзине |
| Плагины скидок | Готовые решения для скидок | Просты в использовании, много опций | Могут быть тяжелыми, не всегда гибкие |