Диагностика задачи: когда и зачем менять цену товара динамически
В WooCommerce нередко требуется менять цену товара на лету — например, в зависимости от роли пользователя, количества в корзине, даты или внешних условий. Стандартные настройки WooCommerce не позволяют гибко менять цены, поэтому разработчики используют хуки для изменения цены программно.
Основная проблема — понять, какой именно хук использовать, и как правильно изменить цену без конфликтов с кэшированием и другими плагинами.
Выбор правильных хуков для динамического изменения цены
Для изменения цены товара в WooCommerce чаще всего используются фильтры:
woocommerce_product_get_price— возвращает цену для продукта;woocommerce_product_get_regular_price— цена без скидки;woocommerce_product_get_sale_price— цена со скидкой;woocommerce_get_price_html— позволяет изменить HTML вывода цены;woocommerce_cart_item_price— цена товара в корзине.
Для динамического изменения цены в корзине и на странице оформления заказа применяют фильтры, связанные с объектами корзины, например woocommerce_before_calculate_totals.
Пошаговое решение: пример динамического изменения цены по роли пользователя
Задача: скидка 10% для пользователей с ролью "subscriber" на все товары.
add_action('woocommerce_before_calculate_totals', 'custom_dynamic_price_by_user_role', 10, 1);
function custom_dynamic_price_by_user_role( $cart ) {
if ( is_admin() && ! defined('DOING_AJAX') ) return;
if ( did_action('woocommerce_before_calculate_totals') >= 2 ) return;
$user = wp_get_current_user();
if ( in_array('subscriber', (array) $user->roles) ) {
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 );
}
}
}
Этот код проверяет роль пользователя при расчете корзины и меняет цену каждого товара на 90% от регулярной.
Изменение цены на странице товара
Чтобы цена отображалась измененной и на странице товара, можно использовать фильтр woocommerce_product_get_price:
add_filter('woocommerce_product_get_price', 'custom_dynamic_price_display', 10, 2);
function custom_dynamic_price_display( $price, $product ) {
$user = wp_get_current_user();
if ( in_array('subscriber', (array) $user->roles) ) {
return $price * 0.9; // 10% скидка
}
return $price;
}
Проверка результата после внедрения
- Залогиньтесь под пользователем с ролью "subscriber" и проверьте цену товара на странице товара и в корзине — она должна быть на 10% ниже.
- Залогиньтесь под другим пользователем или гостем — цена должна оставаться без изменений.
- Очистите кэш сайта и браузера, чтобы убедиться, что изменения видны.
- Проверьте, что на странице оформления заказа и в письмах цена соответствует измененной.
Частые ошибки и как их исправить
- Цена не меняется на странице товара: возможно, используется кэширование или фильтр применяется некорректно. Проверьте, что код подключен в functions.php или плагине и что нет конфликтов с другими плагинами кэширования.
- Цена меняется, но в корзине и на странице оформления заказа не обновляется: убедитесь, что используется
woocommerce_before_calculate_totalsи что функция не вызывается дважды (смотрите проверкуdid_action). - Ошибка "Cannot modify header information": проверьте, что в файлах нет лишних пробелов или пустых строк до
<?phpили после?>. - Изменение цены влияет на отчеты и заказы некорректно: помните, что динамическое изменение цены — только для отображения и расчета в корзине. Для изменения данных заказа нужно использовать хуки при сохранении заказа.
Практические советы по безопасности и производительности
- Не используйте динамическое изменение цены для важных финансовых данных без логирования — это может запутать владельца магазина.
- Всегда проверяйте пользовательскую роль через
wp_get_current_user(), а не через глобальные переменные. - Избегайте тяжелых операций внутри хука
woocommerce_before_calculate_totals, чтобы не замедлять процесс оформления заказа. - Тестируйте изменения на тестовой среде и с отключенным кэшем, чтобы избежать ложных срабатываний.
Сравнение способов реализации динамического изменения цены
| Метод | Преимущества | Недостатки |
|---|---|---|
Фильтр woocommerce_product_get_price | Изменяет цену на странице товара и везде, где берется цена | Не влияет на цену в корзине по умолчанию, требуется дополнительный код |
Хук woocommerce_before_calculate_totals | Изменяет цену в корзине и на этапе оформления заказа | Не меняет цену на странице товара без дополнительных фильтров |
| Изменение цены через метаданные товара | Сохраняется в базе, работает во всех местах | Требует модификации товара, не подходит для временных скидок |