Проблема: повторная отправка уведомлений при изменении статуса заказа
В 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-системы | Максимальная кастомизация | Сложно в поддержке, требует глубоких знаний |