Проблема повторной отправки писем при смене статуса заказа в WooCommerce
В WooCommerce при изменении статуса заказа часто автоматически отправляются уведомления на email клиента. При частых изменениях статусов письма могут дублироваться, что раздражает покупателей и увеличивает нагрузку на почтовый сервер. Это происходит из-за повторного срабатывания хуков, отвечающих за отправку писем. В статье разберём, как диагностировать эту проблему, и покажем, как исключить повторную отправку писем без отключения уведомлений полностью.
Диагностика проблемы: как понять, что письма отправляются повторно
Для начала убедитесь, что действительно происходит повторная отправка письма при изменении статуса. Для этого:
- Перейдите в админку WooCommerce → Заказы;
- Выберите любой заказ и измените статус, например, со «В обработке» на «Выполнен»;
- Проверьте почтовый ящик клиента — должно прийти одно письмо с уведомлением;
- Повторите изменение статуса обратно и снова вперёд;
- Если письма приходят каждый раз и вы подозреваете, что они дублируются, проблема налицо.
Также можно включить логирование почтовых событий через плагин WP Mail Logging. Это позволит увидеть, сколько писем и при каких событиях отправляется.
Пошаговое решение: отключаем повторную отправку писем при смене статуса
WooCommerce отправляет письма с помощью класса WC_Email. Чтобы исключить повторную отправку, нам нужно контролировать, чтобы письмо отправлялось только при первом изменении нужного статуса, а при повторных изменениях не отправлялось.
Пример кода, который можно добавить в functions.php вашей темы или в свой плагин:
add_filter('woocommerce_email_enabled_customer_completed_order', 'disable_duplicate_completed_order_email', 10, 2);
function disable_duplicate_completed_order_email($enabled, $order) {
// Получаем ID заказа
$order_id = $order->get_id();
// Используем transient для хранения факта отправки письма
$transient_key = 'completed_email_sent_' . $order_id;
if (get_transient($transient_key)) {
// Письмо уже отправлялось, отключаем повторную отправку
return false;
}
// Устанавливаем флаг на 24 часа
set_transient($transient_key, true, DAY_IN_SECONDS);
return $enabled;
}Этот фильтр отключает повторную отправку письма «Заказ выполнен» клиенту. Аналогично можно добавить для других статусов, меняя фильтр:
woocommerce_email_enabled_customer_processing_order— для статуса «В обработке»;woocommerce_email_enabled_customer_on_hold_order— для «Ожидает оплаты»;- и так далее.
Важный момент: get_transient и set_transient применяются для хранения флага отправки письма на стороне сервера, что исключает повторную отправку в течение указанного времени.
Альтернативный способ: отмена отправки в момент смены статуса
Если нужно точечно контролировать отправку, можно использовать хук woocommerce_order_status_changed и отключать письмо в зависимости от условий:
add_action('woocommerce_order_status_changed', 'custom_prevent_duplicate_email', 10, 4);
function custom_prevent_duplicate_email($order_id, $old_status, $new_status, $order) {
if ($new_status === 'completed') {
// Удаляем флаг, если нужно сбросить ограничение
delete_transient('completed_email_sent_' . $order_id);
}
}Этот код удаляет флаг при смене статуса, позволяя отправить письмо заново, если это действительно нужно.
Проверка результата после внедрения
- Сделайте несколько смен статусов заказа с теми, для которых вы отключили повторную отправку;
- Проверьте почтовый ящик — письма должны приходить только при первом переходе в статус, а повторно — не приходить;
- Включите логирование почты и убедитесь, что количество отправленных писем соответствует ожидаемому;
- Проверьте, что другие уведомления WooCommerce продолжают работать без сбоев.
Частые ошибки и как их исправить
- Письма продолжают дублироваться: возможно, вы не применили фильтр к нужному событию или используете кастомные статусы без поддержки в коде. Проверьте все статусы и хуки.
- Письма не отправляются вовсе: проверьте, не возвращаете ли вы
falseв фильтре всегда, а не только при дубликате. - Транзиенты не работают: убедитесь, что на вашем сервере настроен корректный кеш, или замените транзиенты на пользовательские опции в базе данных.
- Конфликты с плагинами SMTP или кэширования: временно отключите их, чтобы проверить влияние на отправку писем.
Практические советы по оптимизации и безопасности
- Используйте транзиенты для минимизации нагрузки на базу данных и уменьшения количества отправляемых писем.
- Внедряйте логи почты (например, с помощью WP Mail Logging) для мониторинга отправки и быстрого выявления проблем.
- Для кастомных статусов создавайте свои фильтры по аналогии с WooCommerce, чтобы полностью контролировать почтовые уведомления.
- Перед изменениями на рабочем сайте тестируйте код на локальной или staging-среде.
- Следите за обновлениями WooCommerce — иногда меняется логика отправки писем и хуки.
Сравнение способов решения проблемы повторной отправки писем
| Метод | Пример | Преимущества | Недостатки |
|---|---|---|---|
| Фильтр включения писем | Использование woocommerce_email_enabled_customer_completed_order | Простота, минимальное вмешательство, легко расширять | Требует добавления фильтров для каждого типа письма |
| Обработка события смены статуса | Хук woocommerce_order_status_changed и удаление транзиентов | Гибкость, можно сбрасывать флаги и контролировать отправку динамически | Сложнее в поддержке, требует аккуратности |
| Отключение уведомлений плагином | Плагины типа Disable Emails | Простота для начинающих | Полное отключение, отсутствие гибкости |