Диагностика задачи: зачем исключать товары и варианты по атрибуту
В интернет-магазинах на WooCommerce часто возникает необходимость скрыть из корзины и процесса оформления определённые товары или их вариации по заданному атрибуту. Например, товары с атрибутом "Снято с производства" или вариации типа "Тестовые" нельзя продавать. Это не только улучшает UX, но и предотвращает ошибки с заказами недоступных позиций.
Без корректной фильтрации такие товары могут остаться в корзине, что приведёт к проблемам с оплатой, логистикой и поддержкой клиентов.
Как проверить, что в корзине есть товары с нужным атрибутом
Для диагностики используйте следующий сниппет. Он выведет названия товаров с заданным атрибутом (например, pa_status со значением discontinued) в лог ошибок PHP:
add_action('woocommerce_check_cart_items', function() {
$attribute_name = 'pa_status'; // имя атрибута
$attribute_value = 'discontinued'; // значение атрибута
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
if ($product->is_type('variation')) {
$variation_attributes = $product->get_variation_attributes();
if (isset($variation_attributes[$attribute_name]) && $variation_attributes[$attribute_name] === $attribute_value) {
error_log('В корзине товар с атрибутом discontinued: ' . $product->get_name());
}
} else {
$product_attributes = $product->get_attributes();
if (isset($product_attributes[$attribute_name])) {
$terms = wc_get_product_terms($product->get_id(), $attribute_name, array('fields' => 'slugs'));
if (in_array($attribute_value, $terms)) {
error_log('В корзине товар с атрибутом discontinued: ' . $product->get_name());
}
}
}
}
});Проверьте логи PHP (обычно error_log) после добавления товаров в корзину. Если сообщения появляются, значит задачи фильтрации актуальна.
Пошаговое решение: исключение товаров и вариантов по атрибуту из корзины и оформления
Реализуем фильтрацию на двух уровнях: удаление таких товаров из корзины и блокировка оформления заказа с предупреждением.
1. Удаление товаров с заданным атрибутом из корзины
add_action('woocommerce_before_calculate_totals', function() {
$attribute_name = 'pa_status';
$attribute_value = 'discontinued';
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$remove = false;
if ($product->is_type('variation')) {
$variation_attributes = $product->get_variation_attributes();
if (isset($variation_attributes[$attribute_name]) && $variation_attributes[$attribute_name] === $attribute_value) {
$remove = true;
}
} else {
$product_attributes = $product->get_attributes();
if (isset($product_attributes[$attribute_name])) {
$terms = wc_get_product_terms($product->get_id(), $attribute_name, array('fields' => 'slugs'));
if (in_array($attribute_value, $terms)) {
$remove = true;
}
}
}
if ($remove) {
WC()->cart->remove_cart_item($cart_item_key);
}
}
});2. Блокировка оформления заказа при наличии таких товаров
add_action('woocommerce_check_cart_items', function() {
$attribute_name = 'pa_status';
$attribute_value = 'discontinued';
foreach (WC()->cart->get_cart() as $cart_item) {
$product = $cart_item['data'];
if ($product->is_type('variation')) {
$variation_attributes = $product->get_variation_attributes();
if (isset($variation_attributes[$attribute_name]) && $variation_attributes[$attribute_name] === $attribute_value) {
wc_add_notice('В корзине есть товары, которые нельзя заказать: "' . $product->get_name() . '".', 'error');
break;
}
} else {
$product_attributes = $product->get_attributes();
if (isset($product_attributes[$attribute_name])) {
$terms = wc_get_product_terms($product->get_id(), $attribute_name, array('fields' => 'slugs'));
if (in_array($attribute_value, $terms)) {
wc_add_notice('В корзине есть товары, которые нельзя заказать: "' . $product->get_name() . '".', 'error');
break;
}
}
}
}
});Проверка результата после внедрения
- Добавьте в магазин товар или вариацию с атрибутом
pa_status=discontinued. - Положите этот товар в корзину.
- Проверьте, что товар автоматически удаляется при обновлении корзины или выводится ошибка при попытке оформить заказ.
- Посмотрите логи PHP, чтобы убедиться, что сниппеты работают корректно (если добавляли диагностический код).
Частые ошибки и как их исправить
- Неправильное имя атрибута: WooCommerce добавляет префикс
pa_к пользовательским атрибутам. Проверьте точное имя атрибута в админке в разделе Товары – Атрибуты. - Атрибут не привязан к товару: убедитесь, что атрибут назначен товарам и что у вариаций есть правильные значения.
- Кэширование корзины: если используется плагин кэширования, отключите кэширование страниц корзины и оформления заказа, иначе изменения не будут видны.
- Конфликты с другими плагинами: временно деактивируйте плагины, влияющие на корзину, чтобы проверить корректность работы кода.
Практические советы по производительности и безопасности
- Для больших магазинов избегайте перебора всех товаров в корзине слишком часто. Используйте хуки, которые срабатывают только по необходимости (например,
woocommerce_before_calculate_totals). - Кэшируйте результаты запросов атрибутов, если планируете расширять функцию.
- Не выводите в пользовательский интерфейс подробные технические сообщения — используйте только понятные уведомления.
- Тестируйте изменения на копии сайта, чтобы избежать сбоев в рабочем магазине.
Сравнение вариантов решения
| Метод | Плюсы | Минусы | Пример |
|---|---|---|---|
| Фильтрация через код (хук) | Максимальный контроль, без лишних плагинов | Требует навыков PHP, нужно тестировать | Код из статьи |
| Плагины с фильтрацией по атрибутам | Простота настройки, готовые решения | Часто платные, могут влиять на производительность | WooCommerce Conditional Shipping and Payments |
| Использование групп цен или статусов товара | Гибкое управление на уровне WooCommerce | Сложнее настроить, требует дополнительных плагинов | Группы пользователей + цены |