Диагностика задачи: зачем исключать товары из корзины по атрибутам
Иногда в интернет-магазине на WooCommerce нужно запретить одновременную покупку определённых товаров с особыми атрибутами. Например, товары с атрибутом "скидка" не должны сочетаться с товарами из категории "новинки", или нельзя позволить добавлять в корзину товары с атрибутом "промо" вместе с обычными товарами. Такая логика помогает контролировать акции, предотвращать ошибки ценообразования и улучшать UX.
Как проверить, есть ли в корзине товары с определённым атрибутом
Для начала нужно программно проверить, присутствуют ли товары с нужным атрибутом в корзине. Атрибуты в WooCommerce хранятся в метаданных продукта, и доступны через объект WC_Product.
function cart_has_product_with_attribute( $attribute_name, $attribute_value ) {
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$attributes = $product->get_attributes();
foreach ( $attributes as $attribute ) {
if ( $attribute->is_taxonomy() ) {
$terms = wp_get_post_terms( $product->get_id(), $attribute->get_name(), array( 'fields' => 'names' ) );
if ( in_array( $attribute_value, $terms, true ) ) {
return true;
}
} else {
if ( $attribute->get_options() && in_array( $attribute_value, $attribute->get_options(), true ) ) {
return true;
}
}
}
}
return false;
}Этот код проверяет корзину на наличие товара с определённым значением атрибута.
Пошаговое решение: блокируем добавление товара при конфликте атрибутов
Далее реализуем хук woocommerce_add_to_cart_validation, который срабатывает перед добавлением товара в корзину. Если в корзине уже есть товар с запрещённым атрибутом, отменим добавление и покажем сообщение об ошибке.
add_filter( 'woocommerce_add_to_cart_validation', 'prevent_conflicting_attributes_in_cart', 10, 3 );
function prevent_conflicting_attributes_in_cart( $passed, $product_id, $quantity ) {
$product = wc_get_product( $product_id );
// Пример: нельзя добавить товар с атрибутом "promo", если в корзине есть товар с "sale"
$new_product_has_promo = has_term( 'promo', 'pa_special', $product_id );
$cart_has_sale = cart_has_product_with_attribute( 'pa_special', 'sale' );
if ( $new_product_has_promo && $cart_has_sale ) {
wc_add_notice( 'Нельзя добавлять товары с атрибутом "promo" вместе с товарами по акции.', 'error' );
return false;
}
// Аналогично проверяем обратную ситуацию
$new_product_has_sale = has_term( 'sale', 'pa_special', $product_id );
$cart_has_promo = cart_has_product_with_attribute( 'pa_special', 'promo' );
if ( $new_product_has_sale && $cart_has_promo ) {
wc_add_notice( 'Нельзя добавлять товары по акции вместе с товарами с атрибутом "promo".', 'error' );
return false;
}
return $passed;
}Здесь pa_special — это slug атрибута, например, «pa_special» для атрибута «Специальные предложения».
Проверка результата после внедрения
- Добавьте в корзину товар с атрибутом
sale. - Попробуйте добавить товар с атрибутом
promo. Вы должны увидеть ошибку и товар не добавится. - Проверьте обратную ситуацию — сначала товар с
promo, потом сsale. - Добавление товаров без конфликтующих атрибутов происходит без ошибок.
Частые ошибки и как их исправить
- Неправильный slug атрибута или значения. Проверьте в админке WooCommerce в разделе «Атрибуты» точный slug (например,
pa_special), а также названия терминов. Ошибки в регистре или опечатки приводят к пропуску проверки. - Проверка атрибутов у вариативных продуктов. Если товар вариативный, атрибуты могут находиться в дочерних продуктах (вариациях). Нужно проверять именно вариацию, которая добавляется в корзину.
- Кэш корзины. Если вы используете плагин кэширования, убедитесь, что корзина обновляется корректно и нет кеширования AJAX-запросов.
Практические советы по безопасности и производительности
- Храните проверяемые атрибуты и их значения в константах или настройках, чтобы можно было быстро менять логику без правки кода.
- Не используйте тяжелые запросы к базе данных в хуках, вызываемых часто. Кэшируйте результаты, если проверка сложная.
- Тестируйте на разных версиях WooCommerce и WordPress, особенно если используете кастомные темы или плагинов, которые могут влиять на корзину.
- Логируйте ошибки с помощью
error_log()или специализированных плагинов, чтобы быстро находить проблемы.
Сравнение вариантов реализации
| Вариант | Плюсы | Минусы |
|---|---|---|
Код на hook woocommerce_add_to_cart_validation | Гибко, без плагинов, точечный контроль | Требует навыков PHP, может конфликтовать с кастомными плагинами |
| Плагин с настройками атрибутов | Простота настройки, интерфейс | Зависимость от стороннего кода, возможные платные лицензии |
| JavaScript-валидация на фронтенде | Быстрая обратная связь пользователю | Можно обойти, не гарантирует защиту на сервере |