Сценарий знакомый: покупатель оплатил заказ, а WooCommerce сразу переводит его в статус processing («В обработке»), хотя вам нужен другой рабочий поток — например, оставить заказ в on-hold, отправить его на ручную проверку или не ломать интеграцию с внешней CRM. Проблема обычно не в одном месте: автопереход может быть вызван способом оплаты, настройками самого плагина, кастомным кодом темы или расширением для склада/доставки.
Когда это действительно проблема
Автоматический переход статуса сам по себе не ошибка. Для цифровых товаров, мгновенной выдачи доступа или полностью автоматизированной логистики он часто полезен. Но если у вас есть хотя бы один из сценариев ниже, статус processing может мешать:
- заказ должен уходить на ручную проверку перед отгрузкой;
- оплата приходит, но товар резервируется только после подтверждения менеджером;
- внешняя система забирает заказы только из определённого статуса;
- нужно отдельно проверять риск-факторы: адрес, телефон, промокоды, повторные покупки;
- статус влияет на триггеры писем, складской учёт или вебхуки.
Диагностика: кто именно меняет статус
Прежде чем что-то отключать, стоит понять источник. В WooCommerce статус после оплаты может меняться по нескольким причинам:
1. Поведение платёжного шлюза
Некоторые методы оплаты сами переводят заказ в processing или completed, если считают оплату успешной. Это нормально для шлюза, но не всегда подходит вашему процессу.
2. Хук в теме или плагине
Частая практика — кастомный код на woocommerce_payment_complete, woocommerce_order_status_changed или woocommerce_payment_complete_order_status. Именно он может принудительно менять статус.
3. Плагин автоматизации
Плагины доставки, складского учёта, подписок и CRM иногда меняют статус сразу после оплаты, чтобы синхронизировать заказ с внешней системой.
4. Настройки самого WooCommerce
Для отдельных типов товаров WooCommerce может завершать заказ автоматически, если товар виртуальный или загружаемый. Это не всегда связано с тем, что вы видите на фронтенде, но поведение статуса меняется именно там.
Если нужно быстро проверить источник, включите логирование и временно добавьте отладочный код в functions.php дочерней темы или в небольшой mu-plugin.
add_action('woocommerce_order_status_changed', function($order_id, $old_status, $new_status, $order) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log(sprintf(
'Order #%d status changed: %s -> %s',
$order_id,
$old_status,
$new_status
));
}
}, 10, 4);Этот лог не покажет, кто именно вызвал изменение, но даст точку входа: после какой оплаты и в какой момент статус уходит в processing.
Как отключить автопереход: рабочие варианты
Ниже — три подхода. Выбор зависит от того, хотите ли вы полностью изменить поведение магазина или только для части заказов.
| Подход | Когда использовать | Плюсы | Минусы |
|---|---|---|---|
| Код через фильтр | Нужно точечно изменить статус после оплаты | Контроль, без лишних плагинов | Нужна проверка после обновлений |
| Настройка платёжного шлюза | Проблема только в одном способе оплаты | Чистое решение на уровне интеграции | Не все шлюзы дают такой параметр |
| Кастомный обработчик статуса | Нужна отдельная логика для разных товаров | Гибко для сложных магазинов | Сложнее сопровождать |
Вариант 1. Изменить статус после оплаты через фильтр
Если вам нужно, чтобы заказ после успешной оплаты не уходил в processing, а оставался, например, в on-hold, можно переопределить статус через фильтр woocommerce_payment_complete_order_status.
add_filter('woocommerce_payment_complete_order_status', function($status, $order_id, $order) {
if (! $order instanceof WC_Order) {
return $status;
}
// Пример: для всех заказов оставляем статус on-hold
return 'on-hold';
}, 10, 3);Это грубый вариант. На практике лучше ограничить его конкретными условиями: способом оплаты, категорией товара, суммой заказа или ролью пользователя.
add_filter('woocommerce_payment_complete_order_status', function($status, $order_id, $order) {
if (! $order instanceof WC_Order) {
return $status;
}
// Только для оплаты банковским переводом
if ($order->get_payment_method() === 'bacs') {
return 'on-hold';
}
// Для остальных заказов не вмешиваемся
return $status;
}, 10, 3);Вариант 2. Не давать шлюзу переводить заказ в processing
Если источник — конкретный платёжный плагин, у него может быть собственный фильтр или настройка. Здесь важно не гадать, а смотреть документацию именно этого шлюза. Универсального параметра для всех нет.
Если шлюз использует стандартный механизм WooCommerce, иногда достаточно перехватить статус на этапе завершения оплаты и вернуть нужное значение. Это безопаснее, чем пытаться править ядро или переопределять класс шлюза напрямую.
Вариант 3. Менять статус только для части товаров
Когда в одном магазине есть и цифровые, и физические товары, лучше не отключать автопереход глобально. Можно оставить processing только для тех заказов, где есть физическая отгрузка, а для остальных — свой статус.
add_filter('woocommerce_payment_complete_order_status', function($status, $order_id, $order) {
if (! $order instanceof WC_Order) {
return $status;
}
foreach ($order->get_items() as $item) {
$product = $item->get_product();
if ($product && ! $product->is_virtual()) {
return 'processing';
}
}
return 'on-hold';
}, 10, 3);Логика простая: если в заказе есть хотя бы один физический товар, оставляем стандартный рабочий статус. Если заказ состоит только из виртуальных позиций, отправляем его в ручную проверку.
Проверка результата после внедрения
После изменения кода не ограничивайтесь визуальной проверкой в админке. Нужны три теста:
- создайте тестовый заказ с нужным способом оплаты;
- выполните оплату и проверьте, какой статус получил заказ сразу после callback/redirect;
- посмотрите, не отправилось ли лишнее письмо клиенту или менеджеру;
- проверьте, не сломалась ли синхронизация с CRM, складом или сервисом доставки;
- если есть вебхуки, убедитесь, что они срабатывают на нужном статусе.
Удобно смотреть не только список заказов, но и историю статусов внутри карточки заказа. Если статус меняется дважды — сначала на нужный вам, а потом обратно на processing, значит, вмешивается ещё один обработчик.
Для дополнительной проверки можно временно добавить запись в лог при каждом изменении статуса:
add_action('woocommerce_order_status_changed', function($order_id, $old_status, $new_status) {
error_log(sprintf('Order %d: %s -> %s', $order_id, $old_status, $new_status));
}, 10, 3);Частые ошибки и как их исправить
Статус меняется, но письмо уже ушло
Это значит, что письмо привязано к другому хуку или срабатывает раньше вашего фильтра. Решение — проверить, не завязано ли уведомление на woocommerce_order_status_processing. Иногда нужно менять не только статус, но и условия отправки письма.
Код работает для части заказов, но не для всех
Чаще всего причина в том, что разные способы оплаты используют разные сценарии завершения платежа. Проверьте $order->get_payment_method() и убедитесь, что фильтр не пропускает нужный метод.
После обновления плагина всё вернулось обратно
Если вы правили файл плагина или родительской темы, обновление затрёт изменения. Перенесите код в дочернюю тему или в отдельный mu-plugin. Это не только надёжнее, но и проще для сопровождения.
Заказ зависает в неправильном статусе
Так бывает, если фильтр возвращает статус, который не соответствует логике магазина. Например, вы оставили заказ в on-hold, но не настроили ручную обработку менеджером. В итоге заказ не двигается дальше, хотя оплата уже прошла.
Что учесть по безопасности и производительности
Любой код, который вмешивается в статус заказа, должен быть предсказуемым. Не добавляйте в фильтр тяжёлые запросы к внешним API и не делайте там длинные циклы по базе. Фильтр вызывается в момент обработки оплаты, и лишняя задержка сразу бьёт по UX.
Если нужно принимать решение на основе внешней системы, лучше сначала сохранить заказ в промежуточный статус, а затем отдельным фоновым процессом обновить его после ответа сервиса. Для этого подходят стандартные механизмы WordPress cron или очередь самого плагина, если она есть.
Ещё один практический момент: не отключайте автопереход глобально, если магазин уже завязан на письма, склад или подписки. Сначала проверьте один способ оплаты на тестовом стенде. В WooCommerce статус — это не просто метка в админке, а триггер для нескольких процессов сразу.
Если нужен более аккуратный контроль над уведомлениями, статусами и дублями контента в админке, иногда удобнее закрыть часть задач плагином вроде Clearfy Pro, но именно для статусов заказов в WooCommerce всё равно чаще нужен точечный код, а не универсальная кнопка.