Диагностика задачи: зачем нужны ценовые правила по ролям
В интернет-магазинах на WooCommerce часто возникает необходимость устанавливать разные цены на товары в зависимости от роли пользователя. Например, оптовым покупателям нужна скидка, а новым пользователям — специальные акции. WooCommerce не поддерживает это из коробки, поэтому приходится реализовывать кастомные решения.
Пошаговое решение: как задать цены для ролей через код
1. Определение текущей роли пользователя
Для изменения цены нам нужно определить роль текущего пользователя. В WordPress роли доступны через объект WP_User:
function get_current_user_role() {
if ( ! is_user_logged_in() ) {
return 'guest';
}
$user = wp_get_current_user();
if ( empty( $user->roles ) ) {
return 'subscriber';
}
return $user->roles[0];
}2. Фильтрация цены товара в WooCommerce
Для изменения цены используем фильтр woocommerce_product_get_price и woocommerce_product_get_regular_price, чтобы цена менялась и на странице товара, и в каталоге:
add_filter( 'woocommerce_product_get_price', 'custom_price_for_user_role', 10, 2 );
add_filter( 'woocommerce_product_get_regular_price', 'custom_price_for_user_role', 10, 2 );
function custom_price_for_user_role( $price, $product ) {
$role = get_current_user_role();
// Пример правил для ролей
$discounts = array(
'wholesale_customer' => 0.8, // 20% скидка
'premium_customer' => 0.9, // 10% скидка
'guest' => 1, // без скидки
);
if ( isset( $discounts[ $role ] ) ) {
$price = $price * $discounts[ $role ];
}
return $price;
}3. Обновление цены в корзине и при оформлении заказа
Чтобы цена корректно отображалась в корзине и заказе, добавим фильтр woocommerce_before_calculate_totals:
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_item_price_by_role', 10, 1 );
function custom_cart_item_price_by_role( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$role = get_current_user_role();
$discounts = array(
'wholesale_customer' => 0.8,
'premium_customer' => 0.9,
'guest' => 1,
);
if ( ! isset( $discounts[ $role ] ) ) {
return;
}
foreach ( $cart->get_cart() as $cart_item ) {
$original_price = $cart_item['data']->get_regular_price();
$new_price = $original_price * $discounts[ $role ];
$cart_item['data']->set_price( $new_price );
}
}Проверка результата после внедрения
- Войдите под пользователем с ролью
wholesale_customerи проверьте цену товара на странице и в корзине — она должна быть на 20% ниже обычной. - Выйдите из аккаунта (гость) — цена должна отображаться без скидок.
- Для других ролей проверьте соответствие скидкам.
Частые ошибки и как их исправить
- Цена не меняется в корзине: вероятно, пропущен хук
woocommerce_before_calculate_totalsили функция не проверяет роль пользователя корректно. - Скидка применяется не к той цене: всегда используйте
get_regular_price()для расчёта скидки, иначе могут возникать циклы и неверные цены. - Скидка видна гостям: не забывайте обрабатывать роль
guestотдельно. - Конфликты с другими плагинами скидок: протестируйте на чистом сайте, чтобы исключить конфликты.
Практические советы по безопасности и производительности
- Не храните скидки в опциях WordPress — лучше сделать массив в коде или использовать CPT для гибкости.
- Кэширование страницы может мешать динамическому изменению цен. Для страниц с индивидуальными ценами отключайте кэш или используйте AJAX для обновления цены.
- Минимизируйте нагрузку, не вызывайте
wp_get_current_user()в циклах, сохраняйте роль в сессии или глобальной переменной.
Сравнение вариантов реализации ценовых правил по ролям
| Метод | Преимущества | Недостатки |
|---|---|---|
| Кодовые фильтры в functions.php | Полный контроль, бесплатно, гибко | Требует навыков, возможны ошибки |
| Плагины типа "Dynamic Pricing" | Простота настройки, интерфейс | Платные, могут конфликтовать, нагрузка |
| Кастомный плагин с админкой | Удобство и контроль, расширяемость | Сложнее в разработке, поддержке |