WooCommerce: как ограничить доступ к товарам по ролям пользователей

Диагностика задачи: зачем ограничивать доступ к товарам по ролям

В интернет-магазинах на WooCommerce часто возникает необходимость ограничить видимость или покупку определённых товаров для разных групп пользователей, например, для оптовиков, партнёров или VIP-клиентов. В стандартной версии WooCommerce такой функционал отсутствует, и требуется кастомизация либо использование плагинов.

Часто клиенты жалуются, что не могут скрыть товар от незарегистрированных пользователей или ограничить покупку для определённых ролей, что ведёт к ошибкам в бизнес-логике и конфликтам в интерфейсе.

Как настроить ограничение доступа к товарам по ролям в WooCommerce

Создание пользовательских ролей (если ещё нет)

Для начала убедимся, что нужные роли созданы. Если нет, можно добавить роль с помощью функции add_role. Пример создания роли «Оптовик»:

function add_wholesaler_role() {
    add_role('wholesaler', 'Оптовик', array(
        'read' => true,
        'level_0' => true
    ));
}
add_action('init', 'add_wholesaler_role');

Роли можно создавать и через плагины типа User Role Editor, но для разработчиков удобно делать через код.

Ограничение видимости товаров по ролям

Ниже пример, который скрывает товары с метаполем restricted_to_roles от пользователей, не входящих в указанные роли. Мы будем использовать фильтр pre_get_posts для изменения запроса WooCommerce:

function restrict_products_by_user_role( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( is_shop() || is_product_category() || is_product_tag() ) {
        $user = wp_get_current_user();
        $user_roles = (array) $user->roles;
        $meta_query = array(
            'relation' => 'OR',
            array(
                'key' => 'restricted_to_roles',
                'compare' => 'NOT EXISTS'
            ),
            array(
                'key' => 'restricted_to_roles',
                'value' => '',
                'compare' => '='
            ),
            array(
                'key' => 'restricted_to_roles',
                'value' => $user_roles,
                'compare' => 'IN'
            )
        );
        $query->set('meta_query', $meta_query);
    }
}
add_action('pre_get_posts', 'restrict_products_by_user_role');

Здесь предполагается, что для товаров в метаполе restricted_to_roles хранится массив ролей, которым разрешён доступ. Товары без этого метаполя или с пустым полем видны всем.

Блокировка покупки товара по ролям

Чтобы дополнительно запретить добавление товара в корзину для неподходящих ролей, используйте хук woocommerce_add_to_cart_validation:

function restrict_add_to_cart_by_role( $passed, $product_id ) {
    $user = wp_get_current_user();
    $user_roles = (array) $user->roles;
    $allowed_roles = get_post_meta( $product_id, 'restricted_to_roles', true );
    if ( !empty($allowed_roles) && array_intersect($user_roles, $allowed_roles) === array() ) {
        wc_add_notice('У вас нет доступа к покупке этого товара.', 'error');
        return false;
    }
    return $passed;
}
add_filter('woocommerce_add_to_cart_validation', 'restrict_add_to_cart_by_role', 10, 2);

Проверка результата после внедрения

  • Войдите под пользователем с ролью, которая указана в метаполе товара — товар должен отображаться и его можно добавить в корзину.
  • Войдите под другим пользователем или как гость — товар должен быть скрыт в каталоге или показываться, но с ошибкой при добавлении в корзину.
  • Проверьте страницу товара напрямую по URL — если пользователь не имеет доступа, рекомендуем переадресовывать на страницу магазина или показывать сообщение об ограничении.

Частые ошибки и как исправить

  • Метаполе не задано или заполнено неправильно. Проверьте, что restricted_to_roles хранит массив ролей именно в формате PHP serialized или JSON. При неправильном формате фильтр не сработает.
  • Кэширование страниц мешает обновлениям. Отключите кэширование для страниц магазина и товаров при отладке, либо добавьте исключения для разных ролей.
  • Фильтр pre_get_posts применяется не к основному запросу. Убедитесь, что проверяете $query->is_main_query() и не затрагиваете админ-панель.
  • Пользователь не имеет роли. Для гостей роль пустая, поэтому товары с ограничением будут скрыты — это ожидаемо, но можно добавить отдельную логику для гостей.

Практические советы по безопасности и производительности

  • Храните данные о ролях доступа в метаполях товаров в формате JSON для удобства чтения и изменения через API.
  • Используйте объектный кэш WordPress для метаполей, чтобы уменьшить количество запросов к базе.
  • Добавьте редирект с прямых URL товаров, если у пользователя нет доступа, чтобы избежать ошибок 403 или пустых страниц.
  • Тестируйте изменения с включённым кэшированием и на боевом сервере, чтобы избежать сюрпризов.

Сравнение способов реализации ограничения доступа

МетодПлюсыМинусы
Код через pre_get_posts и add_to_cart_validationПолный контроль, гибкость, нет зависимости от плагиновТребует навыков, возможны ошибки при сложных запросах
Плагины (например, User Role Editor + WooCommerce Role Based Pricing)Быстрая настройка, готовый интерфейсДополнительная нагрузка, ограниченная кастомизация, возможны конфликты
Кастомные решения с пользовательским UIИдеально под бизнес-логикуБольшая стоимость разработки и поддержки
⭐⭐⭐⭐⭐