Типичный кейс: у вас есть доставка самовывозом, курьером и почтой, но не все способы оплаты должны быть доступны для каждого варианта. Например, при самовывозе нужен только наличный расчёт, а при доставке курьером — карта и онлайн-оплата. Если это не настроить, покупатель увидит лишние методы оплаты на checkout, а дальше начнутся отмены заказов и ручные правки.
В WooCommerce это решается на уровне фильтра woocommerce_available_payment_gateways. Ниже разберём, как диагностировать проблему, как ограничить оплату по выбранному способу доставки и как проверить, что всё работает без побочных эффектов.
Когда проблема заметна сразу
Обычно ошибка проявляется не в админке, а на странице оформления заказа. Пользователь выбирает доставку, но список оплат не меняется. Или меняется только после обновления страницы, хотя должен реагировать сразу через AJAX. Ещё один частый сценарий — правила работают для гостей, но ломаются для авторизованных покупателей, потому что тема или плагин кешируют checkout-разметку.
Что проверить до внесения кода
- Включён ли классический checkout WooCommerce, а не кастомная форма от темы или конструктора.
- Не переопределяет ли тема шаблон
checkout/payment.php. - Нет ли плагина, который уже фильтрует платежные шлюзы по стране, роли или сумме заказа.
- Используется ли стандартный способ доставки WooCommerce, а не внешний модуль с собственной логикой.
Если на странице оформления заказа уже есть конфликт, сначала отключите лишние плагины на тестовой копии сайта. Иначе вы будете искать ошибку в коде, хотя её создаёт другой фильтр, который срабатывает позже.
Как отключить оплату по способу доставки
Самый надёжный вариант — проверять выбранный shipping method и убирать лишние payment gateways на лету. Код лучше добавлять в дочернюю тему или в небольшой собственный плагин, а не в functions.php активной темы, если тема часто обновляется.
<?php
add_filter( 'woocommerce_available_payment_gateways', 'wpreg_disable_gateways_by_shipping_method' );
function wpreg_disable_gateways_by_shipping_method( $gateways ) {
if ( is_admin() ) {
return $gateways;
}
if ( ! function_exists( 'WC' ) || ! WC()->session ) {
return $gateways;
}
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
if ( empty( $chosen_methods ) || empty( $chosen_methods[0] ) ) {
return $gateways;
}
$chosen_method = $chosen_methods[0];
// Пример: если выбран самовывоз, оставляем только наличные.
if ( strpos( $chosen_method, 'local_pickup' ) !== false ) {
foreach ( $gateways as $gateway_id => $gateway ) {
if ( $gateway_id !== 'cod' ) {
unset( $gateways[ $gateway_id ] );
}
}
}
// Пример: если выбрана курьерская доставка, отключаем наложенный платёж.
if ( strpos( $chosen_method, 'flat_rate' ) !== false ) {
unset( $gateways['cod'] );
}
return $gateways;
}Здесь логика простая: мы смотрим на выбранный метод доставки и убираем из доступных шлюзов те, которые не подходят. Идентификаторы local_pickup, flat_rate и cod — это стандартные значения WooCommerce, но в конкретной установке они могут быть частью более длинной строки, если есть instance ID.
Как адаптировать код под свои методы
Если у вас несколько зон доставки, лучше не полагаться только на название метода. В реальном проекте удобнее сначала вывести значение выбранного метода в лог или временно показать его в HTML-комментарии на checkout, чтобы понять точный идентификатор.
<?php
add_action( 'woocommerce_review_order_before_payment', function() {
if ( current_user_can( 'manage_woocommerce' ) && function_exists( 'WC' ) && WC()->session ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
if ( ! empty( $chosen_methods[0] ) ) {
echo '<!-- chosen shipping method: ' . esc_html( $chosen_methods[0] ) . ' -->';
}
}
} );Этот приём полезен только на тестовом сайте или для админов. На боевом проекте лучше смотреть значение через логирование, чтобы не светить внутренние данные в HTML.
Диагностика: почему правило не срабатывает
Если после добавления фильтра список оплат не меняется, проблема обычно в одном из трёх мест: код не выполняется, выбранный способ доставки читается не из той сессии, или другой плагин перезаписывает результат позже. В WooCommerce это особенно заметно на checkout, потому что он активно использует AJAX и пересчёт фрагментов.
Проверка по шагам
- Убедитесь, что код загружен: временно добавьте
error_log( 'gateway filter loaded' );и проверьтеwp-content/debug.log. - Проверьте, что в сессии есть
chosen_shipping_methods. - Сравните ID платёжных шлюзов в админке WooCommerce с теми, которые вы отключаете в коде.
- Отключите кеширование checkout-страницы на уровне плагина или сервера.
Если используется плагин доставки с собственными методами, строка может выглядеть не как flat_rate, а как flat_rate:3 или похожий вариант. В таком случае сравнение через strpos() обычно надёжнее, чем жёсткое равенство.
Сравнение подходов: плагин, код или настройки шлюза
| Подход | Когда подходит | Минус |
|---|---|---|
| Настройки платёжного плагина | Если шлюз сам умеет ограничение по доставке | Не все плагины это поддерживают |
| Код через фильтр WooCommerce | Нужна точная логика под ваш магазин | Требует проверки после обновлений |
| Отдельный плагин-обвязка | Если логика сложная и нужна переносимость | Чуть больше поддержки и контроля версий |
Если задача одноразовая и логика простая, код через фильтр — самый прямой путь. Если у вас несколько условий, например доставка + страна + сумма заказа, лучше вынести правила в отдельный мини-плагин, чтобы не потерять их при смене темы.
Проверка результата после внедрения
После установки правила не ограничивайтесь визуальной проверкой в браузере. Нужно пройти checkout в нескольких сценариях и убедиться, что WooCommerce не показывает запрещённые методы оплаты после AJAX-пересчёта.
- Выберите самовывоз и проверьте, что доступны только нужные шлюзы.
- Выберите курьерскую доставку и убедитесь, что лишние методы скрыты.
- Обновите страницу оформления заказа и проверьте, что правило сохраняется.
- Оформите тестовый заказ до конца, чтобы убедиться, что выбранный шлюз не сбрасывается.
Если у вас включён режим отладки WooCommerce, посмотрите, не появляются ли ошибки в логах платежного плагина. Иногда шлюз скрывается корректно, но другой модуль пытается его принудительно вернуть через собственный фильтр.
Частые ошибки и как их исправить
Сравнивают не тот ID доставки
Проблема: в коде написано flat_rate, а фактически метод приходит как flat_rate:2. Решение: используйте strpos() или выведите точное значение в лог.
Код добавили в активную тему
Проблема: после обновления темы правило исчезает. Решение: перенесите код в дочернюю тему или в отдельный плагин.
Checkout кешируется
Проблема: покупатель видит старый набор оплат, хотя доставка уже поменялась. Решение: исключите страницу оформления заказа из кеша на уровне плагина, CDN или сервера.
Другой плагин меняет список шлюзов позже
Проблема: ваш фильтр срабатывает, но результат не сохраняется. Решение: проверьте приоритеты фильтров и временно отключите сторонние модули, которые работают с оплатой.
Безопасность и производительность
Сам фильтр лёгкий, но на checkout любая лишняя логика чувствуется сразу. Не делайте в нём запросы к базе, внешним API или тяжёлые вычисления. Если нужны сложные правила, заранее подготовьте данные и храните их в опциях или в мета заказа, а не пересчитывайте на каждом рендере.
Для отладки используйте debug.log и ограничивайте вывод только администраторам. Не оставляйте временные var_dump() и HTML-комментарии на боевом сайте. Если правило связано с оплатой, обязательно проверьте его в тестовом режиме у каждого шлюза, который реально используется в магазине.
Если вам нужно не только скрывать оплату, но и менять текст, порядок или условия показа блоков на checkout, удобнее собрать это в один небольшой плагин. Так проще сопровождать логику и не смешивать её с шаблонами темы.