Диагностика задачи: зачем нужны индивидуальные цены в WooCommerce
В стандартном WooCommerce невозможно задать разные цены на товары для разных ролей пользователей (например, для оптовиков, дилеров, зарегистрированных клиентов). Если бизнес-модель требует дифференцированного ценообразования, необходимо внедрять кастомные решения или использовать плагины. Важно понять, что именно нужно: скидка в процентах, фиксированная цена, цены по категориям или для отдельных товаров.
Как проверить текущие настройки цен для ролей пользователей
Для диагностики:
- Проверьте, есть ли в системе кастомные функции или плагины, влияющие на цены (WooCommerce Dynamic Pricing, Wholesale Suite и пр.).
- Протестируйте цены под разными учетными записями с разными ролями.
- Посмотрите, есть ли в теме или функциях сайта фильтры типа
woocommerce_get_price,woocommerce_product_get_price.
Пошаговое решение: установка и настройка индивидуальных цен через код
1. Создаем роли пользователей
Если нужных ролей еще нет, добавим их функцией:
function add_custom_user_roles() {
add_role('wholesale_customer', 'Оптовый клиент', array('read' => true));
}
add_action('init', 'add_custom_user_roles');2. Добавляем метаполе для индивидуальной цены у товара
Для каждого товара добавим поле с ценой для оптовика через Advanced Custom Fields (ACF) или вручную:
function add_wholesale_price_field() {
woocommerce_wp_text_input(array(
'id' => '_wholesale_price',
'label' => 'Оптовая цена',
'desc_tip' => 'true',
'description' => 'Цена для оптовых клиентов',
'type' => 'text',
));
}
add_action('woocommerce_product_options_pricing', 'add_wholesale_price_field');
function save_wholesale_price_field($post_id) {
$wholesale_price = isset($_POST['_wholesale_price']) ? sanitize_text_field($_POST['_wholesale_price']) : '';
update_post_meta($post_id, '_wholesale_price', $wholesale_price);
}
add_action('woocommerce_process_product_meta', 'save_wholesale_price_field');3. Перекрываем цену товара для оптовиков
Добавим фильтр, который при отображении цены у пользователей с ролью 'wholesale_customer' покажет оптовую цену, если она задана:
function set_wholesale_price_for_role($price, $product) {
if (current_user_can('wholesale_customer')) {
$wholesale_price = get_post_meta($product->get_id(), '_wholesale_price', true);
if (!empty($wholesale_price) && is_numeric($wholesale_price)) {
return $wholesale_price;
}
}
return $price;
}
add_filter('woocommerce_product_get_price', 'set_wholesale_price_for_role', 10, 2);
add_filter('woocommerce_product_get_regular_price', 'set_wholesale_price_for_role', 10, 2);
add_filter('woocommerce_product_get_sale_price', 'set_wholesale_price_for_role', 10, 2);4. Обновление цены в корзине и заказе
Чтобы цена сохранялась в корзине и оформлялась корректно, добавим:
function custom_cart_item_price($cart_object) {
if (!WC()->session->__isset('reload_checkout')) {
foreach ($cart_object->get_cart() as $cart_item_key => $cart_item) {
if (current_user_can('wholesale_customer')) {
$wholesale_price = get_post_meta($cart_item['product_id'], '_wholesale_price', true);
if (!empty($wholesale_price) && is_numeric($wholesale_price)) {
$cart_item['data']->set_price($wholesale_price);
}
}
}
}
}
add_action('woocommerce_before_calculate_totals', 'custom_cart_item_price', 10, 1);Проверка результата
- Войдите под пользователем с ролью
wholesale_customer. - Откройте страницу товара с заполненным полем "Оптовая цена".
- Проверьте отображаемую цену — должна быть оптовая.
- Добавьте товар в корзину и перейдите к оформлению заказа — цена должна сохраниться.
- Под другим пользователем с ролью покупателя цена должна быть стандартной.
Частые ошибки и как их исправить
- Оптовая цена не отображается: проверьте, что метаполе
_wholesale_priceзаполнено и числовое. - Цена в корзине не меняется: возможно, фильтр
woocommerce_before_calculate_totalsне сработал — убедитесь, что функция подключена и приоритет 10. - Пользователь неправильно получает скидку: проверьте роль пользователя через
current_user_can(), возможно, роль не назначена или пользователь не авторизован. - Кэширование мешает увидеть изменения: очистите кэш сайта и браузера.
Практические советы по безопасности и производительности
- Не храните цены в пользовательских метаполях пользователей — для масштабируемости лучше хранить у товаров.
- Используйте числовой тип для цен, валидируйте ввод через
sanitize_text_fieldиfloatval. - Для больших магазинов с множеством ролей и сложными правилами лучше использовать специализированные плагины (например, Clearfy Pro может помочь с оптимизацией и SEO).
- Избегайте дублирования кода, используйте отдельные функции и проверяйте наличие роли через
user_can()для более точной проверки.
Сравнение подходов: плагин vs код
| Подход | Преимущества | Недостатки |
|---|---|---|
| Самописный код (как в статье) | Полный контроль, легковесность, отсутствие лишних функций | Требует навыков, нужно вручную поддерживать, сложнее масштабировать |
| Плагин (например, WooCommerce Wholesale Prices) | Быстрая настройка, поддержка разных правил, обновления | Может нагружать сайт, не всегда гибко под задачу, зависит от разработчика |