Ситуация типичная: клиент выбирает самовывоз, доставку в пункт выдачи или локальную курьерскую доставку, а WooCommerce всё равно показывает все доступные способы оплаты. В итоге появляются лишние варианты, ошибки на чекауте и путаница у менеджеров. Если нужно жёстко связать оплату и доставку, это лучше делать на уровне фильтра, а не вручную в настройках каждого метода.
Когда это действительно нужно
Чаще всего задача возникает в магазинах с несколькими сценариями доставки:
- при самовывозе нельзя показывать оплату при получении;
- при доставке в другой город доступна только предоплата;
- для курьерской доставки в пределах города нужно скрыть банковский перевод;
- для определённых зон доставки нужно оставить только один способ оплаты.
Если ограничение зависит именно от выбранного способа доставки, стандартных настроек WooCommerce обычно недостаточно. В админке можно отключать методы оплаты глобально, но не по условию доставки без кода или дополнительного плагина.
Диагностика проблемы: что проверить до правки кода
Прежде чем лезть в шаблоны и функции, проверьте, как WooCommerce хранит выбранную доставку. На странице оформления заказа метод доставки передаётся как ID вида flat_rate:3, local_pickup:1 или free_shipping:2. Именно по этому значению и нужно фильтровать оплату.
Полезно сначала понять, где проблема проявляется:
- метод оплаты виден, но не должен отображаться;
- метод оплаты скрывается, но потом снова появляется после обновления чекаута AJAX;
- ограничение работает для гостей, но не работает для авторизованных пользователей;
- после установки плагина кешируется старый набор методов оплаты.
Если у вас включены плагины оптимизации, кеша или кастомные checkout-расширения, временно проверьте поведение без них. Иногда проблема не в фильтре, а в том, что фронтенд не получает актуальные данные после обновления доставки.
Как решить задачу через фильтр WooCommerce
Самый надёжный способ — использовать фильтр woocommerce_available_payment_gateways. Он позволяет убрать лишние методы оплаты уже после того, как WooCommerce собрал список доступных вариантов.
Пример: скрыть оплату при самовывозе
Ниже код, который убирает оплату при получении, если выбран самовывоз. Его можно добавить в functions.php дочерней темы или в небольшой кастомный плагин.
add_filter( 'woocommerce_available_payment_gateways', 'wpbit_hide_cod_for_local_pickup' );
function wpbit_hide_cod_for_local_pickup( $gateways ) {
if ( is_admin() ) {
return $gateways;
}
if ( ! function_exists( 'WC' ) || ! WC()->session ) {
return $gateways;
}
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = is_array( $chosen_methods ) ? reset( $chosen_methods ) : '';
if ( strpos( $chosen_shipping, 'local_pickup' ) !== false ) {
unset( $gateways['cod'] );
}
return $gateways;
}Здесь cod — стандартный ID метода «Оплата при доставке». Если у вас другой способ оплаты, нужно подставить его ID. Посмотреть ID можно в настройках платежных шлюзов или через временный вывод массива доступных шлюзов.
Пример: скрыть несколько способов оплаты для конкретной доставки
Если нужно убрать не один, а несколько методов, удобнее работать через массив исключений. Так код проще поддерживать, когда правила меняются.
add_filter( 'woocommerce_available_payment_gateways', 'wpbit_limit_gateways_by_shipping_method' );
function wpbit_limit_gateways_by_shipping_method( $gateways ) {
if ( is_admin() || ! function_exists( 'WC' ) || ! WC()->session ) {
return $gateways;
}
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = is_array( $chosen_methods ) ? reset( $chosen_methods ) : '';
$rules = array(
'local_pickup' => array( 'cod', 'bacs' ),
'flat_rate' => array( 'cod' ),
);
foreach ( $rules as $shipping_key => $payment_ids ) {
if ( strpos( $chosen_shipping, $shipping_key ) !== false ) {
foreach ( $payment_ids as $payment_id ) {
unset( $gateways[ $payment_id ] );
}
}
}
return $gateways;
}Этот вариант удобен, если у вас есть несколько зон доставки и для каждой — свой набор платежей. Но не перегружайте его сложной логикой, если условие одно и простое.
Сравнение подходов: плагин, код или настройки
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Настройки WooCommerce | Нужно отключить метод оплаты глобально | Без кода, быстро | Не умеет связывать оплату с доставкой |
| Плагин для checkout-правил | Нужно управлять правилами без разработки | Удобно для менеджера | Лишняя зависимость, не всегда прозрачно работает с кешем |
| Код через фильтр | Нужна точная логика по доставке | Контроль, предсказуемость, минимум лишнего | Нужно аккуратно тестировать |
Если у вас один магазин и понятные правила, код обычно надёжнее. Если правила часто меняются и ими управляет не разработчик, тогда имеет смысл смотреть в сторону плагина. Но даже в этом случае стоит проверить, как он ведёт себя с AJAX-обновлением чекаута.
Пошаговое внедрение без лишнего риска
- Сделайте резервную копию файлов темы или подготовьте отдельный мини-плагин.
- Определите ID способов оплаты и доставки, которые нужно связать.
- Добавьте фильтр
woocommerce_available_payment_gateways. - Проверьте условие по
chosen_shipping_methods. - Очистите кеш сайта и кеш браузера.
- Протестируйте оформление заказа в режиме гостя и под авторизованным пользователем.
Если вы вносите код в тему, лучше использовать дочернюю тему. Иначе после обновления шаблона правка может исчезнуть. Для небольших правил безопаснее вынести код в отдельный плагин, чтобы не смешивать бизнес-логику с оформлением.
Как проверить, что решение сработало
Проверка должна быть не формальной, а по сценариям. Откройте страницу корзины, выберите нужный способ доставки и посмотрите, исчез ли лишний метод оплаты. Затем переключите доставку на другой вариант и убедитесь, что платёж снова появляется.
Что стоит проверить отдельно:
- обновление чекаута без перезагрузки страницы;
- поведение на мобильном устройстве;
- гостевой заказ и заказ после входа в аккаунт;
- корректность на всех зонах доставки;
- отсутствие ошибок в консоли браузера и в
debug.log.
Если метод оплаты не исчезает, чаще всего проблема в том, что WooCommerce ещё не получил актуальный chosen_shipping_methods. Тогда нужно смотреть, не мешает ли кастомный JS, кеширование AJAX-запросов или сторонний плагин оформления заказа.
Частые ошибки и как их исправить
Сравнивают не тот ID доставки
Иногда разработчик проверяет только local_pickup, а реальный ID метода выглядит как local_pickup:2. В таком случае условие не срабатывает. Используйте strpos() или точное сравнение с полным ID, если он стабилен.
Проверяют только на сервере, но забывают про AJAX
WooCommerce на чекауте обновляет блоки через AJAX. Если метод оплаты скрывается только после полной перезагрузки, а не при смене доставки, значит логика не учитывает динамическое обновление страницы.
Ломают работу в админке
Без проверки is_admin() фильтр может мешать редактированию заказов или тестам в бэкенде. В большинстве случаев это не нужно, поэтому лучше сразу ограничить код фронтендом.
Скрывают не тот шлюз
В коде нужно использовать ID шлюза, а не его название в интерфейсе. Например, cod, bacs, cheque. Если ID указан неверно, метод не исчезнет, хотя фильтр отработает.
Безопасность и производительность
Сам фильтр лёгкий и не создаёт заметной нагрузки, если не добавлять в него тяжёлые запросы к базе. Не стоит внутри этого хука делать сложные выборки заказов или обращение к внешним API: он вызывается на странице оформления заказа, где важна скорость.
Если вы храните правила в опциях или в отдельной таблице, кэшируйте их на уровне объекта или хотя бы не пересчитывайте на каждом AJAX-обновлении без необходимости. И не забывайте, что любые изменения в checkout лучше тестировать на staging-копии магазина.
Для магазинов, где регулярно приходится чистить дубли, править SEO-метаданные и наводить порядок в технических настройках, иногда удобнее держать часть рутины в одном инструменте вроде Clearfy Pro: https://wpshop.ru/plugins/clearfy. Но именно для связки доставки и оплаты всё равно нужен отдельный код или специализированное правило, потому что это уже логика магазина, а не общая оптимизация.
Если после внедрения правила у вас остались лишние способы оплаты, проверьте ещё раз три вещи: выбранный метод доставки, ID платёжного шлюза и то, не переопределяет ли их сторонний checkout-плагин. В WooCommerce такие конфликты встречаются чаще, чем кажется, и обычно решаются не «магией», а точной проверкой данных, которые реально приходят в сессию.