Диагностика задачи: зачем менять цены динамически в WooCommerce
В стандартной установке WooCommerce цена товара задается в админке и отображается статично. Но бывают случаи, когда нужно менять цену на лету — например, в зависимости от роли пользователя, количества товаров в корзине, текущих акций или даты. Для этого используют хуки WooCommerce, которые позволяют вмешиваться в процесс расчета цены без изменения данных в базе.
Какие хуки отвечают за изменение цены товара
В WooCommerce для модификации цены на уровне фронтенда и корзины применяются следующие фильтры:
woocommerce_product_get_price— возвращает цену товара для отображения на странице.woocommerce_product_get_regular_price— цена без скидок.woocommerce_product_get_sale_price— цена со скидкой.woocommerce_cart_item_price— цена товара в корзине.
Для изменения цены перед добавлением в корзину используется хук woocommerce_before_calculate_totals.
Пошаговое решение: динамическое изменение цены для определенной роли пользователя
Рассмотрим пример, где цена товара для пользователей с ролью premium_customer будет снижена на 15%.
add_action('woocommerce_before_calculate_totals', 'custom_dynamic_price_for_premium_role', 20, 1); function custom_dynamic_price_for_premium_role( $cart ) { if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return; // Проверяем роль пользователя if ( ! is_user_logged_in() ) return; $user = wp_get_current_user(); if ( in_array( 'premium_customer', (array) $user->roles ) ) { foreach ( $cart->get_cart() as $cart_item ) { $original_price = $cart_item['data']->get_regular_price(); $new_price = $original_price * 0.85; $cart_item['data']->set_price( $new_price ); } } }Этот код корректно изменит цену в корзине и на странице оформления заказа.
Изменение цены на странице товара
Чтобы отобразить измененную цену на странице товара, используйте фильтр woocommerce_get_price_html:
add_filter('woocommerce_get_price_html', 'display_discounted_price_for_premium', 100, 2); function display_discounted_price_for_premium( $price_html, $product ) { if ( ! is_user_logged_in() ) return $price_html; $user = wp_get_current_user(); if ( in_array( 'premium_customer', (array) $user->roles ) ) { $regular_price = $product->get_regular_price(); $discounted_price = $regular_price * 0.85; $price_html = wc_price( $discounted_price ); } return $price_html; }Проверка результата после внедрения
- Залогиньтесь под обычным пользователем — цены должны отображаться стандартно.
- Залогиньтесь под пользователем с ролью
premium_customer— цена должна быть ниже на 15% как на странице товара, так и в корзине. - Добавьте товар в корзину и проверьте итоговую сумму на странице оформления заказа.
- Очистите кэш (если есть) и отключите плагины кэширования для корректного теста.
Частые ошибки и как исправить
- Цена меняется в корзине, но не на странице товара: не реализован фильтр
woocommerce_get_price_html. - Изменение цены не сохраняется в заказах: нужно менять цену до расчёта итогов, используя
woocommerce_before_calculate_totals. - Динамическая цена влияет на админку или AJAX-запросы: используйте проверки
is_admin()иDOING_AJAX, чтобы ограничить применение кода только фронтендом. - Цена неправильная при использовании кеша страниц: отключите кэширование страниц для авторизованных пользователей или используйте фрагментный кэш.
Практические советы по производительности и безопасности
- Не выполняйте тяжелую логику в хуках, которые вызываются часто (например, в
woocommerce_before_calculate_totals), кешируйте расчёты при необходимости. - Проверяйте роль пользователя один раз за сессию, а не на каждый вызов, чтобы снизить нагрузку.
- Убедитесь, что динамическая цена не нарушает бизнес-логику — например, что скидка не применяется к товарам с уже действующими акциями.
- Обрабатывайте случаи, когда пользователь не авторизован — например, не меняйте цену или показывайте стандартную.
Сравнение способов изменения цены в WooCommerce
| Метод | Где применяется | Плюсы | Минусы |
|---|---|---|---|
Фильтры woocommerce_product_get_price и подобные | Отображение цены на сайте | Простая реализация, меняет только отображение | Не меняет цену в корзине и заказе |
Хук woocommerce_before_calculate_totals | Корзина, оформление заказа | Меняет фактическую цену товара в корзине | Не меняет цену на странице товара без дополнительных фильтров |
| Создание пользовательского типа скидок или купонов | Общая скидка | Гибкость, управление через админку | Более сложная реализация, не всегда подходит для динамических правил |