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

В WooCommerce иногда нужно не просто изменить статус заказа, а именно запретить повторную оплату для заказов, которые уже находятся в определённом состоянии. Типичный сценарий: заказ переведён в on-hold, processing или в кастомный статус, и дальше клиент не должен видеть способы оплаты на странице заказа или в личном кабинете.

Решение здесь зависит от того, где вы хотите отключить оплату: только на странице конкретного заказа, в checkout для части корзин или вообще для заказов с определённым статусом. Ниже — рабочий вариант для сценария с заказами, у которых уже есть статус, и проверка, что логика не ломает обычный checkout.

Когда это реально нужно

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

Типовые сценарии

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

Диагностика проблемы перед изменениями

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

Посмотрите:

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

Если проблема проявляется только на странице заказа, а checkout работает нормально, значит править нужно не список шлюзов в целом, а условия, при которых WooCommerce показывает оплату для конкретного заказа.

Рабочий способ через фильтр WooCommerce

Для страницы оплаты заказа удобно использовать фильтр woocommerce_valid_order_statuses_for_payment. Он определяет, для каких статусов WooCommerce считает оплату допустимой. Если убрать из списка нужный статус, кнопка оплаты и связанные действия перестанут отображаться для заказов в этом статусе.

Добавьте код в functions.php дочерней темы или в собственный мини-плагин:

add_filter( 'woocommerce_valid_order_statuses_for_payment', function( $statuses, $order ) {
    if ( ! $order instanceof WC_Order ) {
        return $statuses;
    }

    // Для этих статусов повторная оплата не нужна.
    $blocked_statuses = array( 'processing', 'on-hold' );

    if ( in_array( $order->get_status(), $blocked_statuses, true ) ) {
        return array_diff( $statuses, $blocked_statuses );
    }

    return $statuses;
}, 10, 2 );

Этот вариант подходит, если вы хотите убрать возможность оплаты именно для уже созданного заказа. Но есть важная деталь: фильтр влияет на логику доступности оплаты, а не на сам статус заказа. Поэтому он не меняет данные в базе и не трогает checkout для новых заказов.

Если нужен кастомный статус

Если у вас свой статус, например awaiting-review, его тоже можно исключить. Главное — использовать реальный slug статуса, который зарегистрирован в системе.

add_filter( 'woocommerce_valid_order_statuses_for_payment', function( $statuses, $order ) {
    if ( ! $order instanceof WC_Order ) {
        return $statuses;
    }

    $blocked_statuses = array( 'awaiting-review' );

    if ( in_array( $order->get_status(), $blocked_statuses, true ) ) {
        return array_diff( $statuses, $blocked_statuses );
    }

    return $statuses;
}, 10, 2 );

Если нужно скрыть оплату только для части способов

Иногда задача не в полном запрете оплаты, а в том, чтобы убрать конкретный шлюз. Например, для заказов со статусом on-hold оставить только банковский перевод, а карту скрыть. Тогда удобнее использовать фильтр woocommerce_available_payment_gateways.

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

    if ( ! function_exists( 'is_wc_endpoint_url' ) || ! is_wc_endpoint_url( 'order-pay' ) ) {
        return $gateways;
    }

    $order_id = absint( get_query_var( 'order-pay' ) );
    if ( ! $order_id ) {
        return $gateways;
    }

    $order = wc_get_order( $order_id );
    if ( ! $order ) {
        return $gateways;
    }

    if ( 'on-hold' === $order->get_status() ) {
        unset( $gateways['cod'] );
        unset( $gateways['stripe'] );
    }

    return $gateways;
} );

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

Сравнение подходов

ПодходЧто делаетКогда использоватьОграничение
Фильтр woocommerce_valid_order_statuses_for_paymentОтключает оплату для заказа по статусуНужно убрать кнопку оплаты целикомНе управляет отдельными шлюзами
Фильтр woocommerce_available_payment_gatewaysСкрывает выбранные методы оплатыНужно оставить часть способов оплатыНадо аккуратно проверять контекст страницы
Изменение шаблоновМеняет вывод кнопок и сообщенийНужна кастомная вёрсткаСложнее поддерживать после обновлений

Пошаговое внедрение без сюрпризов

  1. Определите статус заказа, для которого оплата должна быть недоступна.
  2. Проверьте, нужен ли полный запрет оплаты или только скрытие отдельных шлюзов.
  3. Добавьте код в дочернюю тему или в отдельный мини-плагин.
  4. Очистите кеш, если у вас есть кеширование страниц личного кабинета.
  5. Протестируйте заказ в нужном статусе под обычным клиентом, а не из админки.

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

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

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

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

Дополнительно откройте страницу заказа в личном кабинете и проверьте HTML: если кнопка скрыта, но ссылка на оплату осталась в разметке, значит где-то вмешивается тема или шаблон WooCommerce. Тогда нужно смотреть переопределённые шаблоны в теме и плагины, которые модифицируют страницу заказа.

Полезно также включить логирование WooCommerce на время теста и посмотреть, не появляются ли ошибки при открытии страницы оплаты. Если ошибка возникает только для конкретного шлюза, проблема может быть не в статусе, а в самом платёжном плагине.

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

Используют не тот slug статуса

В админке статус может отображаться как «В обработке», но в коде он называется processing. Если подставить русское название, условие не сработает. Проверяйте именно внутренний slug.

Ломают checkout вместо страницы заказа

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

Не учитывают кеш

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

Скрывают шлюз без проверки ID

Неверный идентификатор платёжного метода приводит к тому, что код вроде бы работает, но ничего не меняет. Сначала проверьте ID шлюза в настройках или в документации плагина оплаты.

Безопасность и производительность

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

Если вы используете кастомные статусы и дополнительные проверки, не делайте тяжёлые запросы к базе на каждом открытии страницы заказа. Для этой задачи достаточно объекта WC_Order и проверки статуса через get_status().

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

Что делать, если нужен более гибкий сценарий

Иногда правило зависит не только от статуса, но и от суммы заказа, способа доставки или роли пользователя. Тогда лучше вынести условие в отдельную функцию и использовать её в фильтре. Это проще поддерживать, чем размазывать проверки по нескольким местам.

function wpbegin_disable_payment_for_order( WC_Order $order ): bool {
    if ( in_array( $order->get_status(), array( 'on-hold', 'awaiting-review' ), true ) ) {
        return true;
    }

    if ( (float) $order->get_total() > 100000 ) {
        return true;
    }

    return false;
}

add_filter( 'woocommerce_valid_order_statuses_for_payment', function( $statuses, $order ) {
    if ( $order instanceof WC_Order && wpbegin_disable_payment_for_order( $order ) ) {
        return array();
    }

    return $statuses;
}, 10, 2 );

Такой подход удобен, когда правило меняется со временем. Вы правите одну функцию, а не переписываете логику в нескольких фильтрах.

Динамическая система оценок в WordPress с использованием AJAX
14.04.2026
WooCommerce: автоматическое удаление неоплаченных заказов через время
01.08.2026
WooCommerce: как автоматически удалять заказы со статусом «Отменен»
25.05.2026
Как создать Custom Post Type с дополнительными метаданными в WordPress
23.12.2025
Как отключить автоматическое обновление плагинов в WordPress
08.12.2025