Типичный сценарий: в магазине есть самовывоз, но одновременно подключены платные способы доставки — курьер, СДЭК, Boxberry, фиксированная ставка. Проблема появляется, когда покупатель выбирает самовывоз, а WooCommerce всё равно показывает лишние варианты или считает их в итоговой сумме. Ниже — рабочие способы, как убрать платную доставку при самовывозе без лишней магии и с проверкой результата.
Когда это действительно ломает оформление заказа
Чаще всего ошибка выглядит не как «доставка не работает», а как несоответствие логики. Пользователь выбирает самовывоз, но:
- видит одновременно самовывоз и платные методы;
- сумма доставки не обнуляется;
- на странице оформления заказа остаются старые расчёты после смены адреса;
- платный метод становится выбранным по умолчанию, хотя нужен только самовывоз.
Если у вас включены зоны доставки, это особенно заметно: WooCommerce честно отдаёт все методы, которые подходят под зону, а бизнес-логика «при самовывозе платную доставку не показывать» уже не входит в стандартное поведение.
Что проверить до правки кода
Перед изменениями посмотрите на базовую конфигурацию. Иногда проблема не в коде, а в настройках зоны доставки.
- В WooCommerce → Настройки → Доставка проверьте, что самовывоз добавлен как отдельный метод в нужной зоне.
- Убедитесь, что платные методы не продублированы в нескольких зонах с пересечением адресов.
- Проверьте, не включён ли плагин, который переопределяет расчёт доставки или кэширует checkout-данные.
- Если используется кастомная тема, временно переключитесь на стандартную и проверьте поведение.
Как решить задачу через фильтр WooCommerce
Самый надёжный путь — отфильтровать список доступных методов доставки и оставить только local_pickup, когда он выбран или когда нужно принудительно скрыть платные варианты в этой зоне. Для этого подходит фильтр woocommerce_package_rates.
Ниже пример, который оставляет только самовывоз, если он доступен в посылке. Код лучше добавить в мини-плагин или в functions.php дочерней темы.
add_filter('woocommerce_package_rates', function ($rates, $package) {
$pickup_rates = [];
foreach ($rates as $rate_id => $rate) {
if (strpos($rate_id, 'local_pickup') === 0) {
$pickup_rates[$rate_id] = $rate;
}
}
if (!empty($pickup_rates)) {
return $pickup_rates;
}
return $rates;
}, 100, 2);Что делает этот код: если в доступных методах есть самовывоз, он оставляет только его. Если самовывоза нет, список не трогается. Это безопаснее, чем жёстко удалять все платные методы в любой ситуации.
Если нужно скрывать платную доставку только при выборе самовывоза
Иногда самовывоз и платные методы должны быть видны сначала, а после выбора самовывоза платные варианты нужно убрать. Тогда удобнее ориентироваться на выбранный метод из сессии WooCommerce.
add_filter('woocommerce_package_rates', function ($rates, $package) {
if (!function_exists('WC') || !WC()->session) {
return $rates;
}
$chosen_methods = WC()->session->get('chosen_shipping_methods');
$chosen_method = isset($chosen_methods[0]) ? $chosen_methods[0] : '';
if (strpos($chosen_method, 'local_pickup') !== 0) {
return $rates;
}
$filtered = [];
foreach ($rates as $rate_id => $rate) {
if (strpos($rate_id, 'local_pickup') === 0) {
$filtered[$rate_id] = $rate;
}
}
return !empty($filtered) ? $filtered : $rates;
}, 100, 2);Этот вариант полезен, если у вас несколько способов доставки и самовывоз должен работать как переключатель, а не как постоянное ограничение.
Диагностика: почему код может не сработать
Если после вставки кода ничего не изменилось, не спешите искать конфликт в WooCommerce. Сначала проверьте, какой именно ID у метода доставки. У самовывоза он обычно начинается с local_pickup, но в конкретной зоне может быть несколько экземпляров с разными ID.
Для быстрой диагностики можно временно вывести список rate ID в лог:
add_filter('woocommerce_package_rates', function ($rates, $package) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('Shipping rates: ' . implode(', ', array_keys($rates)));
}
return $rates;
}, 1, 2);После этого откройте страницу оформления заказа и посмотрите wp-content/debug.log. Если там нет local_pickup, значит проблема в настройках зоны доставки, а не в фильтре.
Пошаговая схема внедрения
- Проверьте, что самовывоз добавлен в нужную зону доставки.
- Определите, нужно ли скрывать платные методы всегда или только после выбора самовывоза.
- Добавьте код в дочернюю тему или мини-плагин, а не в основную тему.
- Очистите кэш сайта и кэш браузера, если на checkout есть оптимизация или отложенная загрузка.
- Протестируйте оформление заказа в режиме инкогнито.
Мини-плагин вместо functions.php
Если не хотите зависеть от темы, проще оформить решение как маленький плагин. Это удобно для переноса между проектами.
<?php
/**
* Plugin Name: WooCommerce Local Pickup Shipping Filter
*/
add_filter('woocommerce_package_rates', function ($rates, $package) {
$pickup_rates = [];
foreach ($rates as $rate_id => $rate) {
if (strpos($rate_id, 'local_pickup') === 0) {
$pickup_rates[$rate_id] = $rate;
}
}
return !empty($pickup_rates) ? $pickup_rates : $rates;
}, 100, 2);Как проверить, что решение сработало
Проверка должна быть не визуальной, а функциональной. Иначе легко пропустить ситуацию, когда на одном адресе всё работает, а на другом — нет.
- Откройте checkout в режиме инкогнито.
- Выберите адрес, который попадает в зону доставки с самовывозом.
- Убедитесь, что при наличии самовывоза платные методы не отображаются.
- Смените адрес на другой, где самовывоз не предусмотрен, и проверьте, что доставка снова считается по обычным правилам.
- Проверьте итоговую сумму заказа до и после смены метода доставки.
Если у вас включён AJAX на checkout, важно сделать ещё один тест: сменить метод доставки без перезагрузки страницы и убедиться, что WooCommerce пересчитывает корзину корректно.
Сравнение подходов: плагин, код, компромисс
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Код через фильтр | Нужна точная логика без лишних зависимостей | Контроль, предсказуемость, нет лишнего интерфейса | Нужно аккуратно тестировать зоны и ID методов |
| Плагин доставки | Нужны сложные правила по весу, городу, складу | Больше готовой логики, меньше ручного кода | Может добавлять лишнюю сложность и конфликтовать с темой |
| Компромисс через настройки зоны | Самовывоз нужен только в отдельных регионах | Просто и без кода | Не решает сценарий, когда логика зависит от выбранного метода |
Частые ошибки и как их исправить
Скрывают не тот метод доставки
Ошибка возникает, когда разработчик сравнивает не ID метода, а его название в админке. В WooCommerce нужно ориентироваться на технический ID, например local_pickup, а не на человекочитаемую подпись.
Код добавили в родительскую тему
После обновления темы правка исчезает. Для такого кода лучше использовать дочернюю тему или мини-плагин.
Не учитывают кэш checkout-страницы
Если на сайте есть агрессивный кэш или оптимизация JS, WooCommerce может показывать старые расчёты. В этом случае нужно исключить страницу оформления заказа из кэширования и проверить, не ломает ли оптимизатор AJAX-запросы.
Оставили несколько пересекающихся зон доставки
Тогда самовывоз может появляться в неожиданной зоне, а фильтр будет работать не так, как ожидается. Проверьте порядок зон и адреса, которые в них попадают.
Безопасность и производительность
Сам фильтр лёгкий, но проблема обычно не в нём, а в окружении. Не добавляйте тяжёлую логику в woocommerce_package_rates: там не стоит делать запросы к внешним API или сложные вычисления по каждому AJAX-обновлению checkout.
Если нужно более сложное правило — например, скрывать платную доставку только для определённых категорий товаров или складов — лучше вынести расчёт в отдельную функцию и кешировать результат на уровне транзиентов или сессии WooCommerce, если это оправдано логикой магазина.
Для проектов, где часто приходится чистить дубли, оптимизировать WooCommerce и убирать лишние сущности из админки, полезно держать под рукой инструменты вроде Clearfy Pro: он не решает задачу доставки напрямую, но помогает убрать часть технического шума на сайте и быстрее отлавливать конфликты. Если нужен такой инструмент, смотрите Clearfy Pro.
Если после внедрения логики самовывоза у вас всё ещё остаются нестабильные расчёты доставки, проверьте не только код, но и плагины кэширования, оптимизации checkout и сторонние модули доставки. В WooCommerce именно они чаще всего создают ощущение, что фильтр «не работает», хотя на самом деле проблема в пересчёте корзины.