В WooCommerce заказ может появляться ещё до финального подтверждения оплаты. Для части магазинов это удобно: есть резервирование, проще отлавливать брошенные корзины и строить аналитику. Но в реальных проектах это же поведение часто создаёт мусорные заказы, мешает интеграциям с CRM и ломает логику, если внешний сервис ждёт только оплаченные заказы.
Ниже — практический разбор: когда это действительно проблема, как проверить источник создания заказа и какие варианты отключения безопасны. Сразу оговорюсь: полностью «выключить создание заказа» без последствий нельзя в любой конфигурации. В WooCommerce checkout завязан на внутренний объект заказа, и задача обычно сводится не к полному запрету, а к переносу создания заказа на более поздний этап или к очистке промежуточных записей.
Когда это становится проблемой
Сценарий типичный: пользователь открыл оформление, заполнил часть полей, ушёл, а в админке уже появился заказ со статусом pending или failed. Если таких записей много, начинаются побочные эффекты:
- CRM получает лишние лиды и дублирует коммуникации;
- скрипты доставки или оплаты срабатывают раньше времени;
- менеджеры видят «заказы-призраки» и тратят время на ручную чистку;
- аналитика по конверсии и выручке искажается, если внешняя система считает все созданные заказы.
Отдельно это заметно на сайтах с нестабильной оплатой, редиректами на внешние шлюзы и кастомными checkout-полями. Там заказ создаётся, но пользователь не доходит до подтверждения, а запись уже живёт своей жизнью.
Диагностика: где именно создаётся заказ
Перед правкой кода полезно понять, на каком шаге WooCommerce создаёт запись. Самый простой способ — посмотреть, меняется ли статус заказа сразу после отправки формы checkout или только после возврата с платёжного шлюза.
Что проверить в админке и логах
- Появляется ли заказ после нажатия кнопки оформления, даже если оплата не завершена;
- какой у него статус:
pending,failed,on-hold; - есть ли в заказе метки от платёжного плагина или кастомного кода;
- не создаёт ли запись сторонний плагин доставки, подписок или CRM-интеграции.
Если у вас включён режим отладки WooCommerce, полезно посмотреть системные журналы в WooCommerce → Статус → Журналы. Но чаще всего достаточно временно поставить логирование на собственный хук и увидеть, когда вызывается создание заказа.
Мини-проверка через хук
Этот фрагмент можно временно добавить в functions.php дочерней темы или в небольшой mu-plugin. Он не меняет поведение, а только пишет в лог момент создания заказа.
add_action( 'woocommerce_checkout_create_order', function( $order, $data ) {
if ( function_exists( 'wc_get_logger' ) ) {
$logger = wc_get_logger();
$logger->info( 'Checkout order is being created: ' . $order->get_id(), array( 'source' => 'checkout-debug' ) );
}
}, 10, 2 );После отправки формы проверьте WooCommerce → Статус → Журналы и убедитесь, что заказ создаётся именно на этапе checkout, а не позже через внешний callback.
Как отключить раннее создание заказа: рабочие варианты
Здесь есть три подхода. Выбор зависит от того, что именно вы хотите получить в итоге.
| Подход | Что делает | Когда подходит |
|---|---|---|
| Код в теме или mu-plugin | Меняет логику checkout точечно | Если нужен контроль без лишних плагинов |
| Настройка платёжного плагина | Откладывает создание записи до callback | Если проблема в конкретном шлюзе |
| Очистка промежуточных заказов | Не убирает создание, но удаляет мусор | Если бизнес-процесс уже завязан на текущую схему |
Вариант 1. Перенести создание заказа на более поздний этап
Если у вас кастомный checkout или интеграция, иногда можно не создавать полноценный заказ до подтверждения оплаты. Для этого обычно используют фильтры и собственную логику, но важно понимать: WooCommerce core не рассчитан на полный отказ от объекта заказа в стандартном checkout. Поэтому безопаснее менять не сам факт создания, а момент, когда заказ считается рабочим для внешних систем.
Практичный вариант — не отправлять данные в CRM и не запускать внешние процессы, пока заказ не перешёл в нужный статус. Например, только после processing или completed.
add_action( 'woocommerce_order_status_processing', 'my_send_order_to_crm' );
add_action( 'woocommerce_order_status_completed', 'my_send_order_to_crm' );
function my_send_order_to_crm( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
// Здесь отправляйте только подтверждённые заказы.
// Например: API-запрос в CRM, склад или ERP.
}Это не отключает создание заказа, но убирает основную боль: внешние системы перестают реагировать на незавершённые попытки оформления.
Вариант 2. Не создавать дубли при повторной отправке checkout
Частая причина «лишних» заказов — повторный сабмит формы. Пользователь нажимает кнопку дважды, страница подвисает, платёжный шлюз отвечает медленно, и WooCommerce получает несколько запросов подряд. В таких случаях полезно добавить простую серверную защиту от повторной отправки.
add_action( 'woocommerce_checkout_process', function() {
if ( ! empty( $_POST['woocommerce-process-checkout-nonce'] ) ) {
$nonce = sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) );
if ( ! wp_verify_nonce( $nonce, 'woocommerce-process_checkout' ) ) {
wc_add_notice( 'Не удалось проверить запрос оформления заказа.', 'error' );
}
}
} );Этот пример не отменяет checkout, а лишь показывает, как важно не полагаться только на фронтенд. Если проблема именно в дублях, дальше стоит смотреть в сторону блокировки повторной отправки кнопки на JS-уровне и проверки платёжного шлюза.
Вариант 3. Удалять незавершённые заказы по расписанию
Если бизнес-процесс уже использует стандартное создание заказа, а менять его рискованно, можно чистить записи со статусами pending и failed по расписанию. Это не «отключение», но на практике часто решает задачу без поломки checkout.
if ( ! wp_next_scheduled( 'my_cleanup_unfinished_orders' ) ) {
wp_schedule_event( time(), 'daily', 'my_cleanup_unfinished_orders' );
}
add_action( 'my_cleanup_unfinished_orders', function() {
$orders = wc_get_orders( array(
'status' => array( 'pending', 'failed' ),
'limit' => 50,
'return' => 'ids',
'orderby' => 'date',
'order' => 'ASC',
) );
foreach ( $orders as $order_id ) {
wp_delete_post( $order_id, true );
}
} );Перед удалением обязательно проверьте, не используются ли эти статусы для ручной обработки оплат или сверки с платёжным провайдером. В некоторых магазинах pending — это не мусор, а рабочая стадия.
Пошаговое решение для типового магазина
- Определите, что именно мешает: лишние записи, дубли, ранние интеграции или ошибки оплаты.
- Проверьте, создаётся ли заказ до редиректа на платёжный шлюз.
- Если проблема в CRM или webhook-логике, перенесите отправку данных на статус
processingилиcompleted. - Если проблема в дублях, добавьте защиту от повторной отправки формы и проверьте платёжный плагин.
- Если нужны только чистые данные в админке, настройте регулярную очистку незавершённых заказов.
Для большинства проектов этого достаточно. Полностью переписывать checkout имеет смысл только тогда, когда у вас нестандартная схема оплаты или внешний фронтенд, который сам управляет заказом.
Проверка результата после внедрения
После изменений не ограничивайтесь визуальной проверкой в админке. Нужно пройти весь путь как пользователь и как интеграция.
- Откройте checkout в режиме инкогнито и создайте тестовый заказ;
- прервите оформление до оплаты и проверьте, появился ли заказ;
- завершите оплату и убедитесь, что внешние сервисы сработали только на нужном статусе;
- проверьте, не сломались ли письма WooCommerce и уведомления менеджерам;
- посмотрите журналы WooCommerce и логи платёжного плагина.
Если вы чистили незавершённые заказы, отдельно проверьте, что не удалились нужные записи. Для этого удобно сначала прогнать скрипт в режиме выборки ID и вывести список в лог, а удаление включать только после ручной проверки.
Частые ошибки и как их исправить
Удаляют не те статусы
Ошибка встречается часто: разработчик удаляет все заказы, кроме completed, и ломает возвраты, ручную обработку и сверку оплат. Исправление простое — удаляйте только те статусы, которые реально считаются промежуточными в вашем магазине.
Ставят очистку на cron без проверки платёжного шлюза
Если шлюз подтверждает оплату с задержкой, заказ может ещё быть pending, когда cron уже его удалил. В итоге деньги списались, а заказа в системе нет. Для таких магазинов нужен запас по времени или другая логика очистки.
Путают проблему checkout с проблемой CRM
Иногда заказ создаётся корректно, а лишние действия запускает интеграция. В этом случае не нужно трогать WooCommerce checkout. Достаточно перенести webhook или API-вызов на другой статус заказа.
Правят код в родительской теме
После обновления тема перезапишется, и проблема вернётся. Для таких правок используйте дочернюю тему или отдельный mu-plugin.
Безопасность и производительность
Если вы добавляете очистку заказов или логику на хуках, не делайте это тяжёлыми запросами на каждом открытии страницы. Для регулярных задач лучше использовать cron, а не запускать массовое удаление на фронтенде.
Ещё два практических правила:
- не удаляйте заказы без резервной копии базы;
- не отправляйте данные в сторонние сервисы до подтверждённого статуса заказа;
- если используете кастомный код, держите его в отдельном файле и версионируйте вместе с проектом.
Если задача шире, чем один магазин, и нужно быстро убрать дубли, лишние статусы и мусорные записи, можно посмотреть в сторону инструментов для чистки WooCommerce и WordPress. Но даже в этом случае сначала проверьте, какие именно данные вы собираетесь удалять, а не запускайте массовую очистку вслепую.