Сценарий типичный: в магазине есть несколько способов доставки, но EMS должна быть доступна не везде. Например, вы хотите скрыть её для локальной зоны, для самовывоза или для заказов с маленькой суммой, где тариф EMS не имеет смысла. В WooCommerce это лучше решать не через правку шаблонов, а через фильтр доступных методов доставки.
Когда проблема проявляется и что именно ломается
Обычно EMS продолжает показываться в корзине и на checkout, хотя по бизнес-логике её там быть не должно. Это создаёт лишние вопросы от клиентов и путаницу в расчёте доставки. Если у вас уже настроены зоны доставки, но метод всё равно виден, причина чаще всего в том, что фильтрация не привязана к конкретной зоне, либо код проверяет не те идентификаторы методов.
Что нужно проверить до правки кода
- Включены ли в WooCommerce зоны доставки и назначен ли EMS именно в нужной зоне.
- Какой у метода доставки instance_id и method_id: у разных зон один и тот же метод может иметь разные экземпляры.
- Не переопределяет ли тему или плагин список способов доставки на checkout.
- Не кэшируется ли страница корзины или checkout сторонним плагином.
Если вы не уверены, какой идентификатор у EMS, сначала посмотрите его в настройках зоны доставки. В коде обычно фильтруют по method_id или по полному ключу метода, который приходит в массиве доступных способов.
Как отключить EMS для конкретной зоны доставки
Самый надёжный способ — отфильтровать доступные методы через woocommerce_package_rates. Этот хук срабатывает при расчёте доставки и позволяет убрать EMS только там, где она не нужна.
add_filter( 'woocommerce_package_rates', 'wpcodex_hide_ems_for_selected_zones', 20, 2 );
function wpcodex_hide_ems_for_selected_zones( $rates, $package ) {
if ( empty( $package['destination']['country'] ) ) {
return $rates;
}
$country = $package['destination']['country'];
$state = isset( $package['destination']['state'] ) ? $package['destination']['state'] : '';
$postcode = isset( $package['destination']['postcode'] ) ? $package['destination']['postcode'] : '';
foreach ( $rates as $rate_key => $rate ) {
if ( 'ems' === $rate->method_id ) {
if ( 'RU' === $country && in_array( $state, array( 'MOW', 'SPE' ), true ) ) {
unset( $rates[ $rate_key ] );
}
}
}
return $rates;
}Этот пример скрывает EMS для Москвы и Санкт-Петербурга, если доставка идёт по России. Логику можно поменять под вашу задачу: отключать метод для конкретной страны, региона, индекса или даже при определённой сумме заказа.
Если нужно отключать EMS только при низкой сумме заказа
Иногда EMS оставляют только для заказов выше порога. Тогда удобнее проверять сумму корзины и убирать метод до расчёта доставки.
add_filter( 'woocommerce_package_rates', 'wpcodex_disable_ems_below_threshold', 20, 2 );
function wpcodex_disable_ems_below_threshold( $rates, $package ) {
$cart_total = WC()->cart ? (float) WC()->cart->get_cart_contents_total() : 0;
$threshold = 5000;
if ( $cart_total < $threshold ) {
foreach ( $rates as $rate_key => $rate ) {
if ( 'ems' === $rate->method_id ) {
unset( $rates[ $rate_key ] );
}
}
}
return $rates;
}Такой вариант полезен, если EMS слишком дорогая для мелких заказов и вы не хотите показывать её как «ложный» выбор.
Сравнение подходов: плагин, код или настройка зоны
| Подход | Когда подходит | Минус |
|---|---|---|
| Настройки зон доставки | Если EMS нужно просто убрать из одной зоны | Не хватает гибкости для условий по сумме или составу корзины |
Код через woocommerce_package_rates | Если нужна точная логика по стране, региону, сумме, товарам | Нужно поддерживать код и проверять после обновлений |
| Сторонний плагин доставки | Если у команды нет разработчика и нужна простая админка | Лишняя зависимость и риск конфликтов с другими плагинами |
Если задача одна и логика понятная, код обычно надёжнее. Если правила часто меняются менеджером, лучше вынести часть условий в настройки плагина или в отдельный административный интерфейс.
Пошагово: как внедрить без поломки checkout
- Сначала определите, где именно EMS должна скрываться: по зоне, стране, региону или сумме заказа.
- Проверьте
method_idу способа доставки в WooCommerce. - Добавьте фильтр в дочернюю тему или в небольшой кастомный плагин.
- Очистите кеш страницы корзины и checkout, если он есть.
- Протестируйте несколько адресов доставки вручную.
Если вы добавляете код в functions.php, делайте это в дочерней теме. Для боевого проекта безопаснее вынести логику в отдельный мини-плагин: так она не исчезнет после обновления темы.
Как проверить, что решение сработало
Проверка должна быть не только визуальной. Откройте корзину и checkout с разными адресами доставки и убедитесь, что EMS появляется только там, где вы её оставили. Если метод скрывается условно, проверьте несколько сценариев подряд:
- адрес в нужной зоне — EMS должна быть видна;
- адрес вне зоны — EMS не должна отображаться;
- заказ ниже порога — EMS скрыта;
- заказ выше порога — EMS снова доступна;
- после смены адреса в корзине список методов пересчитывается корректно.
Если метод не исчезает, временно включите логирование и проверьте, какой массив приходит в $rates. Иногда проблема в том, что у метода не ems, а другой идентификатор, зависящий от конкретного плагина доставки.
Частые ошибки и как их исправить
Проверяют не тот идентификатор метода
У многих способов доставки есть общий method_id и отдельный экземпляр зоны. Если фильтр написан по неверному ключу, EMS останется в списке. Сначала посмотрите структуру объекта $rate через временный error_log() или отладчик.
Скрывают метод слишком поздно
Если пытаться менять вывод уже на уровне шаблона checkout, WooCommerce может пересчитать доставку и вернуть метод обратно. Надёжнее работать через фильтр расчёта ставок.
Не учитывают кэш
Кеш страницы корзины, AJAX-кеш или серверный кеш могут показывать старый список методов. После изменения логики очистите кеш и проверьте страницу в приватном окне.
Ломают доставку для всех зон
Это происходит, когда в коде нет проверки адреса или зоны, и метод удаляется всегда. Если нужна точечная логика, обязательно проверяйте страну, регион, индекс или сумму заказа до unset().
Безопасность и производительность
Фильтр доставки вызывается часто, поэтому код должен быть коротким и предсказуемым. Не делайте внутри него тяжёлые запросы к базе и не ходите во внешние API. Если нужно принять решение по сложным правилам, лучше заранее сохранить нужные данные в мета заказа или в настройках плагина.
Ещё один практический момент: не храните логику в случайных сниппетах без контроля версий. Для магазина это риск, потому что после обновления темы или переноса сайта правило может исчезнуть. Если у вас много технических правок, удобно держать их в отдельном плагине или в mu-plugin.
Если вам нужно не только скрывать EMS, но и убирать лишние дубли в магазине, полезно посмотреть на Clearfy Pro: он помогает с чисткой сайта и рядом типовых технических настроек, но саму бизнес-логику доставки всё равно лучше держать в коде.