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

Проблема: повторная отправка уведомлений при изменении статуса заказа

В WooCommerce стандартное поведение — отправлять email-уведомление каждый раз, когда статус заказа меняется. Иногда это приводит к лишним письмам, особенно если статус изменяется программно несколько раз подряд или при откате. Это мешает пользователям и перегружает почтовый сервер.

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

Чтобы проверить, что именно вызывает повторную отправку писем, выполните следующие шаги:

  • Активируйте логирование WooCommerce для email (WooCommerce > Настройки > Emails > Включить логирование).
  • Выполните несколько изменений статуса заказа вручную и программно.
  • Проверьте логи в wp-content/uploads/wc-logs, чтобы увидеть, сколько раз и какие письма были отправлены.
  • Обратите внимание на хуки, которые срабатывают при изменении статуса: woocommerce_order_status_changed, woocommerce_email_send.

Пошаговое решение: отключение повторной отправки писем

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

Шаг 1. Добавляем флаг отправки письма в метаданные заказа

Сохраняем в метаданных факт отправки письма для конкретного статуса:

add_action('woocommerce_order_status_changed', 'prevent_duplicate_email_on_status_change', 10, 4);
function prevent_duplicate_email_on_status_change($order_id, $old_status, $new_status, $order) {
    // Проверяем, был ли уже отправлен email для нового статуса
    $sent_statuses = get_post_meta($order_id, '_sent_email_statuses', true);
    if (!is_array($sent_statuses)) {
        $sent_statuses = [];
    }

    if (in_array($new_status, $sent_statuses)) {
        // Уже отправляли — ничего не делаем
        return;
    }

    // Помечаем, что письмо для этого статуса будет отправлено
    $sent_statuses[] = $new_status;
    update_post_meta($order_id, '_sent_email_statuses', $sent_statuses);
}

Шаг 2. Отключаем отправку email, если статус уже обработан

Используем фильтр woocommerce_email_enabled_{email_id}, чтобы блокировать отправку:

add_filter('woocommerce_email_enabled_customer_processing_order', 'disable_duplicate_email', 10, 2);
add_filter('woocommerce_email_enabled_customer_completed_order', 'disable_duplicate_email', 10, 2);
// Добавьте другие email по необходимости

function disable_duplicate_email($enabled, $order) {
    if (!$enabled || !is_a($order, 'WC_Order')) {
        return $enabled;
    }

    $order_id = $order->get_id();
    $current_status = $order->get_status();
    $sent_statuses = get_post_meta($order_id, '_sent_email_statuses', true);
    if (!is_array($sent_statuses)) {
        $sent_statuses = [];
    }

    if (in_array($current_status, $sent_statuses)) {
        // Отключаем отправку, если письмо уже отправлялось
        return false;
    }

    return $enabled;
}

Шаг 3. Очистка метаданных при необходимости

Если вы хотите, чтобы письма могли отправляться повторно при повторном смене статуса (например, после возврата), добавьте кнопку или крон-задачу для очистки мета:

update_post_meta($order_id, '_sent_email_statuses', []);

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

  • Измените статус заказа вручную несколько раз на один и тот же.
  • Проверьте, что email отправляется только при первом изменении на этот статус.
  • Проверьте логи WooCommerce — письма не должны дублироваться.
  • Проверьте работу с разными статусами заказов (processing, completed и т.д.).

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

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

Практические советы по безопасности и производительности

  • Используйте транзиенты или объектный кеш для хранения статусов отправленных писем, если база данных перегружена.
  • Не сохраняйте слишком много метаданных — очищайте устаревшие записи.
  • Тестируйте код на staging-сайте перед продакшеном.
  • Если у вас много типов email, создайте универсальную функцию с параметрами для управления списком фильтров.

Сравнение вариантов решения

МетодПлюсыМинусы
Плагин для управления emailПростота настройки, готовые функцииДополнительная нагрузка, ограниченная кастомизация
Код на фильтрах и хуках (описанный вариант)Точный контроль, гибкость, нет зависимостейТребует навыков разработки, возможны ошибки при обновлениях WooCommerce
Полная замена email-системыМаксимальная кастомизацияСложно в поддержке, требует глубоких знаний
WooCommerce: как использовать хуки для изменения статей оплаты
07.05.2026
WooCommerce: как исключить повторную отправку письма при изменении статуса заказа
06.06.2026
Как автоматизировать удаление старых записей в WordPress через PHP CLI
10.03.2026
Как создать автоматический отзыв в WordPress на основе плагина Quizle
30.03.2026
Как отключить AJAX пагинацию в WordPress: практические решения
07.12.2025