Как отключить оплату при определённом способе доставки в WooCommerce

Типичный кейс: у вас есть доставка самовывозом, курьером и почтой, но не все способы оплаты должны быть доступны для каждого варианта. Например, при самовывозе нужен только наличный расчёт, а при доставке курьером — карта и онлайн-оплата. Если это не настроить, покупатель увидит лишние методы оплаты на 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 и пересчёт фрагментов.

Проверка по шагам

  1. Убедитесь, что код загружен: временно добавьте error_log( 'gateway filter loaded' ); и проверьте wp-content/debug.log.
  2. Проверьте, что в сессии есть chosen_shipping_methods.
  3. Сравните ID платёжных шлюзов в админке WooCommerce с теми, которые вы отключаете в коде.
  4. Отключите кеширование 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, удобнее собрать это в один небольшой плагин. Так проще сопровождать логику и не смешивать её с шаблонами темы.

Исключение товаров WooCommerce по атрибуту из корзины и оформления заказа
28.05.2026
Как сделать удалённый вызов REST API в WordPress с авторизацией
16.01.2026
Как исключить товары и варианты WooCommerce по атрибуту из корзины и оформления заказа
11.05.2026
Оптимизация базы данных WordPress для ускорения сайта
03.11.2025
Как исключить товары WooCommerce по атрибуту из корзины и оформления заказа
03.05.2026