Диагностика задачи: зачем менять цены по ролям в WooCommerce
Иногда в интернет-магазинах на WooCommerce требуется отображать разные цены для разных групп пользователей. Например, для оптовиков, постоянных клиентов или партнеров цены могут отличаться от стандартных. Это позволяет гибко управлять ценовой политикой без создания отдельных товаров или магазинов.
По умолчанию WooCommerce не поддерживает изменение цены товара в зависимости от роли пользователя. Для решения задачи используются сторонние плагины или кастомный код.
Пошаговое решение с использованием PHP-кода
1. Определяем роли и нужные скидки
Для примера возьмем две пользовательские роли: wholesaler (оптовик) и vip_customer (VIP клиент). Для оптовиков цена будет снижена на 20%, для VIP клиентов — на 10%.
2. Добавляем фильтр для изменения цены товара
В functions.php вашей темы или в кастомном плагине добавьте следующий код:
add_filter('woocommerce_product_get_price', 'custom_price_by_user_role', 10, 2);
add_filter('woocommerce_product_get_regular_price', 'custom_price_by_user_role', 10, 2);
add_filter('woocommerce_product_get_sale_price', 'custom_price_by_user_role', 10, 2);
function custom_price_by_user_role($price, $product) {
if (is_admin()) return $price; // Не менять цену в админке
// Получаем объект текущего пользователя
$user = wp_get_current_user();
if (empty($user->roles)) return $price;
// Определяем скидку по роли
if (in_array('wholesaler', $user->roles)) {
return $price * 0.8; // скидка 20%
} elseif (in_array('vip_customer', $user->roles)) {
return $price * 0.9; // скидка 10%
}
return $price;
}
3. Обновляем отображение цены в корзине и чекауте
Для корректного отображения цены нужно добавить тот же фильтр для цены в корзине:
add_filter('woocommerce_cart_item_price', 'custom_cart_item_price', 10, 3);
function custom_cart_item_price($price_html, $cart_item, $cart_item_key) {
$product = $cart_item['data'];
$price = custom_price_by_user_role($product->get_price(), $product);
return wc_price($price);
}
Проверка результата после внедрения
- Залогиньтесь под пользователем с ролью
wholesalerи откройте страницу товара — цена должна быть на 20% ниже базовой. - Залогиньтесь под пользователем с ролью
vip_customer— цена должна быть на 10% ниже. - Залогиньтесь под пользователем без этих ролей — цена отображается стандартная.
- Добавьте товар в корзину под разными ролями и проверьте цену в корзине и на странице оформления заказа.
Частые ошибки и как их исправить
- Цена не меняется для незалогиненных пользователей. Это нормальное поведение, т.к. код проверяет роль текущего пользователя. Для гостей цена остается базовой.
- Цена меняется в админке товара. В коде есть проверка
is_admin(), чтобы этого избежать. Если цена меняется, убедитесь, что код добавлен корректно. - Конфликт с кэшированием. Если на сайте включено кеширование (например, плагин кеша), новые цены могут не отображаться сразу. Очистите кеш.
- Не отображается цена со скидкой в виджетах или на страницах с архивом товаров. Тогда дополнительно добавьте фильтры
woocommerce_get_price_htmlдля кастомизации вывода цены.
Практические советы по производительности и безопасности
- Код изменяет цену на лету, не сохраняя ее в базе, что безопасно и не влияет на данные товара.
- Используйте кеширование объекта пользователя, если планируете усложнять логику.
- Проверяйте роли пользователя через
in_array(), а не напрямую, чтобы избежать ошибок при нескольких ролях. - Для более сложных схем ценообразования лучше использовать проверенные плагины для оптовых цен или динамического ценообразования.
Сравнение вариантов реализации
| Метод | Плюсы | Минусы | Рекомендации |
|---|---|---|---|
| Кастомный код через хуки | Легко адаптировать, не требует плагинов | Требует навыков PHP, возможны ошибки | Использовать для простых скидок |
| Плагин оптовых цен | Готовые функции, поддержка, UI | Стоимость, нагрузка на сайт | Для сложных сценариев и корпоративных клиентов |
| Использование пользовательских метаполей | Гибкость, можно задать цены индивидуально | Сложнее поддерживать, требует кастомного кода | Если нужно уникальное ценообразование |