Диагностика задачи: зачем ограничивать покупку товаров по атрибутам
В интернет-магазине на WooCommerce иногда возникает необходимость запретить клиентам добавлять в корзину определенные товары или варианты продуктов, если они обладают заданным атрибутом. Пример: запретить покупку товаров с атрибутом «Скидка» вместе с обычными товарами или ограничить минимальное/максимальное количество товаров с определенным атрибутом. Такие ограничения могут быть нужны для промо-акций, управления складом или предотвращения конфликтов товаров.
Как проверить, что ограничения нужны и какие атрибуты участвуют
Для начала определите, какие именно атрибуты должны влиять на логику корзины. Перейдите в админку WordPress: Товары → Атрибуты. Здесь посмотрите слаг (slug) атрибута и значения. Для примера возьмем атрибут color с термином red.
Пошаговое решение: запрет добавления в корзину товаров с определенным атрибутом
1. Добавление фильтра для проверки товаров в корзине
В файл functions.php вашей темы или в кастомный плагин вставьте следующий код:
add_filter('woocommerce_add_to_cart_validation', 'wc_restrict_products_by_attribute', 10, 3);
function wc_restrict_products_by_attribute($passed, $product_id, $quantity) {
$restricted_attribute = 'color'; // Атрибут для проверки
$restricted_term = 'red'; // Значение атрибута, по которому ограничиваем
$product = wc_get_product($product_id);
if (!$product) {
return $passed;
}
// Получаем атрибуты товара
$attributes = $product->get_attributes();
if (!isset($attributes[$restricted_attribute])) {
return $passed;
}
$attribute = $attributes[$restricted_attribute];
// Проверяем, является ли атрибут вариативным или нет
if ($attribute->is_taxonomy()) {
$terms = wp_get_post_terms($product_id, $attribute->get_name(), ['fields' => 'slugs']);
if (in_array($restricted_term, $terms)) {
wc_add_notice(__('Извините, покупка товаров с красным цветом временно запрещена.'), 'error');
return false;
}
} else {
// Атрибут кастомный, не таксономия
$values = explode('|', $attribute->get_options());
if (in_array($restricted_term, $values)) {
wc_add_notice(__('Извините, покупка товаров с красным цветом временно запрещена.'), 'error');
return false;
}
}
return $passed;
}2. Ограничение по количеству товаров с атрибутом в корзине
Чтобы ограничить количество товаров с определенным атрибутом, например максимум 2 штуки товаров с цветом red, используйте такой код:
add_filter('woocommerce_add_to_cart_validation', 'wc_limit_quantity_by_attribute', 20, 3);
function wc_limit_quantity_by_attribute($passed, $product_id, $quantity) {
$restricted_attribute = 'color';
$restricted_term = 'red';
$max_quantity = 2;
$product = wc_get_product($product_id);
if (!$product) {
return $passed;
}
$attributes = $product->get_attributes();
if (!isset($attributes[$restricted_attribute])) {
return $passed;
}
$attribute = $attributes[$restricted_attribute];
$has_restricted_term = false;
if ($attribute->is_taxonomy()) {
$terms = wp_get_post_terms($product_id, $attribute->get_name(), ['fields' => 'slugs']);
if (in_array($restricted_term, $terms)) {
$has_restricted_term = true;
}
} else {
$values = explode('|', $attribute->get_options());
if (in_array($restricted_term, $values)) {
$has_restricted_term = true;
}
}
if (!$has_restricted_term) {
return $passed;
}
// Подсчёт количества товаров с этим атрибутом в корзине
$current_qty = 0;
foreach (WC()->cart->get_cart() as $cart_item) {
$cart_product = $cart_item['data'];
if (!$cart_product) continue;
$cart_attributes = $cart_product->get_attributes();
if (!isset($cart_attributes[$restricted_attribute])) continue;
$cart_attribute = $cart_attributes[$restricted_attribute];
if ($cart_attribute->is_taxonomy()) {
$cart_terms = wp_get_post_terms($cart_product->get_id(), $cart_attribute->get_name(), ['fields' => 'slugs']);
if (in_array($restricted_term, $cart_terms)) {
$current_qty += $cart_item['quantity'];
}
} else {
$cart_values = explode('|', $cart_attribute->get_options());
if (in_array($restricted_term, $cart_values)) {
$current_qty += $cart_item['quantity'];
}
}
}
if (($current_qty + $quantity) > $max_quantity) {
wc_add_notice(sprintf(__('Максимальное количество товаров с цветом красный — %d.'), $max_quantity), 'error');
return false;
}
return $passed;
}Проверка результата после внедрения
- Попробуйте добавить товар с атрибутом
color=redв корзину. Если стоит запрет, должна появиться ошибка и товар не добавится. - Попробуйте добавить несколько товаров с этим атрибутом, чтобы проверить ограничение по количеству.
- Добавьте товар без атрибута
color=red— он должен добавляться без проблем. - Проверьте работу в разных браузерах и учёт сессий.
Частые ошибки и как исправить
- Неверный слаг атрибута: в коде указан атрибут, которого нет у товара. Проверьте точный slug в
Товары → Атрибуты. - Неправильная проверка таксономии: если используете пользовательские атрибуты (не таксономии), методы получения значений отличаются. Код учитывает оба варианта.
- Кэширование корзины: иногда кэш может мешать проверить изменения, выключите кэширование страниц для корзины и оформления заказа.
- Конфликты с другими плагинами: отключите сторонние плагины, если ограничения не работают.
Практические советы по безопасности и производительности
- Код ограничений не должен выполнять избыточные запросы к базе. Используйте методы WooCommerce для получения атрибутов и терминов, они кэшируются.
- Добавляйте сообщения об ошибках через
wc_add_notice, чтобы пользователи точно понимали причину отказа. - Храните кастомные функции в отдельном плагине, чтобы сохранить их при смене темы.
- Тестируйте изменения на staging-сайте перед внедрением в продакшен.
Сравнение вариантов реализации ограничения товаров по атрибутам
| Метод | Плюсы | Минусы | Пример использования |
|---|---|---|---|
| Код в functions.php | Быстро, без плагинов, гибко | Зависит от темы, требует навыков | Код из статьи |
| Плагин «WooCommerce Conditional Shipping and Payments» | Удобный интерфейс, много условий | Платный, более тяжелый | Ограничения на оплату/доставку |
| Пользовательский плагин | Максимальная гибкость, не зависит от темы | Требует разработки | Создать собственный модуль по примеру статьи |