Как ограничить способы оплаты по методам доставки в WooCommerce

Сценарий типичный: клиент выбирает самовывоз, а вы хотите показывать только оплату на месте; при курьерской доставке — онлайн-эквайринг; при наложенном платеже — только те способы, которые реально поддерживает логистика. В WooCommerce это лучше решать на уровне фильтрации доступных шлюзов, а не через ручные инструкции для менеджеров.

Ниже — рабочий вариант без выдуманных API и без тяжёлых плагинов. Подход подходит, если нужно связать payment gateways с выбранным методом доставки на checkout.

Когда проблема проявляется и что именно ломается

Обычно ошибка видна не сразу. Магазин работает, заказы приходят, но в корзине и на оформлении заказа появляются лишние способы оплаты. Это приводит к трем практическим проблемам:

  • клиент выбирает оплату, которая не подходит для выбранной доставки;
  • оператор вручную меняет заказы и тратит время на уточнения;
  • часть заказов уходит в статус ожидания оплаты, хотя должна была оформляться только при доставке.

Если у вас несколько зон доставки, несколько курьерских служб или самовывоз из разных точек, правило обычно строится не по названию метода, а по его идентификатору. Это важный момент: в админке виден человекочитаемый текст, но в коде нужно опираться на технический ID.

Как быстро диагностировать, что именно передаёт WooCommerce

Перед внедрением правила проверьте, какие методы доставки реально выбираются на checkout. Самый простой способ — временно вывести выбранный метод в лог или в HTML-комментарий на тестовой среде. Если вы работаете в дочерней теме или мини-плагине, можно использовать такой отладочный фрагмент:

add_action( 'woocommerce_review_order_before_payment', function () {
    if ( ! function_exists( 'WC' ) || ! WC()->session ) {
        return;
    }

    $chosen = WC()->session->get( 'chosen_shipping_methods' );

    if ( ! empty( $chosen ) ) {
        echo '<!-- chosen_shipping_methods: ' . esc_html( implode( ', ', (array) $chosen ) ) . ' -->';
    }
} );

Это не боевой код, а способ увидеть, какой идентификатор реально приходит в сессию. На тестовом сайте откройте checkout, переключите доставку и посмотрите исходный код страницы или лог браузера.

Как ограничить оплату по выбранной доставке

Для задачи достаточно фильтра woocommerce_available_payment_gateways. Он позволяет убрать лишние шлюзы до того, как WooCommerce покажет их покупателю.

Ниже пример: при самовывозе оставляем только оплату наличными, при курьерской доставке скрываем наложенный платёж, а для остальных случаев ничего не меняем.

add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
    if ( is_admin() ) {
        return $gateways;
    }

    if ( ! function_exists( 'WC' ) || ! WC()->session ) {
        return $gateways;
    }

    $chosen_shipping = WC()->session->get( 'chosen_shipping_methods' );
    $chosen_shipping = is_array( $chosen_shipping ) ? reset( $chosen_shipping ) : '';

    if ( ! $chosen_shipping ) {
        return $gateways;
    }

    // Пример: самовывоз
    if ( strpos( $chosen_shipping, 'local_pickup' ) !== false ) {
        unset( $gateways['cod'] );
        unset( $gateways['bacs'] );
        return $gateways;
    }

    // Пример: курьерская доставка
    if ( strpos( $chosen_shipping, 'flat_rate' ) !== false ) {
        unset( $gateways['cod'] );
        return $gateways;
    }

    return $gateways;
} );

Здесь используются стандартные идентификаторы шлюзов WooCommerce: cod для наложенного платежа, bacs для банковского перевода. У вас могут быть другие шлюзы — их ID нужно проверить в настройках или в коде плагина оплаты.

Если нужно связать оплату не с типом доставки, а с конкретным методом

Иногда flat_rate слишком грубый критерий. Например, у вас два курьерских тарифа: один с предоплатой, другой с оплатой при получении. Тогда лучше сравнивать полный ID метода доставки, например flat_rate:3 или local_pickup:1. Именно такой формат WooCommerce часто хранит в сессии.

Пример более точного правила:

add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
    if ( is_admin() || ! function_exists( 'WC' ) || ! WC()->session ) {
        return $gateways;
    }

    $chosen_shipping = WC()->session->get( 'chosen_shipping_methods' );
    $chosen_shipping = is_array( $chosen_shipping ) ? reset( $chosen_shipping ) : '';

    if ( $chosen_shipping === 'local_pickup:1' ) {
        unset( $gateways['stripe'] );
        unset( $gateways['cod'] );
    }

    if ( $chosen_shipping === 'flat_rate:3' ) {
        unset( $gateways['cod'] );
    }

    return $gateways;
} );

Замените local_pickup:1 и flat_rate:3 на свои значения. Это уже не общая логика, а точечное правило под конкретную схему магазина.

Плагин, код или настройка: что выбрать

Если задача простая и стабильная, код обычно надёжнее: он прозрачен, не зависит от интерфейса стороннего плагина и легко переносится между средами. Если у вас много правил и ими должны управлять менеджеры без доступа к коду, тогда имеет смысл смотреть в сторону специализированного плагина для conditional payment methods.

