Диагностика задачи: зачем менять цену товара динамически
В WooCommerce часто возникает задача изменять цену товара в зависимости от контекста — например, на странице категорий показывать скидку, а на странице товара — другую цену, или же менять цену в корзине в зависимости от количества или роли пользователя. Стандартных настроек WooCommerce для таких сценариев нет, поэтому приходится использовать код.
Типичные симптомы, что нужна динамическая корректировка цены:
- Цена на странице товара отличается от цены в списке товаров;
- Необходима скидка для определенных пользователей или ролей только на определенных страницах;
- Хочется показывать специальные цены во время акций только на странице категории, не меняя цену в карточке товара;
- Нужно менять цену в корзине под условия (например, при заказе от определенной суммы или количества).
Обзор подходов к изменению цены по условиям
Варианты реализации
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
Использование фильтра woocommerce_product_get_price | Изменение цены на уровне объекта товара при вызове | Гибко, работает во всех местах, где цена запрашивается | Необходимо учитывать условия, чтобы не изменить цену везде одинаково |
Изменение цены в корзине через woocommerce_before_calculate_totals | Коррекция цены только в корзине и на кассе | Чётко воздействует на итоговую сумму заказа | Не влияет на вывод цены на страницах товаров и каталога |
| Использование JavaScript для замены цены на фронтенде | Динамическая подмена цены без изменения данных на сервере | Быстро реализуется, не затрагивает сервер | Цена не меняется в заказе, только визуально; можно обойти |
Пошаговое решение: динамическое изменение цены по условиям страниц
1. Изменяем цену на основе типа страницы
Для примера изменим цену товара на странице категории и на странице товара по-разному.
add_filter('woocommerce_product_get_price', 'custom_dynamic_price_by_page', 10, 2);
add_filter('woocommerce_product_get_regular_price', 'custom_dynamic_price_by_page', 10, 2);
function custom_dynamic_price_by_page($price, $product) {
if (is_admin()) return $price; // Не трогаем админку
if (is_product_category()) {
// Например, скидка 10% на странице категории
$price = $price * 0.9;
} elseif (is_product()) {
// На странице товара скидка 5%
$price = $price * 0.95;
}
return $price;
}
2. Корректируем цену в корзине и на странице оформления заказа
Чтобы цена в корзине соответствовала изменённой цене, нужно использовать хук woocommerce_before_calculate_totals.
add_action('woocommerce_before_calculate_totals', 'custom_dynamic_cart_price', 20, 1);
function custom_dynamic_cart_price($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$price = $product->get_price();
// Здесь можно повторить логику из фильтра цены или вынести в отдельную функцию
if (current_user_can('wholesale_customer')) {
// Допустим, дополнительная скидка для оптовиков
$price = $price * 0.85;
}
$cart_item['data']->set_price($price);
}
}
3. Вынос логики в отдельную функцию для удобства
Чтобы не дублировать код, создадим функцию, которая рассчитывает цену по условиям, и используем её в фильтрах и в корзине.
function get_dynamic_price_for_product($product) {
$price = $product->get_regular_price();
if (is_product_category()) {
$price *= 0.9;
} elseif (is_product()) {
$price *= 0.95;
}
if (current_user_can('wholesale_customer')) {
$price *= 0.85;
}
return $price;
}
add_filter('woocommerce_product_get_price', function($price, $product) {
if (is_admin()) return $price;
return get_dynamic_price_for_product($product);
}, 10, 2);
add_filter('woocommerce_product_get_regular_price', function($price, $product) {
if (is_admin()) return $price;
return get_dynamic_price_for_product($product);
}, 10, 2);
add_action('woocommerce_before_calculate_totals', function($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$price = get_dynamic_price_for_product($cart_item['data']);
$cart_item['data']->set_price($price);
}
});
Проверка результата после внедрения
Чтобы проверить, что цена меняется корректно:
- Откройте страницу категории — цены должны быть на 10% ниже обычных.
- Откройте страницу товара — цена должна быть снижена на 5%.
- Добавьте товар в корзину и проверьте итоговую цену: если пользователь с ролью
wholesale_customer, цена должна быть дополнительно снижена на 15%. - Проверьте админ-панель — цены не должны изменяться.
Для проверки используйте инструменты разработчика браузера и дебаг-выводы (например, error_log()).
Частые ошибки и как их исправить
- Цена меняется в админке или REST API: всегда проверяйте
is_admin()иdefined('DOING_AJAX'), чтобы не ломать административные функции. - Изменения цены не применяются в корзине: не забудьте использовать хук
woocommerce_before_calculate_totalsи правильно устанавливать цену черезset_price(). - Дублирование логики: вынесите расчёт цены в отдельную функцию, чтобы избежать рассогласованности.
- Кеширование цен: если используете кеширование (например, объектный кеш или плагин кеша), очищайте кеш после внесения изменений.
Практические советы по производительности и безопасности
- Не выполняйте дорогостоящие операции в фильтрах изменения цены, особенно если это происходит для каждого товара на странице.
- Используйте кэширование результатов расчёта цены, если логика сложная.
- Не изменяйте цену напрямую в базе данных, только через хуки и методы объектов WooCommerce.
- Проверяйте права пользователя, чтобы не допустить утечки информации или неправильных скидок.