Типичный сценарий: у вас есть самовывоз, курьер и доставка транспортной компанией, а платить можно не везде одинаково. Например, при самовывозе нужен только наличный расчёт и оплата картой на месте, а при доставке курьером — только онлайн-оплата. Если не ограничить методы оплаты, покупатель увидит лишние варианты на этапе оформления заказа, а это часто приводит к ошибкам и брошенным корзинам.
В WooCommerce это решается двумя путями: через плагин или кодом. Если логика простая и завязана на несколько способов доставки, надёжнее сделать это через фильтр woocommerce_available_payment_gateways. Так вы контролируете поведение без лишней зависимости от стороннего расширения.
Когда проблема проявляется и что именно ломается
Обычно жалобы выглядят так: клиент выбирает доставку, но видит неподходящие способы оплаты; при смене доставки список оплат не обновляется; или в заказе остаётся метод оплаты, который не должен был быть доступен для выбранной зоны доставки. На практике это чаще всего связано не с багом WooCommerce, а с тем, что правила оплаты и доставки никак не связаны между собой.
Диагностика перед правкой
Сначала проверьте, как у вас называются методы доставки и какие ID они получают. В WooCommerce на checkout важны не названия, а идентификаторы вроде flat_rate:3, local_pickup:1 или free_shipping:2. Если вы будете сравнивать только текстовое название, правило быстро сломается после изменения настроек.
- Откройте страницу оформления заказа и выберите каждый способ доставки вручную.
- Посмотрите, какие способы оплаты показываются в каждом сценарии.
- Проверьте, есть ли у доставки разные instance ID в разных зонах.
- Убедитесь, что кэш страницы не фиксирует старый набор методов оплаты.
Если у вас включён кэш на checkout, сначала исключите из кэширования страницу оформления заказа и корзину. Иначе вы можете отлаживать не WooCommerce, а сохранённый HTML.
Решение через код: скрываем оплату по выбранной доставке
Ниже пример для темы или небольшого кастомного плагина. Он скрывает часть способов оплаты в зависимости от выбранного метода доставки. Логика простая: при самовывозе оставляем только наличные и оплату при получении, при курьерской доставке — только онлайн-эквайринг.
<?php
add_filter( 'woocommerce_available_payment_gateways', 'cyrtolat_filter_payment_gateways_by_shipping' );
function cyrtolat_filter_payment_gateways_by_shipping( $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 ) && ! empty( $chosen_methods[0] ) ? $chosen_methods[0] : '';
// Самовывоз
if ( strpos( $chosen_shipping, 'local_pickup' ) === 0 ) {
foreach ( $gateways as $gateway_id => $gateway ) {
if ( ! in_array( $gateway_id, array( 'cod', 'bacs' ), true ) ) {
unset( $gateways[ $gateway_id ] );
}
}
}
// Курьерская доставка
if ( strpos( $chosen_shipping, 'flat_rate' ) === 0 ) {
foreach ( $gateways as $gateway_id => $gateway ) {
if ( in_array( $gateway_id, array( 'cod' ), true ) ) {
unset( $gateways[ $gateway_id ] );
}
}
}
return $gateways;
}Этот код нужно адаптировать под ваши реальные ID доставок и оплат. Например, если у вас самовывоз должен разрешать только bacs, уберите cod из массива. Если курьерская доставка должна разрешать только stripe или другой онлайн-метод, оставьте только его.
Как не ошибиться с ID
У способов оплаты ID обычно совпадает с ID шлюза: cod, bacs, stripe, paypal и т.д. У доставки ID сложнее: это не только тип, но и instance, поэтому одно и то же flat_rate может существовать в нескольких зонах. Если нужно привязаться к конкретной зоне, сравнивайте полное значение из сессии, например flat_rate:3.
Если вы хотите ограничивать оплату не по типу доставки, а по конкретной зоне, используйте точное сравнение:
<?php
add_filter( 'woocommerce_available_payment_gateways', 'cyrtolat_filter_payment_gateways_by_shipping_instance' );
function cyrtolat_filter_payment_gateways_by_shipping_instance( $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 ) && ! empty( $chosen_methods[0] ) ? $chosen_methods[0] : '';
if ( $chosen_shipping === 'local_pickup:1' ) {
foreach ( $gateways as $gateway_id => $gateway ) {
if ( ! in_array( $gateway_id, array( 'cod', 'bacs' ), true ) ) {
unset( $gateways[ $gateway_id ] );
}
}
}
return $gateways;
}Какой вариант выбрать: код, плагин или настройка в платёжке
Если у вас один магазин и несколько понятных сценариев доставки, код обычно проще сопровождать. Если же логика завязана на десятки условий, регионы, суммы и группы клиентов, лучше смотреть в сторону специализированного плагина или отдельной бизнес-логики в расширении.
| Подход | Когда подходит | Минус |
|---|---|---|
| Код через фильтр | 2–5 понятных сценариев доставки и оплаты | Нужно следить за ID методов и обновлениями темы |
| Плагин | Нужен интерфейс для менеджера без правки кода | Дополнительная зависимость и риск конфликтов |
| Настройки платёжного шлюза | Ограничения уже предусмотрены самим шлюзом | Обычно покрывает только часть сценариев |
Если вы уже используете набор инструментов для чистки WooCommerce и SEO, иногда удобнее держать логику в одном месте, а не разносить её по нескольким плагинам. Но для связки доставки и оплаты отдельный маленький сниппет часто надёжнее большого комбайна.
Пошаговая настройка без лишних рисков
- Сохраните резервную копию файлов темы или вынесите код в мини-плагин.
- Определите реальные ID способов доставки и оплаты в вашем магазине.
- Добавьте фильтр
woocommerce_available_payment_gateways. - Проверьте сценарии в тестовом заказе: самовывоз, курьер, бесплатная доставка.
- Очистите кэш страницы оформления заказа, если он используется.
- Сделайте пробный заказ в каждом сценарии и убедитесь, что лишние шлюзы не отображаются.
Как проверить, что решение сработало
Проверка должна быть не визуальной, а сценарной. Откройте checkout в режиме инкогнито и последовательно меняйте доставку. После каждого изменения список способов оплаты должен обновляться без ручной перезагрузки страницы, если у вас стандартный checkout WooCommerce и включён AJAX-обновляемый блок доставки.
- При самовывозе видны только разрешённые методы оплаты.
- При курьерской доставке исчезают запрещённые методы.
- После оформления заказа в админке сохраняется корректный payment method.
- На мобильной версии поведение не отличается от десктопа.
Если список оплат не меняется, откройте консоль браузера и проверьте, нет ли JS-ошибок на checkout. Иногда проблема не в PHP-коде, а в скрипте темы или конфликте с оптимизацией JS.
Частые ошибки и как их исправить
Сравнивают название доставки вместо ID
Название можно изменить в настройках зоны доставки, а ID останется прежним. Используйте значение из сессии chosen_shipping_methods, а не текст из интерфейса.
Код добавили в functions.php дочерней темы, а потом обновили тему
Если правка лежит в родительской теме, она может исчезнуть. Для стабильности лучше использовать дочернюю тему или небольшой mu-plugin.
Не учли несколько зон доставки
Один и тот же тип доставки в разных зонах получает разные instance ID. Если ограничение должно работать только в конкретной зоне, сравнивайте полное значение, например flat_rate:3.
Checkout кэшируется
Если кэшируется страница оформления заказа, пользователь может видеть старый набор методов оплаты. Исключите /cart/ и /checkout/ из кэша и проверьте, не стоит ли агрессивная оптимизация HTML.
Безопасность и производительность
Не вставляйте такой код в произвольный плагин без понимания, как он загружается. Если логика критична для продаж, лучше оформить её как маленький кастомный плагин: так проще контролировать версию и не потерять код при смене темы. Сам фильтр лёгкий, но лишние проверки в нём не нужны — не делайте тяжёлые запросы к базе на каждом рендере checkout.
Если у вас много правил по доставке и оплате, держите их в одном месте и документируйте, какие ID чему соответствуют. Это экономит время при обновлении WooCommerce и снижает риск случайно открыть неподходящий шлюз для части заказов.
Для магазинов, где одновременно важны чистый checkout и контроль дублей/служебного мусора, полезно держать техдолг под контролем: меньше сторонних условий на странице оформления заказа, меньше конфликтов с кэшем и меньше сюрпризов после обновлений.