Диагностика проблемы: почему стандартные скидки WooCommerce не всегда подходят
WooCommerce позволяет задавать скидки и цены через купоны и стандартные настройки товара, но в ряде случаев требуется более гибкое управление ценами на лету — например, для разных групп пользователей, регионов, объёмов заказа или специальных условий. Без правильных хуков изменить цену товара динамически сложно, а попытки напрямую менять метаполя цены приводят к ошибкам кэширования и некорректному подсчету стоимости в корзине.
Какие хуки WooCommerce использовать для изменения цены товара
Для динамического изменения цены используются фильтры, которые позволяют задать новую стоимость до отображения и расчёта заказа:
woocommerce_product_get_price— изменяет цену товара при получении (вывод на странице товара, категории и т.п.)woocommerce_product_get_regular_price— для регулярной ценыwoocommerce_product_get_sale_price— для цены со скидкойwoocommerce_before_calculate_totals— позволяет изменить цену товара в объекте корзины перед подсчетом итогов
Использование всех этих хуков вместе обеспечивает корректное отображение и подсчет цены в разных частях сайта и фронтенда.
Пошаговое решение: пример динамического изменения цены для группы пользователей
Допустим, нужно сделать скидку 10% для пользователей с ролью «оптовик».
add_filter('woocommerce_product_get_price', 'custom_dynamic_price', 10, 2);
add_filter('woocommerce_product_get_regular_price', 'custom_dynamic_price', 10, 2);
add_filter('woocommerce_product_get_sale_price', 'custom_dynamic_price', 10, 2);
function custom_dynamic_price($price, $product) {
if (is_admin()) return $price; // не менять в админке
if (is_user_logged_in()) {
$user = wp_get_current_user();
if (in_array('wholesaler', (array) $user->roles)) {
return $price * 0.9; // скидка 10%
}
}
return $price;
}
add_action('woocommerce_before_calculate_totals', 'custom_cart_item_price', 20, 1);
function custom_cart_item_price($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
if (is_user_logged_in()) {
$user = wp_get_current_user();
if (in_array('wholesaler', (array) $user->roles)) {
foreach ($cart->get_cart() as $cart_item) {
$original_price = $cart_item['data']->get_price();
$discounted_price = $original_price * 0.9;
$cart_item['data']->set_price($discounted_price);
}
}
}
}Объяснение кода
Фильтры меняют цену на фронтенде (каталог, страница товара), а хук woocommerce_before_calculate_totals меняет цену товара непосредственно в корзине, чтобы учесть скидку при расчёте итогов.
Проверка результата после внедрения
- Войти на сайт под пользователем с ролью «оптовик» (если такой роли нет, создайте через
add_roleили вручную в базе). - Открыть страницу товара и проверить цену — она должна быть на 10% ниже обычной.
- Добавить товар в корзину и перейти к оформлению заказа — итоговая стоимость должна также содержать скидку.
- Выйти из учётной записи или войти под обычным пользователем — цена должна отображаться без скидки.
Частые ошибки и как их исправить
- Изменения не применяются в корзине — часто забывают хук
woocommerce_before_calculate_totals, который меняет цену в объекте корзины. - Цена не меняется на странице товара — нужно использовать фильтры
woocommerce_product_get_priceи аналогичные, чтобы менять цену на фронтенде. - Изменения влияют на админку — добавляйте проверку
is_admin()иDOING_AJAX, чтобы не менять цену в админке. - Формат цены ломается — всегда возвращайте число с плавающей точкой, не строку с символами.
Практические советы по безопасности и производительности
- Кэширование: При использовании динамических цен отключите кэширование страниц для таких пользователей или исключите страницы корзины и оформления заказа из кэша.
- Оптимизация проверок: Храните роль пользователя в переменную, не делайте лишних вызовов
wp_get_current_user(). - Минимизируйте количество вызовов фильтров: Если скидка зависит от сложных условий (базы данных, API), кешируйте результат в сессионных данных или transient.
Сравнение вариантов реализации динамических цен
| Вариант | Плюсы | Минусы |
|---|---|---|
| Использование хуков (код) | Гибкость, контроль, не требует плагинов | Требует навыков, возможны ошибки при неправильном коде |
| Плагины для динамических цен (например, WooCommerce Dynamic Pricing) | Простота настройки, готовые условия и интерфейс | Стоимость, нагрузка, возможные конфликты |
| Использование купонов | Простота, встроено в WooCommerce | Меньше гибкости, не всегда подходит для сложных условий |