Сценарий типичный: покупатель выбирает самовывоз или курьерскую доставку при получении, а WooCommerce всё равно показывает все доступные способы оплаты, включая онлайн-эквайринг. В результате менеджеру приходится вручную править заказы, а клиент видит лишние варианты и путается. Если у вас есть доставка, при которой оплата должна быть только наличными, переводом по счёту или вообще недоступна до подтверждения, это лучше решать на уровне логики checkout, а не инструкциями для менеджеров.
Ниже — рабочий способ без выдуманных хуков и без вмешательства в ядро. Он подходит, если нужно скрывать отдельные способы оплаты в зависимости от выбранного метода доставки.
Когда проблема действительно в логике доставки, а не в платёжном шлюзе
Сначала проверьте, что именно ломается. Иногда причина не в WooCommerce, а в настройках конкретного шлюза: у него может быть ограничение по странам, валюте, сумме заказа или статусу корзины. Но если платёжные методы должны меняться именно от способа доставки, то стандартных настроек WooCommerce обычно недостаточно.
Как быстро диагностировать
- Откройте оформление заказа в режиме инкогнито.
- Выберите по очереди разные способы доставки и посмотрите, меняется ли список оплат.
- Проверьте, не кешируется ли checkout сторонним плагином или серверным кешем.
- Посмотрите, как называются методы доставки в корзине: у WooCommerce это не всегда человекочитаемое имя, а строковый
rate_id.
Для диагностики полезно временно вывести выбранный способ доставки в лог или в заметку администратора. Но в рабочем решении лучше опираться на WC()->session и фильтр woocommerce_available_payment_gateways.
Как отключить оплату для выбранных способов доставки
Самый надёжный путь — отфильтровать доступные платёжные шлюзы на этапе расчёта checkout. WooCommerce уже знает выбранный способ доставки, и вы можете убрать ненужные методы оплаты до того, как они попадут на страницу оформления.
Пример: если выбран local_pickup, скрываем онлайн-оплату и оставляем только наличные при получении. Логику можно расширить под свои методы доставки.
add_filter( 'woocommerce_available_payment_gateways', 'wpes_limit_gateways_by_shipping_method' );
function wpes_limit_gateways_by_shipping_method( $gateways ) {
if ( is_admin() && ! wp_doing_ajax() ) {
return $gateways;
}
if ( ! function_exists( 'WC' ) || ! WC()->session ) {
return $gateways;
}
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_method = is_array( $chosen_methods ) && ! empty( $chosen_methods[0] ) ? $chosen_methods[0] : '';
if ( ! $chosen_method ) {
return $gateways;
}
// Пример: при самовывозе оставляем только оплату при получении.
if ( strpos( $chosen_method, 'local_pickup' ) !== false ) {
foreach ( $gateways as $gateway_id => $gateway ) {
if ( 'cod' !== $gateway_id ) {
unset( $gateways[ $gateway_id ] );
}
}
}
return $gateways;
}Если у вас не самовывоз, а, например, доставка курьером с оплатой только переводом, меняется только условие и список разрешённых шлюзов. Важно не сравнивать название метода доставки «на глаз», а проверить реальный идентификатор в корзине.
Как точечно привязать оплату к конкретному rate_id
У метода доставки в WooCommerce есть формат вроде flat_rate:3 или local_pickup:1. Если нужно отработать только на одном конкретном тарифе, лучше сравнивать полный идентификатор, а не часть строки. Это уменьшает риск случайно задеть другой способ доставки с похожим названием.
add_filter( 'woocommerce_available_payment_gateways', 'wpes_gateway_rules_for_specific_shipping_rate' );
function wpes_gateway_rules_for_specific_shipping_rate( $gateways ) {
if ( is_admin() && ! wp_doing_ajax() ) {
return $gateways;
}
if ( ! function_exists( 'WC' ) || ! WC()->session ) {
return $gateways;
}
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_method = is_array( $chosen_methods ) && ! empty( $chosen_methods[0] ) ? $chosen_methods[0] : '';
if ( 'flat_rate:3' === $chosen_method ) {
// Для этого тарифа оставляем только банковский перевод.
foreach ( $gateways as $gateway_id => $gateway ) {
if ( 'bacs' !== $gateway_id ) {
unset( $gateways[ $gateway_id ] );
}
}
}
return $gateways;
}Если нужен гибкий вариант: сравнение подходов
Иногда достаточно кода в теме или небольшом mu-plugin. Иногда удобнее взять готовое решение, если правила часто меняются и ими должен управлять менеджер без разработчика. Ниже — короткое сравнение.
| Подход | Когда подходит | Минус |
|---|---|---|
Код через woocommerce_available_payment_gateways | Правило одно или несколько, логика понятна и стабильна | Нужно поддерживать код и проверять после обновлений |
| Плагин для условной логики checkout | Много исключений, правила часто меняются | Дополнительная нагрузка и риск конфликта с другими плагинами |
| Настройки внутри платёжного шлюза | Ограничение зависит только от суммы, страны или валюты | Не решает привязку к способу доставки |
Если вы уже используете плагины для оптимизации и чистки сайта, например Clearfy Pro, это не заменяет такую логику. Здесь нужен именно контроль checkout, а не общая оптимизация фронтенда.
Пошаговая настройка без лишнего риска
- Определите, какие способы доставки должны влиять на оплату.
- Уточните реальные
rate_idв корзине. - Выберите, какие платёжные шлюзы должны остаться доступными.
- Добавьте код в дочернюю тему или в собственный мини-плагин.
- Проверьте оформление заказа на разных товарах и в разных зонах доставки.
Если у вас уже есть собственный плагин для бизнес-логики, лучше добавить код туда, а не в functions.php. Так проще переносить изменения между темами и не потерять их при обновлении.
Как проверить, что решение сработало
Проверка должна быть не формальной, а по сценариям. Откройте checkout и пройдите минимум три варианта:
- доставка, для которой оплаты нужно ограничить;
- доставка, для которой ограничения нет;
- смешанный случай, если у вас несколько зон или тарифов.
Смотрите не только на список методов оплаты, но и на итоговый заказ в админке. Важно, чтобы после оформления не появлялось расхождение между выбранной доставкой и доступной оплатой. Если используете кэш на стороне сервера или плагин ускорения, очистите кэш и повторите тест в инкогнито.
Полезно также проверить, не ломается ли обновление checkout через AJAX: WooCommerce пересчитывает доступные способы оплаты после смены доставки, и ваш фильтр должен отрабатывать именно в этот момент.
Частые ошибки и как их исправить
Сравнивают не тот идентификатор доставки
Ошибка выглядит так: код написан на основе названия метода, а в магазине фактически используется flat_rate:2 или другой instance ID. В итоге условие никогда не срабатывает. Решение простое: смотрите реальный rate_id в сессии или временно выводите его в лог.
Отключают шлюзы в админке без учёта AJAX
Если не исключить админскую часть и AJAX-обновления, можно сломать редактирование заказов или получить пустой список оплат в checkout. Поэтому в примерах выше есть проверка is_admin() и wp_doing_ajax().
Ставят код в тему, а потом теряют его после обновления
Для такой логики лучше использовать дочернюю тему или собственный плагин. Если правило критично для продаж, не храните его в файлах, которые регулярно заменяются.
Не проверяют конфликт с другими плагинами checkout
Плагины доставки, оплаты и кастомизации оформления заказа могут перезаписывать доступные шлюзы после вашего фильтра. Если поведение нестабильное, временно отключите всё лишнее и проверьте на чистом WooCommerce. Это быстрее, чем искать проблему в готовой сборке.
Что учесть для безопасности и производительности
Сам фильтр лёгкий, но он вызывается на checkout часто, поэтому код должен быть коротким и без лишних запросов к базе. Не делайте внутри фильтра тяжёлые WP_Query или обращения к внешним API. Если правила сложные, заранее храните их в массиве или в настройках плагина, а не вычисляйте каждый раз заново.
Если вы работаете с платёжными шлюзами, не скрывайте их только визуально через JavaScript. Это плохая практика: пользователь может отправить форму вручную, а сервер всё равно должен проверить допустимость оплаты. Именно поэтому серверный фильтр надёжнее фронтенд-скрытия.
Для магазинов с частыми изменениями логики доставки удобно вынести правила в отдельный файл и покрыть их хотя бы ручным чек-листом после каждого обновления WooCommerce. Это дешевле, чем разбирать инцидент, когда клиент оформил заказ с неподходящим способом оплаты.