Диагностика задачи: зачем ограничивать доступ к продуктам по ролям
В интернет-магазинах на WooCommerce часто возникает задача показывать определённые товары только определённым группам пользователей — например, оптовым покупателям или зарегистрированным клиентам с ролью "дилер". Это помогает реализовать дифференцированное ценовое предложение и персонализацию каталога.
Стандартный WooCommerce не предусматривает гибких настроек доступа к отдельным продуктам по ролям, поэтому для решения задачи нужно использовать кастомные методы или специализированные плагины.
Пошаговое решение: ограничение доступа к продуктам по ролям через код
1. Определение ролей и продуктов
Для начала определимся с ролями пользователей. Можно использовать стандартные роли WordPress или добавить свои. Например, роль wholesale_customer для оптовых клиентов.
2. Скрытие продуктов от неавторизованных ролей
Добавим фильтр, который исключит из каталога продукты, если пользователь не принадлежит к разрешённой роли.
add_action('pre_get_posts', 'wpa_restrict_products_by_role');
function wpa_restrict_products_by_role($query) {
if (is_admin() || !$query->is_main_query()) {
return;
}
if (is_shop() || is_product_category() || is_product_tag()) {
$user = wp_get_current_user();
$allowed_roles = ['wholesale_customer', 'administrator']; // роли с доступом
if (!array_intersect($allowed_roles, (array) $user->roles)) {
// Исключаем продукты с мета key 'restricted' = 'yes'
$meta_query = $query->get('meta_query');
if (!$meta_query) {
$meta_query = [];
}
$meta_query[] = [
'key' => 'restricted',
'value' => 'yes',
'compare' => '!=',
];
$query->set('meta_query', $meta_query);
}
}
}В данном примере мы предполагаем, что у товаров, доступ к которым надо ограничить, есть метаполе restricted со значением yes.
3. Добавление метаполя к продуктам
Чтобы пометить нужные продукты, можно использовать стандартный UI WooCommerce (через кастомные поля) или добавить метабокс через код:
add_action('add_meta_boxes', function() {
add_meta_box('product_restricted', 'Ограниченный доступ', function($post) {
$value = get_post_meta($post->ID, 'restricted', true);
wp_nonce_field('save_restricted_meta', 'restricted_meta_nonce');
?>
<label><input type="checkbox" name="restricted" value="yes" <?php checked($value, 'yes'); ?>> Ограничить доступ</label>
<?php
}, 'product', 'side');
});
add_action('save_post_product', function($post_id) {
if (!isset($_POST['restricted_meta_nonce']) || !wp_verify_nonce($_POST['restricted_meta_nonce'], 'save_restricted_meta')) {
return;
}
$restricted = isset($_POST['restricted']) && $_POST['restricted'] === 'yes' ? 'yes' : '';
update_post_meta($post_id, 'restricted', $restricted);
});Проверка результата после внедрения
- Залогиньтесь под пользователем с ролью
wholesale_customer— в каталоге должны отображаться все товары, включая помеченные как ограниченные. - Залогиньтесь под пользователем без этой роли — ограничённые товары должны исчезнуть из каталога и поисковой выдачи.
- Проверьте, что ограниченные товары недоступны через прямую ссылку — для этого дополнительно нужно реализовать проверку при загрузке продукта.
Дополнительная проверка доступа на странице товара
add_action('template_redirect', function() {
if (is_product()) {
global $post;
$user = wp_get_current_user();
$allowed_roles = ['wholesale_customer', 'administrator'];
$restricted = get_post_meta($post->ID, 'restricted', true);
if ($restricted === 'yes' && !array_intersect($allowed_roles, (array) $user->roles)) {
wp_redirect(home_url());
exit;
}
}
});Частые ошибки и как их исправить
- Ошибка: Ограниченные продукты всё равно видны для неавторизованных пользователей.
Причина: Фильтрpre_get_postsне срабатывает, если запрос не основной или код подключён не в правильном хукe.
Решение: Убедитесь, что функция подключена кpre_get_postsи проверяется$query->is_main_query(). Код должен быть в файле темы functions.php или в плагине. - Ошибка: Ограниченные продукты доступны по прямой ссылке.
Причина: Нет проверки доступа на уровне шаблона продукта.
Решение: Добавьте редирект вtemplate_redirect, как показано выше. - Ошибка: Метаполе
restrictedне сохраняется или не отображается.
Причина: Нет nonce-проверки или неправильно реализена сохранение метаполя.
Решение: Следуйте примеру с nonce и проверкой прав в функции сохранения метаполя.
Практические советы по безопасности и производительности
- Используйте проверки nonce и capability при сохранении метаполей, чтобы предотвратить CSRF и несанкционированное изменение данных.
- Для больших каталогов с множеством ограниченных продуктов рекомендуется индексировать метаполя в базе данных для ускорения запросов.
- Если ограничений много, рассмотрите использование специализированных плагинов (например, «Members» или «User Role Editor») для упрощения управления ролями.
- Кэширование страниц с учётом ролей пользователей может привести к утечке ограниченного контента — используйте кэширование, учитывающее текущего пользователя или отключайте кэш для страниц каталога.
Сравнение вариантов реализации ограничения доступа
| Метод | Плюсы | Минусы |
|---|---|---|
Код на pre_get_posts + метаполе | Полный контроль, бесплатно, легко кастомизируется | Требует знаний PHP, возможны ошибки при реализации |
| Плагин «Members» или «Groups» | Удобный UI, гибкие настройки ролей и доступа | Дополнительная нагрузка, не всегда подходит для тонкой настройки товаров |
| Платные решения WooCommerce Memberships | Полный функционал, поддержка, интеграция с WooCommerce | Цена, избыточность для простых задач |