Диагностика проблемы: зачем удалять товары без заказов
При большом каталоге WooCommerce накапливаются товары, которые не приносят продаж и занимают ресурсы базы данных. Это увеличивает время резервного копирования, замедляет работу админки и индексирование поисковиками. Чтобы поддерживать базу данных в чистоте и ускорить работу, полезно автоматически удалять товары, которые не были куплены за определённый период.
Как определить товары без заказов за период
Для начала нужно понять, какие товары не имеют связанных заказов за последние N дней. В WooCommerce связь между товарами и заказами хранится в таблицах wp_woocommerce_order_items и wp_woocommerce_order_itemmeta, а сами заказы — в wp_posts с типом shop_order. Это важно для правильного поиска.
Пример SQL запроса для проверки
SELECT p.ID, p.post_title FROM wp_posts p
LEFT JOIN wp_woocommerce_order_items oi ON oi.order_item_name = p.ID::text
LEFT JOIN wp_posts o ON o.ID = oi.order_id AND o.post_type = 'shop_order' AND o.post_status IN ('wc-completed', 'wc-processing')
WHERE p.post_type = 'product'
AND o.ID IS NULL
AND p.post_date < DATE_SUB(NOW(), INTERVAL 30 DAY);
Этот запрос — концептуальный, требует доработки под вашу структуру и префиксы таблиц. Он показывает товары без заказов за последние 30 дней.
Пошаговое решение: автоматическое удаление товаров через WP-Cron
Построим простое решение в виде функции, которая будет запускаться ежедневно и удалять товары без заказов за 30 дней.
Шаг 1. Добавляем функцию удаления в functions.php или плагин
function wc_delete_products_without_orders() {
global $wpdb;
$interval_days = 30;
// Получаем ID товаров без заказов за последние $interval_days дней
$product_ids = $wpdb->get_col($wpdb->prepare(
"SELECT p.ID FROM {$wpdb->posts} p
WHERE p.post_type = 'product'
AND p.post_status = 'publish'
AND p.post_date < NOW() - INTERVAL %d DAY
AND NOT EXISTS (
SELECT 1 FROM {$wpdb->prefix}woocommerce_order_items oi
JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
JOIN {$wpdb->posts} o ON oi.order_id = o.ID
WHERE o.post_type = 'shop_order'
AND o.post_status IN ('wc-completed', 'wc-processing')
AND oim.meta_key = '_product_id'
AND oim.meta_value = p.ID
)",
$interval_days
));
if (!empty($product_ids)) {
foreach ($product_ids as $prod_id) {
wp_delete_post($prod_id, true); // true - без возможности восстановления
}
}
}
Шаг 2. Планируем запуск через WP-Cron
if (!wp_next_scheduled('wc_daily_delete_products')) {
wp_schedule_event(time(), 'daily', 'wc_daily_delete_products');
}
add_action('wc_daily_delete_products', 'wc_delete_products_without_orders');
Проверка результата после внедрения
- Запустите функцию вручную через
wc_delete_products_without_orders()или дождитесь запланированного запуска. - Проверьте, что товары без заказов старше 30 дней удалены из базы (через админку или SQL).
- Просмотрите логи ошибок, чтобы убедиться, что ошибок при удалении нет.
- Для тестирования можно изменить интервал на меньший (например, 1 день) и создать тестовый товар без заказов.
Частые ошибки и как их исправить
- Неправильные префиксы таблиц: используйте
$wpdb->prefixи$wpdb->postsвместо жестко вписанных имен. - Удаление товаров с заказами в статусе 'on-hold' или 'pending': убедитесь, что в запросе фильтруются только финализированные статусы
wc-completedиwc-processing. - Отсутствие WP-Cron: если на сайте мало трафика, WP-Cron может не запускаться регулярно. Настройте системный cron или запускайте вручную.
- Потеря данных: всегда делайте резервную копию базы перед массовым удалением!
Практические советы по безопасности и производительности
- Используйте
wp_delete_post($id, true)для полного удаления, включая метаданные. - Ограничьте количество удаляемых товаров за один запуск, например, добавив
LIMIT 50в запрос и циклический запуск, чтобы избежать таймаутов. - Логируйте удалённые ID в отдельный файл для аудита.
- Регулярно проверяйте таблицы WooCommerce на наличие устаревших данных и оптимизируйте их.
- Для больших магазинов рассмотрите запуск удаления в CLI скриптах или с помощью wp-cli для надежности.
Сравнение способов автоматизации удаления товаров без заказов
| Способ | Преимущества | Недостатки | Пример |
|---|---|---|---|
| WP-Cron с кастомным кодом | Гибкость, контроль, бесплатное решение | Зависит от посещений сайта, требует тестирования | Код из статьи |
| Плагины для очистки каталога | Простой интерфейс, готовые решения | Могут быть платными, не всегда гибкие | WP Sweep, Advanced Database Cleaner |
| Ручное удаление через админку | Безопасно, без риска ошибки кода | Неэффективно для больших магазинов | WooCommerce > Товары > Фильтры |