Диагностика задачи: зачем ограничивать доступ к товарам по ролям
В интернет-магазинах на 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 | Идеально под бизнес-логику | Большая стоимость разработки и поддержки |