Как отключить самовывоз в WooCommerce при наличии конкретного товара в корзине

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

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

Когда это нужно и как выглядит проблема

Обычно ошибка проявляется так: на странице оформления заказа самовывоз доступен для всех корзин, хотя для части товаров он запрещён внутренними правилами. После оплаты менеджер вручную меняет способ доставки, пишет клиенту или отменяет заказ. Это уже не техническая мелочь, а источник лишней ручной работы и конфликтов с покупателем.

Проверять нужно не только карточку товара, но и реальное содержимое корзины. В WooCommerce товар может попадать в корзину в нескольких количествах, а в корзине могут быть вариации. Поэтому решение должно смотреть на product_id или variation_id, а не на заголовок товара.

Диагностика: что именно мешает

Перед правкой кода ответьте на три вопроса:

  • Какой именно товар должен блокировать самовывоз: простой товар, вариация или оба варианта?
  • Нужно ли отключать только local_pickup или ещё и другие способы доставки?
  • Должно ли правило работать для всех зон доставки или только для конкретной зоны?

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

Рабочее решение через фильтр WooCommerce

Самый предсказуемый вариант — отфильтровать доступные методы доставки через woocommerce_package_rates. Этот фильтр получает список методов доставки для пакета, и вы можете удалить из него local_pickup, если в корзине есть запрещённый товар.

Код лучше добавлять в functions.php дочерней темы или в небольшой mu-plugin, если правило должно жить независимо от темы.

add_filter( 'woocommerce_package_rates', 'wpstudy_disable_local_pickup_for_specific_products', 10, 2 );
function wpstudy_disable_local_pickup_for_specific_products( $rates, $package ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return $rates;
    }

    $blocked_product_ids = array( 123, 456 ); // ID товаров, для которых самовывоз запрещён
    $blocked_variation_ids = array( 789 );     // при необходимости — ID вариаций

    $has_blocked_item = false;

    if ( ! empty( WC()->cart ) ) {
        foreach ( WC()->cart->get_cart() as $cart_item ) {
            $product_id   = (int) $cart_item['product_id'];
            $variation_id = ! empty( $cart_item['variation_id'] ) ? (int) $cart_item['variation_id'] : 0;

            if ( in_array( $product_id, $blocked_product_ids, true ) || in_array( $variation_id, $blocked_variation_ids, true ) ) {
                $has_blocked_item = true;
                break;
            }
        }
    }

    if ( $has_blocked_item ) {
        foreach ( $rates as $rate_id => $rate ) {
            if ( false !== strpos( $rate_id, 'local_pickup' ) ) {
                unset( $rates[ $rate_id ] );
            }
        }
    }

    return $rates;
}

Что здесь важно:

  • woocommerce_package_rates работает на уровне доступных способов доставки, а не на уровне интерфейса.
  • Проверка идёт по корзине, поэтому правило сработает и на странице корзины, и на checkout.
  • Удаление идёт по local_pickup в $rate_id, что обычно достаточно для стандартного самовывоза WooCommerce.

Если нужно отключать не только самовывоз

Иногда задача шире: при наличии определённого товара надо скрывать и самовывоз, и часть платных методов доставки. Тогда в массиве можно убрать несколько rate ID, но делать это лучше аккуратно: сначала посмотрите, какие именно идентификаторы приходят в вашей зоне доставки. Их можно временно вывести в лог или посмотреть через отладку.

add_filter( 'woocommerce_package_rates', 'wpstudy_log_shipping_rates_example', 10, 2 );
function wpstudy_log_shipping_rates_example( $rates, $package ) {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        error_log( print_r( array_keys( $rates ), true ) );
    }

    return $rates;
}

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

Сравнение подходов: код, плагин, ручная настройка

ПодходКогда подходитМинус
Код через woocommerce_package_ratesНужно точечное правило по товарам или вариациямТребует аккуратной проверки ID и зоны доставки
Плагин для условий доставкиПравил много, ими должен управлять менеджер без кодаДополнительная зависимость и риск конфликта с темой/кешем
Ручная настройка зон доставкиНужно лишь разделить регионы, без привязки к товарамНе решает задачу, если ограничение зависит от состава корзины

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

Пошаговая настройка без лишних рисков

  1. Определите ID товара или вариации, для которых самовывоз запрещён.
  2. Добавьте код в дочернюю тему или mu-plugin.
  3. Очистите кеш сайта и кеш плагина, если он есть.
  4. Проверьте корзину с обычным товаром и с запрещённым товаром.
  5. Убедитесь, что самовывоз исчезает только в нужном сценарии.

Если у вас несколько зон доставки, протестируйте каждую отдельно. WooCommerce формирует пакеты доставки по адресу и зоне, поэтому в одной зоне метод может быть скрыт, а в другой — нет, и это нормально, если так задумано.

Как проверить, что всё сработало

Проверка должна быть не визуальной «на глаз», а по сценарию:

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

Дополнительно откройте страницу оформления заказа в режиме инкогнито. Это помогает отловить проблемы, которые маскируются локальным кешем браузера или сохранёнными сессиями WooCommerce.

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

Проверяют название товара вместо ID

Название можно поменять, а ID остаётся стабильным. Если правило завязано на текст, оно быстро ломается после редактирования карточки. Используйте product_id и variation_id.

Удаляют не тот rate ID

В разных зонах доставки идентификаторы могут отличаться. Если у вас самовывоз не исчезает, сначала выведите список array_keys( $rates ) и посмотрите, как именно называется метод в вашей конфигурации.

Пишут код в родительскую тему

После обновления темы правило пропадёт. Для такой логики безопаснее дочерняя тема или отдельный mu-plugin.

Не учитывают кеш

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

Что учесть по безопасности и производительности

Сам фильтр лёгкий, но его не стоит превращать в тяжёлую проверку с запросами к базе на каждом рендере. Список блокируемых ID лучше хранить в коде или в настройках, если вы делаете это как мини-плагин. Не тяните данные из внешних API на странице оформления заказа — это лишняя точка отказа.

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

Для магазинов, где много подобных ограничений, полезно держать под рукой инструменты чистки и оптимизации WooCommerce. Например, Clearfy Pro от WPShop может быть уместен для общей гигиены сайта, но саму логику доставки он не заменяет. Если вы используете сторонние решения, всегда проверяйте, не перехватывают ли они фильтры доставки раньше вашего кода.

Как отключить индексацию страниц авторов в WordPress без потери SEO
16.08.2026
Как создать собственный виджет в WordPress с применением PHP и хуков
17.11.2025
Как создать автоматические уведомления о обновлениях в WordPress
03.01.2026
Как закрыть от индексации страницы поиска в WordPress без потери внутренней навигации
19.08.2026
WordPress REST API: как использовать для создания подключений и интеграций
10.11.2025