Как запретить покупку одного товара вместе с другим в WooCommerce без плагинов

В WooCommerce часто нужен не «умный» каталог, а простое правило: если в корзине уже лежит один товар, второй туда добавлять нельзя. Это встречается у расходников и оборудования, у товаров с разной логистикой, у лицензий с разными условиями или у позиций, которые нельзя отправлять одной посылкой. Если ограничение не поставить на уровне корзины, менеджер потом вручную правит заказы, а покупатель получает непредсказуемую ошибку уже после оплаты.

Ниже — рабочий вариант без плагинов: проверяем корзину, блокируем несовместимые товары и показываем понятное сообщение. Подход подходит, если правило простое и его можно описать через ID товаров или категорий.

Когда это действительно нужно

Сценарий обычно выглядит так: товар A можно купить только отдельно, а товар B — только без A. Или наоборот: в одной корзине нельзя смешивать товары из разных групп. Если это ограничение связано не с маркетингом, а с реальной обработкой заказа, лучше решать его сразу в корзине, а не после оформления.

Если у вас десятки исключений и сложная логика по складам, регионам или способам доставки, код ниже можно использовать как основу, но дальше уже стоит выносить правила в отдельную таблицу или метаполя. Для простого кейса этого обычно не требуется.

Диагностика проблемы: где именно ломается сценарий

Перед правкой кода проверьте, на каком этапе возникает конфликт:

  • товар можно добавить в корзину, но ошибка появляется только на checkout;
  • несовместимый товар заменяет предыдущий без предупреждения;
  • корзина очищается полностью, хотя нужно удалить только новый товар;
  • ограничение работает в обычной корзине, но не срабатывает при AJAX-добавлении.

Если у вас включены кэш-плагины или мини-корзина обновляется через AJAX, важно тестировать не только страницу товара, но и быстрый сценарий добавления из каталога. Именно там чаще всего всплывают ошибки с сообщениями и редиректами.

Какой подход выбрать: код, плагин или ручная настройка

ПодходКогда подходитМинус
Код в теме или мини-плагинеНужно одно-две точных бизнес-правилаНадо сопровождать код
Плагин для ограничений корзиныМного правил без разработкиЛишняя нагрузка и зависимость от стороннего решения
Ручная проверка заказовРедкие кейсы и маленький потокОшибки доходят до оформления и поддержки

Если правило стабильно и не меняется каждый день, код обычно надежнее. Если же ограничения будут часто редактироваться менеджером, лучше делать отдельную админ-настройку или использовать специализированный плагин.

Пошаговое решение: блокируем несовместимые товары в корзине

Самый понятный вариант — сравнивать ID товаров. Это удобно, когда несовместимость касается конкретных позиций. Код можно добавить в functions.php дочерней темы или в небольшой mu-plugin.

<?php
add_filter( 'woocommerce_add_to_cart_validation', 'wpaction_block_incompatible_products', 10, 3 );

function wpaction_block_incompatible_products( $passed, $product_id, $quantity ) {
    if ( ! WC()->cart ) {
        return $passed;
    }

    // Список несовместимых товаров: ключ = товар, значение = массив товаров, с которыми его нельзя смешивать.
    $rules = array(
        123 => array( 456, 789 ),
        456 => array( 123 ),
        789 => array( 123 ),
    );

    $cart_product_ids = array();

    foreach ( WC()->cart->get_cart() as $cart_item ) {
        $cart_product_ids[] = (int) $cart_item['product_id'];
    }

    if ( empty( $cart_product_ids ) ) {
        return $passed;
    }

    if ( isset( $rules[ $product_id ] ) ) {
        $conflicts = array_intersect( $cart_product_ids, $rules[ $product_id ] );
        if ( ! empty( $conflicts ) ) {
            wc_add_notice( 'Этот товар нельзя покупать вместе с выбранными позициями в корзине. Оформите отдельный заказ.', 'error' );
            return false;
        }
    }

    foreach ( $rules as $locked_product_id => $blocked_ids ) {
        if ( in_array( $product_id, $blocked_ids, true ) && in_array( (int) $locked_product_id, $cart_product_ids, true ) ) {
            wc_add_notice( 'Этот товар нельзя покупать вместе с выбранными позициями в корзине. Оформите отдельный заказ.', 'error' );
            return false;
        }
    }

    return $passed;
}

Что делает этот код:

  • срабатывает до добавления товара в корзину;
  • собирает список уже лежащих товаров;
  • сравнивает его с таблицей несовместимости;
  • показывает сообщение и отменяет добавление.

Если вам нужно ограничение не по конкретным товарам, а по категориям, логику можно упростить: проверять has_term() для товара и текущих позиций корзины. Это удобнее, когда ассортимент меняется часто.

Вариант по категориям

<?php
add_filter( 'woocommerce_add_to_cart_validation', 'wpaction_block_by_category', 10, 3 );

