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

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

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

Когда проблема действительно в настройках доставки

Сначала проверьте, что WooCommerce вообще получает адрес покупателя и применяет к нему зону доставки. Если зона настроена неверно, код не поможет: WooCommerce просто не найдёт подходящий метод.

Что обычно ломается

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

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

Пошаговое решение через зоны доставки WooCommerce

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

Шаг 1. Разделите зоны по реальным адресам

Откройте WooCommerce → Настройки → Доставка → Зоны доставки и создайте зоны в порядке от самой точной к самой общей. Например:

  • Москва;
  • Московская область;
  • Россия;
  • Остальные страны.

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

Шаг 2. Используйте регионы, а не только страну

Если магазин работает по РФ, не ограничивайтесь страной. WooCommerce умеет учитывать штат/область/регион и индекс. Для локальной доставки это важнее, чем кажется: один и тот же город может попадать в разные тарифные группы по индексам.

Шаг 3. Проверьте приоритет зон

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

ПодходКогда подходитМинус
Зоны доставки в админке2–5 правил, понятные регионыСложно масштабировать при большом числе исключений
Код через фильтрНужна логика по индексу, городу, сумме заказаТребует тестирования после обновлений
Плагин для условий доставкиМного правил и менеджеры меняют их без разработчикаДополнительная нагрузка и зависимость от плагина

Как скрывать методы доставки по адресу через код

Если стандартных зон недостаточно, можно отфильтровать доступные методы доставки на этапе расчёта. Для этого подходит фильтр woocommerce_package_rates. Он позволяет убрать конкретные методы, если адрес покупателя не соответствует условиям.

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

add_filter( 'woocommerce_package_rates', function( $rates, $package ) {
    if ( empty( $package['destination']['state'] ) ) {
        return $rates;
    }

    $state = $package['destination']['state'];

    // Пример: оставляем local_pickup только для Москвы и Московской области.
    $allowed_states = array( 'MOW', 'MOS' );

    if ( ! in_array( $state, $allowed_states, true ) ) {
        foreach ( $rates as $rate_id => $rate ) {
            if ( strpos( $rate_id, 'local_pickup' ) === 0 ) {
                unset( $rates[ $rate_id ] );
            }
        }
    }

    return $rates;
}, 10, 2 );

Важный момент: коды регионов зависят от страны и справочников WooCommerce. Для РФ это не всегда очевидно, поэтому перед внедрением проверьте, что именно приходит в $package['destination']['state'] и $package['destination']['postcode'].

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

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

add_filter( 'woocommerce_package_rates', function( $rates, $package ) {
    $postcode = isset( $package['destination']['postcode'] ) ? preg_replace( '/\D+/', '', $package['destination']['postcode'] ) : '';

    if ( $postcode === '' ) {
        return $rates;
    }

    // Пример: скрываем flat_rate для индексов вне диапазона.
    if ( $postcode < 100000 || $postcode > 199999 ) {
        foreach ( $rates as $rate_id => $rate ) {
            if ( strpos( $rate_id, 'flat_rate' ) === 0 ) {
                unset( $rates[ $rate_id ] );
            }
        }
    }

    return $rates;
}, 10, 2 );

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

Диагностика: как понять, что фильтр сработал

Перед тем как считать задачу решённой, проверьте расчёт доставки в корзине и на оформлении заказа. Самая частая ошибка — код добавили, но он не влияет на конкретный shipping method ID.

Что смотреть в первую очередь

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

Если нужно быстро увидеть структуру данных, временно добавьте логирование. Не оставляйте var_dump() на живом сайте.

add_filter( 'woocommerce_package_rates', function( $rates, $package ) {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        error_log( print_r( $package['destination'], true ) );
        error_log( print_r( array_keys( $rates ), true ) );
    }

    return $rates;
}, 20, 2 );

После теста удалите логирование или оставьте его только под условием WP_DEBUG. Иначе в логах быстро появится мусор.

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

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

  1. Откройте корзину в режиме инкогнито.
  2. Введите адрес, для которого метод должен быть скрыт.
  3. Обновите расчёт доставки и убедитесь, что лишний метод исчез.
  4. Смените адрес на разрешённый и проверьте, что метод возвращается.
  5. Создайте тестовый заказ и посмотрите, что в админке WooCommerce выбран корректный способ доставки.

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

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

Неправильный ID метода доставки

В коде часто проверяют не тот идентификатор. У метода может быть префикс flat_rate: с числовым ID, а не просто flat_rate. Сначала посмотрите реальные ключи в массиве $rates.

Проверка только страны

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

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

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

Метод скрывается не там, где ожидаете

Иногда фильтр убирает метод из одного shipping package, но WooCommerce формирует несколько пакетов. Это бывает при раздельной доставке товаров. Тогда нужно проверять каждый пакет отдельно, а не только первый.

Что выбрать: код, зоны или плагин

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

Практический ориентир

  • Зоны — когда правило можно объяснить одной строкой: «в Москве доступен самовывоз».
  • Код — когда нужно скрывать методы по нескольким условиям сразу.
  • Плагин — когда правил много и они должны редактироваться из админки.

Если вы уже используете плагины оптимизации вроде Clearfy Pro, не смешивайте их с логикой доставки без необходимости: чистка лишнего кода и отключение скриптов не решает проблему расчёта shipping methods. Здесь важнее корректная серверная логика и проверка адреса.

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

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

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

  • не используйте var_dump() на боевом сайте;
  • проверяйте код на staging перед публикацией;
  • не полагайтесь на кэш, если меняете правила доставки;
  • сохраняйте список реальных регионов и индексов, по которым работает доставка.

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

Как создать автоматическое сообщение о новых товарах WooCommerce через email
30.01.2026
Как использовать хук WooCommerce для обновления метаданных заказа на этапе оформления
05.05.2026
Как добавить вывод стоимости отсутствующих товаров в корзине WooCommerce
01.05.2026
WooCommerce: как настроить автоматическое возврат денег за отменённые заказы
05.07.2026
Как создать собственный виджет в WordPress: практическое руководство
25.11.2025

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