wp-lessons.ru wordpress WP-Lessons

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

Сценарий типичный: товар есть в каталоге, карточка открывается, но остаток на складе уже 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;
} );

Такой подход удобнее, чем глобально резать все способы оплаты. Он даёт контроль на уровне бизнес-правил, а не только по признаку «товар закончился».

Проверка результата после внедрения

После добавления кода нужно проверить не только визуально, но и по факту формирования заказа.

  1. Добавьте в корзину товар с остатком 0.
  2. Откройте страницу оформления заказа в приватном окне.
  3. Убедитесь, что нужные способы оплаты скрылись.
  4. Попробуйте сменить товар в корзине на обычный и обновить checkout.
  5. Проверьте, что при изменении состава корзины список способов оплаты пересчитывается.

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

×
Прокачай свой WordPress!

Скидка -20% на премиум темы и плагины

Воспользоваться сейчас ⋙