function wpaction_block_by_category( $passed, $product_id, $quantity ) {
    if ( ! WC()->cart ) {
        return $passed;
    }

    $restricted_category = 'hazmat';
    $product_terms = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'slugs' ) );

    if ( is_wp_error( $product_terms ) || ! in_array( $restricted_category, $product_terms, true ) ) {
        return $passed;
    }

    foreach ( WC()->cart->get_cart() as $cart_item ) {
        $cart_product_id = (int) $cart_item['product_id'];
        $cart_terms = wp_get_post_terms( $cart_product_id, 'product_cat', array( 'fields' => 'slugs' ) );

        if ( ! is_wp_error( $cart_terms ) && ! empty( array_intersect( array( $restricted_category ), $cart_terms ) ) ) {
            continue;
        }

        wc_add_notice( 'Товары из этой категории нельзя смешивать с текущей корзиной.', 'error' );
        return false;
    }

    return $passed;
}

Этот вариант полезен, если правило завязано на тип товара, а не на отдельные карточки. Но у него есть компромисс: если категория используется для разных сценариев, ограничение станет слишком грубым.

Как сделать сообщение понятным покупателю

Фраза «ошибка добавления товара» не помогает никому. Лучше сразу писать, что именно делать дальше: удалить текущие позиции, оформить отдельный заказ или выбрать другой товар. Так вы снижаете количество обращений в поддержку.

Если хотите, можно заменить сообщение на более конкретное для разных правил. Например, для одного товара — «Этот товар оформляется отдельно», для другой группы — «Сначала завершите заказ на текущие позиции». Главное — не перегружать текст внутренними терминами склада.

Проверка результата после внедрения

После добавления кода проверьте сценарий не только вручную, но и в нескольких точках:

  • добавление товара со страницы товара;
  • добавление из каталога через AJAX;
  • попытка добавить несовместимый товар в уже заполненную корзину;
  • переход на checkout после очистки кэша;
  • поведение на мобильной версии, если мини-корзина открывается отдельно.

Если правило работает, WooCommerce должен показать notice и не добавить товар. Корзина при этом остается без изменений. Для проверки удобно открыть корзину в режиме инкогнито и повторить сценарий с нуля, чтобы исключить влияние старых сессий.

Дополнительно можно посмотреть, не ломается ли оформление заказа при наличии купонов, доставки и налога. Само ограничение на добавление товара обычно не конфликтует с этими функциями, но в реальном магазине лучше пройти весь путь до оплаты.

Частые ошибки и как их исправить

Код добавили в родительскую тему

После обновления темы правило исчезает. Для таких правок используйте дочернюю тему или отдельный мини-плагин. Это особенно важно, если магазин живет долго и обновляется регулярно.

Проверка идет только по product_id, а в корзине вариации

Если у товара есть вариации, иногда нужно учитывать не только родительский товар, но и variation_id. Иначе ограничение сработает не на ту позицию или не сработает вообще. В сложных кейсах проверяйте оба значения в массиве корзины.

Сообщение не показывается при AJAX-добавлении

Обычно причина в том, что тема или плагин перехватывает вывод notices. Проверьте, выводятся ли стандартные уведомления WooCommerce на странице корзины. Если нет, сначала исправьте шаблон, а потом уже тестируйте ограничение.

Корзина очищается целиком

Так делать не стоит, если правило касается только несовместимости. Пользователь теряет уже выбранные товары и чаще всего уходит. Лучше отменять добавление нового товара и оставлять текущую корзину как есть.

Безопасность и производительность

Сам по себе такой код легкий, но есть несколько практических моментов. Не храните правила в случайных опциях без валидации, если потом будете редактировать их из админки. Не используйте тяжелые запросы к базе на каждом добавлении товара, если можно обойтись ID и категориями. И не вставляйте код в сторонний плагин, который может отключиться после обновления.

Если ограничений много, лучше вынести правила в отдельный массив или в настройку, которую читает только админ. Для магазинов с большим каталогом имеет смысл заранее продумать структуру: товарные ID, категории, атрибуты или метки. Это упростит поддержку и снизит риск ошибки при ручном редактировании.

Когда нужно не только блокировать корзину, но и управлять другими сценариями магазина, иногда удобнее собрать набор точечных правок в одном месте. Для этого подходит, например, Clearfy Pro — не как замена коду, а как инструмент для части типовых задач по чистке и настройкам сайта: https://wpshop.ru/plugins/clearfy.

Если после внедрения ограничения покупатели все равно пытаются оформить несовместимые товары, проверьте не только код, но и путь добавления в корзину: быстрые кнопки, сторонние фильтры, мини-корзину и кэш на уровне страницы. В WooCommerce такие правила обычно ломаются не из-за самого хука, а из-за того, что тестируют не тот сценарий, который реально используют клиенты.

WooCommerce: автоматическое удаление неактуальных вариантов товаров
01.06.2026
Как автоматизировать обновление публикаций в WordPress с помощью WP-Cron и WPRemark
28.01.2026
Как удалить заблокированные пользователи из WordPress
09.12.2025
Автоматическое удаление корзины в WooCommerce после оплаты
01.05.2026
WooCommerce: как автоматически удалять заблокированные заказы для очистки базы
18.07.2026