Диагностика проблемы с повторной отправкой писем в WooCommerce
Многие разработчики и владельцы WooCommerce-магазинов сталкиваются с ситуацией, когда система отправляет уведомления клиентам несколько раз при изменении статуса заказа. Это не только раздражает пользователей, но и создает лишнюю нагрузку на сервер и почтовую систему.
Причины повторной отправки писем могут быть разными:
- Неправильное использование стандартных хуков WooCommerce для отправки писем;
- Множественные вызовы функций отправки уведомлений при одном событии;
- Отсутствие проверки условий для отправки письма;
- Плагины, которые дублируют функционал уведомлений.
Как WooCommerce обрабатывает уведомления о смене статуса заказа
Стандартно WooCommerce отправляет письма через класс WC_Email и триггерит их при смене статуса заказа. Например, хук woocommerce_order_status_changed запускает отправку соответствующего email.
Отправка происходит один раз при переходе заказа из одного статуса в другой. Если код или плагин не фильтрует такие переходы, письмо может уйти повторно.
Пошаговое решение: исключаем повторную отправку писем по условиям
1. Используйте фильтр woocommerce_email_enabled_{email_id} для контроля отправки
Каждое письмо имеет идентификатор (например, customer_completed_order, customer_processing_order), для которого можно включать или отключать отправку динамически.
Добавьте в functions.php или в свой плагин следующий код, чтобы отключать отправку письма при повторном изменении определенного статуса:
add_filter('woocommerce_email_enabled_customer_completed_order', 'disable_redundant_completed_order_email', 10, 2);
function disable_redundant_completed_order_email($enabled, $order) {
// Получаем мета с предыдущей отправкой письма
$already_sent = get_post_meta($order->get_id(), '_completed_order_email_sent', true);
if ($already_sent) {
// Отключаем повторную отправку
return false;
}
return $enabled;
}
// Отмечаем, что письмо отправлено
add_action('woocommerce_order_status_completed_notification', 'mark_completed_order_email_sent');
function mark_completed_order_email_sent($order_id) {
update_post_meta($order_id, '_completed_order_email_sent', true);
}2. Очистка мета при возврате заказа в другой статус
Если заказ меняет статус назад (например, с "завершен" на "в обработке"), стоит сбросить мета, чтобы письмо могло быть отправлено снова при новом завершении.
add_action('woocommerce_order_status_changed', 'reset_completed_email_flag_on_status_change', 10, 4);
function reset_completed_email_flag_on_status_change($order_id, $old_status, $new_status, $order) {
if ($old_status === 'completed' && $new_status !== 'completed') {
delete_post_meta($order_id, '_completed_order_email_sent');
}
}Проверка результата после внедрения
- Создайте тестовый заказ и переведите его в статус
completed— письмо должно уйти один раз. - Попробуйте изменить статус обратно на
processing, а затем снова наcompleted— письмо должно отправиться повторно. - При повторном переводе заказа в статус
completedбез смены на другой статус письмо не должно отправляться.
Частые ошибки и как их исправить
- Письма не отправляются вообще. Проверьте, что фильтр возвращает
trueпо умолчанию и отключает отправку только в нужных случаях. - Метаданные не сохраняются. Убедитесь, что
update_post_metaвызывается с правильным ID заказа. - Другие плагины конфликтуют. Отключите сторонние плагины уведомлений и протестируйте повторно.
- Проверка условий сделана неверно. Например, используйте правильные статусы и правильные хуки для сброса мета.
Практические советы по безопасности и производительности
- Сохраняйте минимум метаданных — только то, что реально нужно для логики отправки.
- Используйте хук
woocommerce_order_status_changedдля контроля статуса, а не менее специфичные хуки, чтобы избежать лишних вызовов. - Не отключайте полностью стандартные уведомления, если не уверены — лучше фильтровать их выборочно.
Таблица сравнения способов решения задачи
| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
Фильтр woocommerce_email_enabled_{email_id} | Гибкий контроль, легкая реализация | Требует точной логики для условий | Когда нужно исключить повторные письма для конкретного email |
| Отключение писем через плагин | Простое решение без кода | Менее гибко, может отключить нужные уведомления | Для быстрого решения без кастомизации |
| Переопределение email-классов | Полный контроль над письмами | Сложно в поддержке, больше кода | Для сложных сценариев с кастомизацией писем |