В WooCommerce статус заказа после оплаты меняется не «сам по себе», а по логике шлюза оплаты и самого магазина. Чаще всего проблема выглядит так: клиент оплатил заказ, а вместо нужного вам статуса заказ уходит в processing или сразу в completed. Для магазина с цифровыми товарами, предзаказами, ручной проверкой или нестандартной логистикой это неудобно: менеджер теряет контроль над обработкой, а автоматические письма и интеграции с CRM начинают срабатывать раньше времени.
Ниже — практический разбор, как понять источник изменения статуса и как отключить или переопределить его без ломки checkout и без правки ядра WooCommerce.
Когда WooCommerce меняет статус автоматически
После успешной оплаты WooCommerce опирается на тип товара, способ оплаты и код шлюза. Условно поведение делится на три сценария:
- Заказ уходит в
processing— обычно для физических товаров, которые нужно собирать и отправлять. - Заказ уходит в
completed— часто для цифровых товаров, когда доставка не требуется. - Статус меняет сам платежный плагин — например, после callback/webhook от банка или платежной системы.
Если вы хотите, чтобы после оплаты заказ оставался, например, в on-hold или переходил в кастомный статус, нужно смотреть не только на WooCommerce, но и на логику конкретного платежного метода.
Диагностика: кто именно меняет статус
Перед правкой кода важно понять, где происходит переключение. Иначе можно отключить одно место, а статус продолжит меняться в другом.
Проверяем журнал заказов и логи шлюза
Откройте заказ в админке и посмотрите историю статусов. Если статус меняется сразу после возврата с платежной страницы — это обычно логика шлюза. Если через несколько секунд или минут — вероятен webhook или фоновая обработка.
Дальше проверьте:
- WooCommerce → Статус → Логи — если шлюз пишет в лог, там часто видно, какой метод вызвал обновление.
- Настройки платежного плагина — некоторые шлюзы имеют отдельный параметр вроде «автоматически завершать заказы».
- Кастомные хуки в теме или плагинах — ищите вызовы
update_status(),payment_complete(),set_status().
Быстрый способ понять источник через отладочный хук
Если нужно быстро увидеть, когда заказ меняет статус, добавьте временный лог в functions.php дочерней темы или в небольшой mu-plugin:
add_action( 'woocommerce_order_status_changed', function( $order_id, $old_status, $new_status, $order ) {
if ( ! $order instanceof WC_Order ) {
return;
}
error_log( sprintf(
'Order #%d status changed: %s => %s, payment method: %s',
$order_id,
$old_status,
$new_status,
$order->get_payment_method()
) );
}, 10, 4 );После этого оплатите тестовый заказ и посмотрите debug.log. Если изменение происходит сразу после payment_complete(), значит нужно вмешиваться в логику оплаты. Если статус меняется позже, ищите webhook или отдельный обработчик плагина.
Как отключить автоматическое изменение статуса после оплаты
Самый безопасный путь — не трогать ядро WooCommerce, а переопределить статус после оплаты через фильтр. Важно: этот способ не отменяет саму оплату, он только меняет статус заказа после успешного платежа.
Вариант 1: оставить все оплаченные заказы в on-hold
Подходит, если вам нужна ручная проверка каждого платежа. Например, для дорогих товаров, предзаказов или заказов с дополнительной верификацией.
add_filter( 'woocommerce_payment_complete_order_status', function( $status, $order_id, $order ) {
if ( ! $order instanceof WC_Order ) {
return $status;
}
return 'on-hold';
}, 10, 3 );Что делает этот код: после успешной оплаты WooCommerce не переводит заказ в processing или completed, а оставляет его на ручной контроль.
Вариант 2: вернуть кастомный статус
Если у вас уже есть кастомный статус заказа, можно вернуть его вместо стандартного. Например, если вы используете статус awaiting-review:
add_filter( 'woocommerce_payment_complete_order_status', function( $status, $order_id, $order ) {
if ( ! $order instanceof WC_Order ) {
return $status;
}
return 'awaiting-review';
}, 10, 3 );Но здесь есть важный нюанс: статус должен быть зарегистрирован в WooCommerce. Если его нет, заказ может вести себя непредсказуемо в админке и в письмах.
Вариант 3: отключить автозавершение только для отдельных способов оплаты
Иногда менять поведение нужно не для всех заказов, а только для конкретного шлюза, например для bacs или локального метода оплаты. Тогда фильтр можно ограничить по способу оплаты:
add_filter( 'woocommerce_payment_complete_order_status', function( $status, $order_id, $order ) {
if ( ! $order instanceof WC_Order ) {
return $status;
}
$payment_method = $order->get_payment_method();
if ( in_array( $payment_method, array( 'bacs', 'cod' ), true ) ) {
return 'on-hold';
}
return $status;
}, 10, 3 );Если статус меняет платежный плагин, а не WooCommerce
Это частая ситуация с банковскими эквайрингами, локальными шлюзами и сервисами, которые отправляют webhook. В таком случае фильтр woocommerce_payment_complete_order_status может не помочь, потому что плагин сам вызывает update_status() после подтверждения платежа.
Что делать:
- Проверьте настройки шлюза — иногда есть опция вроде «автоматически завершать заказы».
- Посмотрите документацию плагина на наличие собственного фильтра статуса.
- Если фильтра нет, перехватывайте изменение статуса через общий хук и возвращайте нужное состояние в своей логике.
Ниже пример, когда заказ переводится в completed, но вы хотите вернуть его в processing для физической отгрузки. Делать это нужно аккуратно, чтобы не зациклить обновления:
add_action( 'woocommerce_order_status_completed', function( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
if ( $order->get_payment_method() === 'your_gateway' ) {
remove_action( 'woocommerce_order_status_completed', __FUNCTION__ );
$order->update_status( 'processing', 'Статус скорректирован после оплаты.' );
}
}, 10, 1 );Этот пример рабочий по идее, но использовать его стоит только если вы понимаете, что именно делает шлюз. Лучше сначала найти настройку или фильтр самого плагина оплаты.
Сравнение подходов
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Настройка платежного плагина | Если шлюз умеет управлять статусом | Без кода, меньше рисков | Не у всех плагинов есть такая опция |
Фильтр woocommerce_payment_complete_order_status | Если нужно изменить статус после оплаты глобально или по методам оплаты | Просто внедрить, не трогает ядро | Не сработает, если статус меняет сам шлюз позже |
| Перехват через action/status hooks | Если плагин оплаты жестко меняет статус | Можно точечно исправить поведение | Нужно аккуратно избегать циклов и дублей |
Пошаговое решение без лишнего риска
- Сделайте тестовый заказ в staging-окружении.
- Определите, кто меняет статус: WooCommerce или платежный плагин.
- Если есть настройка в шлюзе — используйте ее первой.
- Если настройки нет, добавьте фильтр
woocommerce_payment_complete_order_status. - Проверьте письма, вебхуки и интеграции с CRM после изменения.
- Только после этого переносите правку на боевой сайт.
Как проверить, что решение сработало
Проверка должна быть не только визуальной в админке. После внедрения убедитесь в трех вещах:
- Статус заказа остается тем, который вы задали в коде или настройке.
- Письма WooCommerce не уходят раньше времени, если они завязаны на смену статуса.
- Интеграции с CRM, складом или доставкой не получают ложный сигнал о завершении заказа.
Практический чек-лист:
- создать тестовый заказ;
- оплатить его тестовым способом;
- проверить статус в админке;
- посмотреть запись в
debug.log; - убедиться, что webhook платежного шлюза не возвращает заказ в другой статус;
- проверить, не сломалась ли логика возвратов и ручной обработки.
Частые ошибки и как их исправить
Фильтр добавили, но статус все равно меняется
Значит, изменение делает не WooCommerce, а платежный плагин после callback/webhook. Ищите собственные настройки шлюза или его хуки.
Возвращаете несуществующий статус
Если статус не зарегистрирован, заказ может отображаться некорректно. Перед использованием кастомного статуса убедитесь, что он добавлен через register_post_status() и отображается в списке статусов WooCommerce.
Случайно ломаете email-уведомления
Многие письма завязаны на переходы между статусами. Если вы оставляете заказ в on-hold, а раньше он уходил в completed, проверьте, какие письма должны отправляться вручную, а какие — автоматически.
Правите файл темы напрямую
После обновления темы изменения пропадут. Для такой логики лучше использовать дочернюю тему, mu-plugin или небольшой кастомный плагин.
Безопасность и производительность
Сам код для смены статуса легкий, но проблема обычно не в нем, а в сопутствующей логике: логировании, webhook-обработчиках и повторных запросах от платежной системы. Не пишите отладку в продакшн без необходимости и не оставляйте временные error_log() на постоянной основе.
Если на сайте много заказов и интеграций, держите изменения в отдельном мини-плагине. Так проще отключить правку, если платежный шлюз обновится и начнет вести себя иначе. Для чистки лишней логики и дублей в WooCommerce иногда помогает аудит плагинов и настроек, а не только код; в таких задачах полезны инструменты вроде Clearfy Pro, если они уже используются в проекте, но саму логику статуса заказа все равно лучше решать точечно.
Главная идея простая: сначала выясняем, кто именно меняет статус, потом меняем только этот участок. Тогда WooCommerce не превращается в набор случайных костылей, а поведение заказов остается предсказуемым.