Сценарий типичный: в магазине есть категории товаров, для которых нельзя принимать часть оплат. Например, для цифровых товаров не нужен наложенный платёж, а для хрупких или дорогих позиций вы хотите убрать оплату при получении. В WooCommerce это лучше решать на уровне логики корзины и checkout, а не вручную в каждом заказе.
Ниже — рабочий способ через фильтр woocommerce_available_payment_gateways. Он не требует отдельного плагина и позволяет точно задать правило: если в корзине есть товар из нужной категории, скрыть конкретные способы оплаты.
Когда это действительно нужно
Ограничение платёжных методов по категориям полезно, когда правила зависят не от всей корзины, а от состава товаров. Это встречается чаще, чем кажется:
- для цифровых товаров нужно убрать оплату при получении;
- для предзаказов — оставить только предоплату;
- для крупногабаритных товаров — отключить методы, которые не поддерживает логистика;
- для B2B-категорий — показать только безналичный расчёт;
- для акционных наборов — запретить методы, которые конфликтуют с условиями продажи.
Диагностика проблемы перед изменениями
Сначала проверьте, где именно ломается логика. Частая ошибка — пытаться скрыть оплату на странице товара, хотя WooCommerce принимает решение уже на этапе корзины и оформления заказа.
Что проверить в админке и в теме
- какие категории назначены товарам в корзине;
- какие способы оплаты включены в WooCommerce → Настройки → Платежи;
- не переопределяет ли тема шаблон checkout;
- нет ли плагина, который уже фильтрует платёжные методы;
- не кэшируется ли checkout сторонним плагином или CDN.
Если правило не срабатывает, сначала проверьте, видит ли код нужную категорию у товара в корзине. Для этого удобно временно записать состав корзины в лог.
add_action('woocommerce_before_checkout_form', function () {
if ( ! function_exists('WC') || ! WC()->cart ) {
return;
}
foreach ( WC()->cart->get_cart() as $item ) {
$product = $item['data'];
if ( $product ) {
error_log('Cart product ID: ' . $product->get_id());
error_log('Categories: ' . implode(', ', wp_get_post_terms($product->get_id(), 'product_cat', ['fields' => 'names'])));
}
}
});Этот фрагмент не нужен в продакшене постоянно. Он помогает понять, какие товары реально попадают в корзину и какие термины у них назначены.
Решение через фильтр доступных способов оплаты
Самый надёжный вариант — пройтись по товарам в корзине, проверить наличие нужной категории и убрать конкретные gateways из массива доступных методов. Логику лучше держать в дочерней теме или в небольшом mu-plugin, чтобы она не пропала после обновления темы.
Пример: скрыть наложенный платёж для категории digital
add_filter('woocommerce_available_payment_gateways', function ($gateways) {
if ( is_admin() && ! wp_doing_ajax() ) {
return $gateways;
}
if ( ! function_exists('WC') || ! WC()->cart ) {
return $gateways;
}
$restricted_category = 'digital';
$payment_methods_to_hide = ['cod'];
$has_restricted_category = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term($restricted_category, 'product_cat', $product_id) ) {
$has_restricted_category = true;
break;
}
}
if ( ! $has_restricted_category ) {
return $gateways;
}
foreach ( $payment_methods_to_hide as $method_id ) {
if ( isset($gateways[$method_id]) ) {
unset($gateways[$method_id]);
}
}
return $gateways;
});Здесь cod — стандартный ID метода «Оплата при доставке». Если вы скрываете другой шлюз, подставьте его реальный ID. Его можно увидеть в настройках платежей или в коде плагина шлюза.
Если нужно ограничить несколько категорий и несколько методов
Когда правил больше одного, удобнее хранить их в массиве. Так код проще поддерживать и расширять без переписывания логики.
add_filter('woocommerce_available_payment_gateways', function ($gateways) {
if ( is_admin() && ! wp_doing_ajax() ) {
return $gateways;
}
if ( ! function_exists('WC') || ! WC()->cart ) {
return $gateways;
}
$rules = [
'digital' => ['cod'],
'b2b' => ['paypal', 'cod'],
'preorder'=> ['cod'],
];
$matched_methods = [];
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
foreach ( $rules as $category_slug => $methods ) {
if ( has_term($category_slug, 'product_cat', $product_id) ) {
$matched_methods = array_merge($matched_methods, $methods);
}
}
}
$matched_methods = array_unique($matched_methods);
foreach ( $matched_methods as $method_id ) {
if ( isset($gateways[$method_id]) ) {
unset($gateways[$method_id]);
}
}
return $gateways;
});Этот вариант удобен, если у вас несколько бизнес-правил и они могут пересекаться. Например, один товар может одновременно относиться к категории b2b и preorder.
Плагин, код или гибридный подход
Если задача простая и правила не меняются часто, код обычно надёжнее. Если менеджеры магазина сами должны переключать условия без разработчика, тогда имеет смысл смотреть в сторону плагина с условиями для checkout. Но у плагинов есть компромисс: они добавляют ещё один слой логики и могут конфликтовать с другими расширениями.
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Код в теме / mu-plugin | Правило одно или несколько, логика стабильная | Прозрачно, быстро, без лишних зависимостей | Нужен разработчик для правок |
| Плагин условий оплаты | Правила часто меняются менеджером | Удобный интерфейс, меньше кода | Риск конфликтов, лишняя нагрузка |
| Гибрид | Базовая логика в коде, исключения в плагине | Баланс контроля и удобства | Сложнее поддерживать |
Как проверить, что всё работает
Проверка должна быть не формальной, а по сценарию покупки. Не ограничивайтесь просмотром страницы товара.
- Добавьте в корзину товар из целевой категории.
- Откройте checkout в режиме инкогнито или после очистки сессии.
- Проверьте, что скрытый способ оплаты не отображается.
- Добавьте товар из обычной категории и убедитесь, что метод снова доступен.
- Если в корзине смешанные товары, проверьте, срабатывает ли правило на весь заказ.
Если используете кэширование, тестируйте именно на реальном checkout URL, а не на закэшированной странице. Для WooCommerce это особенно важно: платёжные методы зависят от содержимого корзины и не должны отдаваться из статического кэша.
Частые ошибки и как их исправить
Неправильный ID платёжного метода
В коде часто указывают название метода вместо его ID. В массиве $gateways ключи — это именно идентификаторы шлюзов. Если вы укажете не тот ключ, метод не скроется.
Проверка категории по неправильному полю
У товара в корзине есть product_id, а у вариации — отдельный variation_id. Если правило должно работать для вариативных товаров, проверяйте именно родительский товар или учитывайте оба ID, в зависимости от структуры категорий.
Срабатывание в админке
Если не добавить защиту is_admin() и wp_doing_ajax(), можно случайно сломать отображение методов оплаты в бэкенде или в AJAX-обновлении checkout.
Конфликт с другим плагином
Некоторые плагины оплаты тоже фильтруют woocommerce_available_payment_gateways. Если ваш метод исчезает не всегда, временно отключите сторонние расширения и проверьте поведение на чистом WooCommerce.
Практические советы по безопасности и поддержке
Не вставляйте такой код в файл functions.php активной родительской темы, если тема часто обновляется. Лучше использовать дочернюю тему или отдельный mu-plugin. Тогда правило не исчезнет после обновления и его проще перенести между проектами.
Если у вас несколько условий для checkout, держите их в одном небольшом файле и комментируйте бизнес-логику. Через полгода это сэкономит время больше, чем кажется.
- не хардкодьте названия категорий, если в проекте уже есть соглашение по slug;
- проверяйте поведение на товарах-variations и grouped products;
- не кэшируйте checkout как обычную страницу;
- после обновления платёжного плагина перепроверьте ID шлюза;
- если правило зависит от региона доставки, тестируйте связку «категория + адрес + способ доставки».
Если нужен более широкий контроль над техническими настройками магазина, в экосистеме WPShop есть Clearfy Pro: он полезен для чистки лишнего и снижения количества конфликтов на сайте, но саму логику ограничений оплаты всё равно лучше держать в коде, а не в оптимизаторе.
После внедрения ещё раз проверьте корзину с каждой проблемной категорией, затем сделайте тестовый заказ в песочнице платёжного шлюза. Если метод скрывается только на части сценариев, значит правило нужно уточнить: по категории, по тегу товара, по роли пользователя или по сумме заказа.