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

В WooCommerce лишние письма чаще всего появляются не из-за «ошибки почты», а из-за того, что один и тот же заказ проходит несколько переходов статуса: например, pendingprocessingcompleted, а затем ещё раз обновляется плагином оплаты или складским модулем. В итоге клиент получает дубли, а менеджер — несколько одинаковых уведомлений.

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

Когда проблема действительно в WooCommerce, а не в почтовом сервере

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

Что проверить в первую очередь

  • Откройте карточку заказа и посмотрите историю статусов: есть ли несколько переходов подряд в короткий промежуток времени.
  • Проверьте, не установлен ли плагин для оплаты, CRM, склада или доставки, который тоже меняет статус заказа.
  • Сравните заголовки письма в почтовом клиенте: если Message-ID разный, письмо, скорее всего, отправлено повторно на уровне сайта.
  • Посмотрите, не включены ли одинаковые уведомления в нескольких плагинах для email-рассылок или транзакционных писем.

Если дубли появляются только при одном конкретном статусе, задача обычно решается фильтром или отключением нужного email-уведомления. Если письма дублируются на всех статусах, сначала ищите конфликт плагинов или повторный вызов save() у заказа.

Какие есть варианты решения

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

ПодходКогда использоватьПлюсыМинусы
Настройки WooCommerceНужно отключить стандартное письмо целикомБыстро, без кодаНе решает дубли от сторонних плагинов
Код через фильтрНужно убрать письмо только для конкретного статуса или сценарияТочно, предсказуемоНужен доступ к теме или mu-plugin
Плагин управления emailНужно дать доступ менеджеру без разработчикаУдобно для админкиДополнительная зависимость и нагрузка

Пошаговое решение через код

Если нужно отключить повторную отправку письма при переходе заказа в определённый статус, удобнее всего использовать фильтр woocommerce_email_enabled_{$email_id}. Он позволяет выключить конкретное письмо до отправки.

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

<?php
add_filter( 'woocommerce_email_enabled_customer_completed_order', 'wpweb_disable_duplicate_completed_order_email', 10, 2 );

function wpweb_disable_duplicate_completed_order_email( $enabled, $order ) {
    if ( ! $order instanceof WC_Order ) {
        return $enabled;
    }

    // Кастомный флаг, чтобы не отправлять письмо повторно.
    if ( $order->get_meta( '_wpweb_completed_email_sent' ) ) {
        return false;
    }

    return $enabled;
}

add_action( 'woocommerce_order_status_completed', 'wpweb_mark_completed_email_sent', 20, 1 );

function wpweb_mark_completed_email_sent( $order_id ) {
    $order = wc_get_order( $order_id );

    if ( ! $order ) {
        return;
    }

    if ( ! $order->get_meta( '_wpweb_completed_email_sent' ) ) {
        $order->update_meta_data( '_wpweb_completed_email_sent', 'yes' );
        $order->save();
    }
}

Этот пример не отключает письмо навсегда для всех заказов. Он ставит метку в метаданных заказа после первого успешного перехода в статус completed. Если заказ снова сохранится тем же статусом, письмо уже не уйдёт повторно.

Если нужно отключить письмо только для одного статуса

Иногда задача проще: например, не отправлять клиенту письмо при переходе в processing, но оставить все остальные уведомления. Тогда можно отключить конкретный email-тип через фильтр.

<?php
add_filter( 'woocommerce_email_enabled_customer_processing_order', '__return_false' );

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

Диагностика: как понять, что письмо уходит повторно именно из-за статуса

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

<?php
add_action( 'woocommerce_order_status_changed', 'wpweb_log_order_status_change', 10, 4 );

function wpweb_log_order_status_change( $order_id, $old_status, $new_status, $order ) {
    if ( ! function_exists( 'wc_get_logger' ) ) {
        return;
    }

    $logger = wc_get_logger();
    $logger->info(
        sprintf( 'Order #%d: %s -> %s', $order_id, $old_status, $new_status ),
        array( 'source' => 'wpweb-order-status' )
    );
}

После этого откройте WooCommerce → Статус → Логи и проверьте, не повторяется ли один и тот же переход несколько раз. Если статус меняется один раз, а письма приходят дважды, проблема уже не в этом хуке — тогда стоит искать повторную отправку через сторонний код или SMTP-плагин.

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

После добавления фильтра или метки не ограничивайтесь тестовым письмом в админке. Проверьте полный сценарий, который раньше создавал дубль.

  • Создайте тестовый заказ с реальным переходом статуса.
  • Переведите заказ в нужный статус вручную и через плагин оплаты, если именно он раньше создавал повтор.
  • Проверьте, что письмо пришло один раз и только в нужный момент.
  • Откройте карточку заказа и убедитесь, что мета-ключ _wpweb_completed_email_sent появился один раз.
  • Посмотрите логи WooCommerce и почтового плагина, если он есть.

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

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

Отключили не то письмо

В WooCommerce email-идентификаторы отличаются по назначению: customer_processing_order, customer_completed_order, new_order и другие. Если отключить не тот идентификатор, можно случайно убрать важное уведомление менеджеру или клиенту. Сначала проверьте, какое именно письмо дублируется, а уже потом вносите правку.

Добавили код в файл темы, который потом обновляется

Если вставить решение в functions.php активной темы, оно может исчезнуть после смены темы. Для стабильной работы лучше использовать небольшой mu-plugin или собственный плагин для сайта.

Не учли сторонний плагин оплаты

Некоторые платёжные модули повторно вызывают смену статуса после подтверждения оплаты. В этом случае отключение email-фильтра может помочь, но первопричина останется. Проверьте, не создаёт ли плагин повторный woocommerce_order_status_changed или повторное сохранение заказа.

Ставят глобальное отключение вместо точечной защиты

Фильтр __return_false удобен, но он выключает письмо всегда. Для магазина это часто слишком жёстко: менеджер перестаёт получать нужные уведомления, а клиент — важные письма о заказе.

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

Любая логика, которая пишет метаданные заказа, должна быть идемпотентной: повторный запуск не должен ломать состояние заказа. Не добавляйте запись в мета без проверки, если хук может сработать несколько раз подряд.

Если магазин большой, не делайте тяжёлые запросы в момент смены статуса. Проверка должна быть быстрой: чтение одного meta-поля и установка одного флага — нормальный сценарий. Не стоит вешать на этот хук запросы к внешним API или сложные выборки по базе.

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

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

Что делать, если письма всё равно дублируются

Если после фильтра дубли остались, проверьте три вещи: не отправляет ли письмо SMTP-плагин повторно при ретрае, не дублирует ли уведомление CRM-интеграция, и не создаёт ли заказ повторный переход статуса из-за вебхука или callback от платёжной системы. В таких случаях проблема уже не в стандартной почте WooCommerce, а в цепочке интеграций вокруг заказа.

Самый практичный путь — временно отключить сторонние плагины по одному и повторить тестовый заказ. Так быстрее понять, где именно возникает повторная отправка, чем пытаться лечить всё одним универсальным хукoм.