Диагностика проблемы дублирования заказов в WooCommerce
Появление дубликатов заказов в WooCommerce – частая проблема, особенно на сайтах с нестабильными платежными шлюзами или при некорректной работе кэша. Такие дубликаты мешают аналитике и создают путаницу в учёте. Чтобы убедиться в наличии проблемы, выполните следующие действия:
- Перейдите в WooCommerce > Заказы и проверьте список заказов на наличие одинаковых записей с одинаковыми товарами и данными клиента.
- Сравните даты и статусы заказов, чтобы определить, являются ли они настоящими дубликатами или разными по сути.
- Включите логирование запросов платежного шлюза, чтобы отследить повторные запросы, которые могут создавать дубликаты.
Причины появления дубликатов заказов
- Повторная отправка формы при медленном отклике сервера.
- Ошибки в работе платежного шлюза, приводящие к повторным уведомлениям.
- Конфликты между плагинами, особенно кэширования и безопасности.
- Неправильная настройка хуков обработки оплаты.
Пошаговое решение: автоматическое удаление дубликатов заказов
Для автоматизации удаления дубликатов можно использовать хук woocommerce_order_status_changed, который срабатывает при изменении статуса заказа. Ниже пример кода, который проверяет наличие дубликатов и удаляет их, сохраняя только первый заказ.
add_action('woocommerce_order_status_changed', 'delete_duplicate_orders_automatically', 10, 3);
function delete_duplicate_orders_automatically($order_id, $old_status, $new_status) {
if ($new_status !== 'processing' && $new_status !== 'completed') {
return; // Проверяем только заказы в статусе обработки или завершён
}
$order = wc_get_order($order_id);
if (!$order) {
return;
}
$customer_id = $order->get_customer_id();
$order_total = $order->get_total();
$order_date = $order->get_date_created();
// Получаем все заказы пользователя с таким же значением total
$args = array(
'customer_id' => $customer_id,
'limit' => -1,
'status' => array('processing', 'completed'),
'exclude' => array($order_id),
'orderby' => 'date',
'order' => 'DESC',
);
$orders = wc_get_orders($args);
foreach ($orders as $existing_order) {
if (abs($existing_order->get_total() - $order_total) < 0.01) {
// Проверяем дату создания, если разница менее 5 минут — считаем дубликатом
$diff = abs($order_date->getTimestamp() - $existing_order->get_date_created()->getTimestamp());
if ($diff < 300) {
// Удаляем дубликат
wp_trash_post($existing_order->get_id());
}
}
}
}
Этот код срабатывает при смене статуса заказа на processing или completed, ищет другие заказы того же клиента с таким же итогом и близкой по времени датой, и удаляет их.
Для запуска очистки по расписанию добавьте задачу WP-Cron:
add_action('wp', 'setup_duplicate_orders_cleanup_cron');
function setup_duplicate_orders_cleanup_cron() {
if (!wp_next_scheduled('cleanup_duplicate_orders_event')) {
wp_schedule_event(time(), 'hourly', 'cleanup_duplicate_orders_event');
}
}
add_action('cleanup_duplicate_orders_event', 'cleanup_duplicate_orders_function');
function cleanup_duplicate_orders_function() {
$args = array(
'limit' => -1,
'status' => array('processing', 'completed'),
'orderby' => 'date',
);
$orders = wc_get_orders($args);
$checked = [];
foreach ($orders as $order) {
$customer_id = $order->get_customer_id();
$order_total = $order->get_total();
$order_date = $order->get_date_created()->getTimestamp();
$key = $customer_id . '_' . round($order_total, 2);
if (!isset($checked[$key])) {
$checked[$key] = $order_date;
} else {
if (abs($order_date - $checked[$key]) < 300) {
wp_trash_post($order->get_id());
} else {
$checked[$key] = $order_date;
}
}
}
}
Проверка результата после внедрения
- Создайте тестовый заказ и повторите попытку оформления, имитируя медленное соединение.
- Проверьте, что после смены статуса на
processingилиcompletedдубликаты автоматически перемещаются в корзину. - Проверьте журнал заказов и убедитесь, что дубликаты не появляются повторно.
Частые ошибки и способы их исправления
- Удаляются не те заказы: Проверьте логику сравнения сумм и времени. Можно увеличить или уменьшить порог по времени (сейчас 5 минут).
- Код не срабатывает: Убедитесь, что хук
woocommerce_order_status_changedправильно подключён и что статусы заказов соответствуют условиям. - Заказы удаляются без уведомления: Вместо
wp_trash_postможно использоватьwp_delete_post, но будьте осторожны с безвозвратным удалением. - Конфликты с другими плагинами: Отключите все сторонние плагины и протестируйте повторно, затем включайте по одному.
Практические советы по безопасности и производительности
- Не удаляйте заказы без резервной копии. Используйте Clearfy Pro или другой плагин для автоматического бэкапа.
- Оптимизируйте запросы к базе данных, ограничив количество обрабатываемых заказов в WP-Cron.
- Добавьте логирование действий удаления для отслеживания и отладки.
- Проверяйте работу платежных шлюзов и корректно обрабатывайте повторные уведомления от них.
Сравнение подходов удаления дубликатов
| Метод | Преимущества | Недостатки | Компромисс |
|---|---|---|---|
| Удаление при смене статуса (хук) | Мгновенное удаление, простая реализация | Может пропустить дубликаты, если статус не меняется | Использовать совместно с WP-Cron |
| Удаление по расписанию (WP-Cron) | Обрабатывает все заказы, корректный обзор | Задержка до часа, нагрузка на БД при большом количестве заказов | Ограничивать выборку заказов |
| Плагины очистки | Готовые решения, поддержка | Могут быть платными, не всегда под нужды | Использовать для комплексной оптимизации |