ПодходКогда подходитМинус
Код через фильтр WooCommerce1–5 жёстких правил, понятные ID доставки и оплатНужно сопровождение в теме или мини-плагине
Специализированный плагинМного условий, нужен интерфейс для менеджеровДополнительная зависимость и риск конфликтов
Ручная инструкция клиентуПочти никогдаОшибки, лишние обращения, плохой UX

Если у вас уже стоит набор сервисных плагинов для оптимизации сайта, например Clearfy Pro, это не решает задачу выбора оплат, но помогает не раздувать проект лишними модулями. Для этой конкретной логики лучше оставить только то, что реально нужно магазину.

Пошаговое внедрение без поломки checkout

  1. Сделайте резервную копию файлов и базы.
  2. Добавьте код в мини-плагин или в functions.php дочерней темы.
  3. Проверьте технические ID способов доставки и оплаты.
  4. Протестируйте checkout в режиме инкогнито и с очищенной корзиной.
  5. Проверьте разные адреса доставки, если правила зависят от зоны.
  6. Убедитесь, что лишний шлюз исчезает после смены метода доставки без перезагрузки страницы.

Если вы вносите код в тему, помните: при обновлении родительской темы изменения могут потеряться. Для магазина безопаснее вынести правило в небольшой mu-plugin или отдельный плагин проекта.

Как проверить, что решение сработало

Проверка должна быть не визуальной, а сценарной. Пройдите по нескольким веткам:

  • выберите самовывоз и убедитесь, что остаются только разрешённые способы оплаты;
  • выберите курьерскую доставку и проверьте, что наложенный платёж скрыт;
  • смените доставку на checkout и посмотрите, обновился ли список оплат без ручной перезагрузки;
  • создайте тестовый заказ и проверьте, что в админке нет несоответствия между доставкой и оплатой.

Если шлюз не скрывается, сначала проверьте, не кэшируется ли checkout сторонним плагином или CDN. Страница оформления заказа не должна обслуживаться агрессивным кэшем. Второй частый источник проблемы — неправильный ID метода доставки: визуально он выглядит как «Самовывоз», а в сессии хранится совсем другой ключ.

Частые ошибки и как их исправить

Сравнивают не тот идентификатор

Ошибка выглядит так: в коде сравнивают название метода, а WooCommerce передаёт технический ID. Исправление простое — сначала вывести значение из сессии, потом уже писать условие.

Проверяют оплату слишком рано

Если пытаться фильтровать шлюзы до того, как WooCommerce определил выбранную доставку, правило не сработает. Используйте фильтр woocommerce_available_payment_gateways, а не произвольный ранний хук в шаблоне.

Забывают про несколько пакетов доставки

В некоторых магазинах WooCommerce формирует несколько shipping packages. Тогда chosen_shipping_methods может содержать массив значений. Если у вас сложная логика, не полагайтесь на первый элемент без проверки структуры.

Ломают оплату в админке

Если не ограничить код фронтендом, можно случайно повлиять на экран редактирования заказа. Поэтому в примере выше есть проверка is_admin(). Для более сложных сценариев можно дополнительно исключить AJAX-запросы, если они не должны затрагиваться.

Практические советы по безопасности и производительности

Не храните такую логику в случайном сниппете без контроля версий. Для магазина лучше отдельный мини-плагин: его проще тестировать, отключать и переносить между окружениями. Если правило зависит от нескольких зон доставки и нескольких шлюзов, держите список ID в одном месте, а не размазывайте по шаблонам.

Ещё один полезный момент: не добавляйте десятки вложенных условий, если можно свести их к таблице соответствий. Это упрощает поддержку и снижает риск ошибки при добавлении нового способа доставки.

add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
    if ( is_admin() || ! function_exists( 'WC' ) || ! WC()->session ) {
        return $gateways;
    }

    $rules = array(
        'local_pickup:1' => array( 'stripe', 'cod' ),
        'flat_rate:3'    => array( 'cod' ),
    );

    $chosen_shipping = WC()->session->get( 'chosen_shipping_methods' );
    $chosen_shipping = is_array( $chosen_shipping ) ? reset( $chosen_shipping ) : '';

    if ( isset( $rules[ $chosen_shipping ] ) ) {
        foreach ( $rules[ $chosen_shipping ] as $gateway_id ) {
            unset( $gateways[ $gateway_id ] );
        }
    }

    return $gateways;
} );

Такой вариант проще расширять: добавили новый метод доставки — дописали одну строку в массиве, а не переписывали весь фильтр.

WooCommerce: как избежать повторного создания заказа при наличии активного
28.06.2026
Как сделать обязательное поле комментария в WooCommerce при оформлении заказа
12.08.2026
Как создать защищённые паролем страницы в WordPress
09.02.2026
Как добавить Custom Post Type в WordPress: подробное руководство с примерами
24.11.2025
WooCommerce: как запретить повторное создание заказа при наличии активного
05.08.2026