Проблема: повторная отправка email при изменении статуса заказа в WooCommerce
В WooCommerce нередко возникает ситуация, когда при повторном сохранении заказа с тем же статусом или при его быстром переключении письма клиенту отправляются несколько раз. Это приводит к неудобствам для клиентов и избыточной нагрузке на сервер.
Диагностика проблемы
Для начала нужно понять, в каких случаях происходит повторная отправка писем:
- Статус заказа меняется на тот же, что и был (повторное сохранение).
- Статус меняется несколько раз за короткий промежуток времени.
- Сторонние плагины или кастомные скрипты принудительно вызывают отправку писем.
Проверить это можно с помощью логирования хуков, которые отвечают за отправку email. В WooCommerce это обычно woocommerce_order_status_{status} и woocommerce_email_send.
Пример логирования отправки писем
add_action('woocommerce_email_send', function($email) {
error_log('WooCommerce email sent: ' . $email->id);
});После этого в wp-content/debug.log будут записываться события отправки писем. Это поможет выявить избыточные вызовы.
Пошаговое решение: предотвратить повторную отправку email при смене статуса заказа
Самый надежный способ — перехватить событие смены статуса и контролировать отправку писем вручную, отключив штатное поведение для повторных вызовов.
1. Отключение штатной отправки для повторных вызовов
Добавьте следующий код в functions.php вашей темы или в плагин:
add_filter('woocommerce_email_enabled_customer_completed_order', 'disable_email_on_repeated_status', 10, 2);
add_filter('woocommerce_email_enabled_customer_processing_order', 'disable_email_on_repeated_status', 10, 2);
function disable_email_on_repeated_status($enabled, $order) {
$last_status = get_post_meta($order->get_id(), '_last_order_status', true);
$current_status = $order->get_status();
if ($last_status === $current_status) {
return false; // Отключаем отправку письма
}
update_post_meta($order->get_id(), '_last_order_status', $current_status);
return $enabled;
}Этот фильтр проверяет предыдущий сохраненный статус заказа и если он совпадает с текущим — отключает отправку письма.
2. Очистка мета при новых статусах
Убедитесь, что метаданные обновляются именно при смене статуса, чтобы не блокировать отправку при реальных изменениях.
Проверка результата
- Измените статус заказа на любой, например, с
processingнаcompleted. Письмо отправится. - Повторно сохраните заказ с тем же статусом — письмо не должно отправиться.
- Проверьте логи
debug.log— количество записей о отправке должно соответствовать реальным изменениям.
Частые ошибки и их исправление
- Ошибка: Письма не отправляются вообще.
Причина: Фильтр отключает все письма без учёта реального изменения.
Решение: Проверьте логику сравнения статусов, возможно, статус хранится в другой форме, используйте$order->get_status()вместо прямого доступа к метаданным. - Ошибка: Повторная отправка при быстром изменении статуса.
Причина: Метаданные не обновляются вовремя.
Решение: Можно добавить задержку или использовать транзиенты для контроля частоты отправок. - Ошибка: Конфликт с плагинами управления заказами.
Причина: Сторонний плагин может вызывать отправку вручную.
Решение: Проверьте сторонние плагины, отключите их по очереди для диагностики.
Практические советы по безопасности и производительности
- Не используйте глобальные переменные для хранения статусов — применяйте метаданные заказа.
- Используйте
wp_cache_setили транзиенты, если нужно ограничить частоту отправки. - Всегда тестируйте изменения на тестовом сервере, чтобы избежать сбоев в работе email-уведомлений.
- Резервируйте логи для email-событий, чтобы отслеживать аномалии.
Сравнение вариантов решения
| Метод | Пример | Плюсы | Минусы |
|---|---|---|---|
| Отключение через фильтры email_enabled | Фильтр в functions.php | Легко внедрить, контролируемо | Требует точной логики сравнения |
| Перехват отправки через хуки email | add_action('woocommerce_email_send') | Точный контроль над моментом отправки | Сложнее реализовать и отлаживать |
| Использование плагинов управления email | Плагины типа WP Mail SMTP Pro | Готовые решения с настройками | Могут конфликтовать и нагружать систему |