Сценарий типичный: товар есть в каталоге, карточка открывается, но остаток на складе уже 0. При этом покупатель всё равно доходит до оформления и видит оплату, хотя заказ по факту выполнить нельзя. В WooCommerce это обычно решают не через «магическую» настройку, а через логику на уровне доступности способов оплаты.
Ниже разберём рабочий вариант без выдуманных хуков: будем отключать конкретные методы оплаты на этапе фильтрации, если в корзине есть товары с нулевым остатком. Это полезно, когда у вас есть предоплата, оплата при получении, банковский перевод и нужно оставить только те варианты, которые реально допустимы для текущего заказа.
Когда проблема проявляется на практике
Чаще всего это всплывает в одном из таких сценариев:
- товар заканчивается, но карточка ещё доступна из-за кеша или задержки синхронизации;
- в корзине есть несколько позиций, и хотя одна из них уже недоступна, способы оплаты не меняются;
- нужно скрывать оплату при нулевом остатке только для части способов, а не для всех;
- магазин работает с предзаказами, и логика «нет остатка — нет оплаты» должна применяться только к обычным товарам.
Что проверить до внедрения
Перед правкой кода стоит быстро посмотреть, как у вас сейчас настроен склад в WooCommerce:
- включён ли учёт запасов в WooCommerce → Настройки → Товары → Запасы;
- используется ли статус
outofstockу товара; - не включены ли предзаказы или сторонний плагин резерва;
- не переопределяет ли тему шаблоны checkout и cart;
- не кэшируется ли страница оформления заказа агрессивным плагином или серверным кешем.
Если товар помечен как отсутствующий, но в корзине всё равно доступны все способы оплаты, значит проблема не в карточке товара, а в логике доступности payment gateways.
Диагностика: где именно ломается логика
В WooCommerce доступные методы оплаты можно фильтровать через woocommerce_available_payment_gateways. Это удобная точка, потому что она срабатывает на этапе формирования списка способов оплаты на checkout.
Сначала полезно убедиться, что в корзине действительно есть товар с нулевым остатком. Для быстрой диагностики можно временно вывести данные в лог:
add_action( 'woocommerce_before_checkout_form', function () {
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
return;
}
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
if ( ! $product instanceof WC_Product ) {
continue;
}
error_log( sprintf(
'Product ID %d, stock status: %s, stock quantity: %s',
$product->get_id(),
$product->get_stock_status(),
$product->get_stock_quantity() === null ? 'null' : (string) $product->get_stock_quantity()
) );
}
} );Если в логах видно outofstock или stock_quantity = 0, а checkout не меняется, значит можно переходить к фильтрации методов оплаты.
Пошаговое решение через фильтр payment gateways
Ниже пример, который отключает выбранные способы оплаты, если в корзине есть хотя бы один товар без остатка. Код лучше добавить в мини-плагин или в functions.php дочерней темы, если у вас нет отдельного места для кастомной логики.
add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
if ( is_admin() ) {
return $gateways;
}
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
return $gateways;
}
$has_out_of_stock_item = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( empty( $cart_item['data'] ) || ! $cart_item['data'] instanceof WC_Product ) {
continue;
}
$product = $cart_item['data'];
if ( $product->managing_stock() && (int) $product->get_stock_quantity() <= 0 ) {
$has_out_of_stock_item = true;
break;
}
if ( ! $product->is_in_stock() ) {
$has_out_of_stock_item = true;
break;
}
}
if ( $has_out_of_stock_item ) {
// Оставляем только банковский перевод, если он нужен для таких заказов.
unset( $gateways['cod'] );
unset( $gateways['stripe'] );
unset( $gateways['paypal'] );
}
return $gateways;
} );Здесь важно не копировать код вслепую. Идентификаторы cod, stripe, paypal зависят от конкретных плагинов оплаты. У вас они могут называться иначе. Перед удалением проверьте ключи массива $gateways.
Как узнать ID способов оплаты
Самый простой способ — временно вывести ключи в лог:
add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
error_log( 'Payment gateways: ' . implode( ', ', array_keys( $gateways ) ) );
return $gateways;
} );После этого откройте checkout и посмотрите debug.log. Так вы увидите реальные ID, которые нужно отключать.
Если нужно отключать оплату только для части товаров
Иногда логика сложнее: например, обычные товары можно оплачивать картой, а товары с нулевым остатком — только по счёту. Тогда лучше проверять не весь заказ, а конкретный тип товара, категорию или мета-данные.
Пример: отключаем онлайн-оплату только если в корзине есть товар из категории preorder и остаток у него нулевой.
add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
return $gateways;
}
$block_online_payment = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
if ( ! $product instanceof WC_Product ) {
continue;
}
if ( has_term( 'preorder', 'product_cat', $product->get_id() ) && ! $product->is_in_stock() ) {
$block_online_payment = true;
break;
}
}
if ( $block_online_payment ) {
unset( $gateways['stripe'] );
unset( $gateways['paypal'] );
}
return $gateways;
} );Такой подход удобнее, чем глобально резать все способы оплаты. Он даёт контроль на уровне бизнес-правил, а не только по признаку «товар закончился».
Проверка результата после внедрения
После добавления кода нужно проверить не только визуально, но и по факту формирования заказа.
- Добавьте в корзину товар с остатком
0. - Откройте страницу оформления заказа в приватном окне.
- Убедитесь, что нужные способы оплаты скрылись.
- Попробуйте сменить товар в корзине на обычный и обновить checkout.
- Проверьте, что при изменении состава корзины список способов оплаты пересчитывается.
Если способы оплаты не меняются сразу, проверьте кеширование checkout-страницы. Для оформления заказа кеш обычно нужно отключать полностью, иначе фильтр может отрабатывать, но пользователь будет видеть старую версию страницы.
Дополнительно полезно проверить заказ в админке: способ оплаты должен соответствовать тому, что реально был доступен на checkout. Если заказ создаётся с неподходящим методом, значит фильтр срабатывает слишком поздно или конфликтует с другим плагином.
Частые ошибки и как их исправить
- Используют не тот ID метода оплаты. Решение: вывести
array_keys( $gateways )в лог и сверить ключи. - Проверяют только
get_stock_quantity(). У товара может быть включён учёт склада, но количество будетnull. Надёжнее сочетатьmanaging_stock()иis_in_stock(). - Добавляют код в родительскую тему. После обновления он исчезнет. Лучше мини-плагин или дочерняя тема.
- Кэшируют checkout. Тогда список оплат не обновляется. Для checkout кеш отключают.
- Не учитывают предзаказы. Если у вас есть товары под заказ, правило «нет остатка — нет оплаты» может быть слишком жёстким.
Сравнение подходов: плагин, код или гибрид
| Подход | Когда подходит | Минус |
|---|---|---|
| Плагин для условной логики оплаты | Если нужно быстро без разработки | Меньше контроля, возможны лишние зависимости |
Код через woocommerce_available_payment_gateways | Если правило простое и понятно | Нужно поддерживать вручную |
| Гибрид: код + настройки категорий/мета | Если логика зависит от типа товара | Требует аккуратной настройки данных |
Безопасность и производительность
Если вы добавляете такую логику на живой магазин, не забывайте про базовые вещи:
- не вставляйте код напрямую в произвольный плагин, который потом может отключиться;
- проверяйте наличие
WC()иWC()->cart, чтобы не ловить ошибки вне фронтенда; - не делайте тяжёлые запросы к базе внутри фильтра оплаты;
- если правило зависит от мета-данных, заранее продумайте индексацию и структуру данных;
- после изменений протестируйте checkout на мобильном и в приватном окне.
Если вам нужно не только скрывать оплату, но и чистить лишние дубли, мета-данные или мусор в WooCommerce-установке, такие задачи удобнее закрывать отдельными инструментами вроде Clearfy Pro: https://wpshop.ru/plugins/clearfy. Но саму логику доступности оплаты всё равно лучше держать в коде, чтобы она была прозрачной и предсказуемой.
Если нужен более строгий сценарий, можно расширить проверку: отключать оплату не только при нулевом остатке, но и при статусе onbackorder, если ваш бизнес-процесс этого требует. Главное — не смешивать разные правила в одном условии без явной проверки, иначе потом сложно понять, почему у клиента пропала оплата.