WooCommerce: как отключить способы доставки для определённых товаров

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

В WooCommerce это лучше решать на уровне фильтра расчёта доставки, а не через ручную правку каждого метода в админке. Так логика остаётся прозрачной и не ломается при обновлении плагинов.

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

Отключение способов доставки по составу корзины полезно, если:

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

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

Диагностика: почему метод доставки не скрывается

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

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

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

add_action('woocommerce_before_calculate_totals', function () {
    if (!function_exists('WC') || !WC()->cart) {
        return;
    }

    foreach (WC()->cart->get_cart() as $cart_item) {
        error_log('Cart product ID: ' . $cart_item['product_id']);
        error_log('Variation ID: ' . ($cart_item['variation_id'] ?? 0));
    }
});

Этот код не нужен в продакшене постоянно. Он только помогает проверить, какие ID реально видит WooCommerce.

Как отключить способы доставки для конкретных товаров

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

Ниже пример: если в корзине есть товар с определённым ID, скрываем все методы, кроме самовывоза. При необходимости список можно расширить под свои правила.

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

    $restricted_product_ids = [123, 456]; // ID товаров, для которых нужна особая доставка
    $has_restricted_product = false;

    foreach ($package['contents'] as $item) {
        $product_id = (int) $item['product_id'];
        $variation_id = !empty($item['variation_id']) ? (int) $item['variation_id'] : 0;

        if (in_array($product_id, $restricted_product_ids, true) || in_array($variation_id, $restricted_product_ids, true)) {
            $has_restricted_product = true;
            break;
        }
    }

    if (!$has_restricted_product) {
        return $rates;
    }

    foreach ($rates as $rate_id => $rate) {
        // Оставляем только самовывоз
        if (strpos($rate_id, 'local_pickup') === false) {
            unset($rates[$rate_id]);
        }
    }

    return $rates;
}, 10, 2);

Если вам нужно не оставить один метод, а наоборот скрыть только конкретные способы, меняется только условие внутри цикла. Например, можно убрать flat_rate:1 и оставить всё остальное.

add_filter('woocommerce_package_rates', function ($rates, $package) {
    $blocked_rate_ids = ['flat_rate:1', 'free_shipping:3'];

    foreach ($rates as $rate_id => $rate) {
        if (in_array($rate_id, $blocked_rate_ids, true)) {
            unset($rates[$rate_id]);
        }
    }

    return $rates;
}, 10, 2);

Если нужно ограничить доставку по категории товара

Часто удобнее проверять не отдельные ID, а категорию. Это особенно полезно, когда ассортимент меняется, а код должен оставаться стабильным.

add_filter('woocommerce_package_rates', function ($rates, $package) {
    $restricted_category_slug = 'khrupkie-tovary';
    $has_restricted_category = false;

    foreach ($package['contents'] as $item) {
        $product_id = (int) $item['product_id'];
        if (has_term($restricted_category_slug, 'product_cat', $product_id)) {
            $has_restricted_category = true;
            break;
        }
    }

    if (!$has_restricted_category) {
        return $rates;
    }

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

    return $rates;
}, 10, 2);

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

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

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

Пошагово: как внедрить без поломки checkout

  1. Определите, по чему именно строится правило: ID товара, категория, вариация или комбинация признаков.
  2. Добавьте код в дочернюю тему или в собственный мини-плагин, а не в файлы WooCommerce.
  3. Проверьте, что условие срабатывает на товаре в корзине, а не только на странице товара.
  4. Очистите кэш страницы и, если используется кэш доставки, обновите расчёт в корзине.
  5. Протестируйте несколько сценариев: только обычный товар, только ограниченный товар, смешанная корзина.

Если вы работаете через мини-плагин, структура может быть такой:

<?php
/**
 * Plugin Name: WC Shipping Restrictions
 */

add_filter('woocommerce_package_rates', function ($rates, $package) {
    $restricted_product_ids = [123, 456];
    $has_restricted_product = false;

    foreach ($package['contents'] as $item) {
        if (in_array((int) $item['product_id'], $restricted_product_ids, true)) {
            $has_restricted_product = true;
            break;
        }
    }

    if (!$has_restricted_product) {
        return $rates;
    }

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

    return $rates;
}, 10, 2);

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

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

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

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

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

Проверяют только product_id, но забывают про вариации

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

Скрывают методы по неправильному rate_id

В WooCommerce идентификатор метода доставки выглядит не как просто flat_rate, а как flat_rate:1 или похожая строка. Сначала посмотрите фактический rate_id, потом уже пишите условие.

Добавляют код в файл темы, который потом меняется

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

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

Если на сайте есть кэширование страниц или агрессивный оптимизатор, checkout и cart должны быть исключены из кэша. Иначе вы будете тестировать не WooCommerce, а сохранённую копию страницы.

Слишком рано отключают все методы

Иногда разработчики фильтруют методы до того, как WooCommerce собрал пакет доставки. В результате список пустой даже там, где правило не должно срабатывать. Для таких задач безопаснее работать через woocommerce_package_rates.

Безопасность и поддержка

Если правило доставки влияет на деньги и логистику, не держите его в произвольном сниппете без контроля версий. Для таких изменений полезно:

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

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

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

Добавь в закладки и поделись с друзьями:

⭐⭐⭐⭐⭐
Автоматическое удаление старых заказов и очистка базы данных WooCommerce
20.06.2026
Как создать собственную настройку плагинов WordPress
12.11.2025
Как использовать хук post save в WordPress для дополнительной обработки данных
19.12.2025
Как удалить дублирующийся контент в WordPress: практические методы и примеры
22.11.2025
Как автоматически удалять большие файлы в WordPress: практическое решение
09.04.2026
×
Прокачай свой WordPress!

Скидка -20% на премиум темы и плагины

Воспользоваться сейчас ⋙