Диагностика задачи: зачем и когда нужно удалять непроданные товары
В интернет-магазинах на WooCommerce со временем накапливается большое количество товаров, которые не продаются. Это увеличивает нагрузку на базу данных, замедляет работу сайта и усложняет управление каталогом. Автоматическое удаление таких товаров по заданному периоду бездействия помогает держать магазин в актуальном состоянии и улучшает производительность.
Как определить непроданные товары за период
Непроданные товары — это те, у которых за последний N дней не было ни одной продажи. Для определения продаж товаров проверяем таблицу заказов wp_posts (post_type = 'shop_order') и связанные метаданные в wp_postmeta, где хранятся статусы заказов и позиции товаров.
В WooCommerce для подсчёта продаж учитываем только заказанные и завершённые заказы, статусы которых 'completed' или 'processing'.
Запрос для получения ID непроданных товаров
SELECT p.ID FROM wp_posts p
LEFT JOIN (
SELECT oi.order_item_id, oim.meta_value AS product_id
FROM wp_woocommerce_order_items oi
JOIN wp_woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id AND oim.meta_key = '_product_id'
JOIN wp_posts o ON oi.order_id = o.ID
WHERE o.post_type = 'shop_order'
AND o.post_status IN ('wc-completed', 'wc-processing')
AND o.post_date > DATE_SUB(NOW(), INTERVAL 90 DAY)
) sold ON p.ID = sold.product_id
WHERE p.post_type = 'product' AND sold.product_id IS NULL;Этот запрос выбирает товары без продаж за последние 90 дней.
Пошаговое решение: автоматическое удаление непроданных товаров через WP-Cron
1. Создаём функцию удаления товаров
function wpbit_delete_unsold_products() {
global $wpdb;
$days = 90; // Период в днях
// Получаем ID товаров без продаж за период
$query = $wpdb->prepare(
"SELECT p.ID FROM {$wpdb->posts} p
LEFT JOIN (
SELECT oi.order_item_id, oim.meta_value AS product_id
FROM {$wpdb->prefix}woocommerce_order_items oi
JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id AND oim.meta_key = '_product_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 o.post_date > DATE_SUB(NOW(), INTERVAL %d DAY)
) sold ON p.ID = sold.product_id
WHERE p.post_type = 'product' AND sold.product_id IS NULL;",
$days
);
$product_ids = $wpdb->get_col($query);
if (empty($product_ids)) {
return;
}
foreach ($product_ids as $product_id) {
wp_delete_post($product_id, true); // Удаляем товар без возможности восстановления
}
}2. Регистрируем WP-Cron задачу
function wpbit_schedule_delete_unsold_products() {
if (!wp_next_scheduled('wpbit_daily_delete_unsold_products')) {
wp_schedule_event(time(), 'daily', 'wpbit_daily_delete_unsold_products');
}
}
add_action('wp', 'wpbit_schedule_delete_unsold_products');
add_action('wpbit_daily_delete_unsold_products', 'wpbit_delete_unsold_products');3. Запуск и отключение задачи по необходимости
Для деактивации cron-задачи можно использовать:
function wpbit_clear_scheduled_delete() {
$timestamp = wp_next_scheduled('wpbit_daily_delete_unsold_products');
if ($timestamp) {
wp_unschedule_event($timestamp, 'wpbit_daily_delete_unsold_products');
}
}Проверка результата после внедрения
- Проверить наличие запланированной задачи в разделе
wp-cron.scheduledс помощью плагинов (например, WP Crontrol). - Запустить функцию вручную через консоль или добавить временный вызов
wpbit_delete_unsold_products()и убедиться, что непроданные товары удаляются. - Проверить базу данных на отсутствие товаров без продаж старше 90 дней.
Частые ошибки и как их исправить
- Неверные статусы заказов: учитывайте только 'wc-completed' и 'wc-processing'. Если добавить 'wc-pending' или 'wc-on-hold', товары могут удаляться некорректно.
- Проблемы с WP-Cron: если на сайте низкий трафик, cron-задачи не выполняются вовремя. Настройте системный cron или используйте плагин WP Crontrol для тестирования.
- Удаление товаров с вариациями: функция удаляет только главные продукты, вариации удаляются вместе с ними. Если вариации используются отдельно, нужно адаптировать код.
- Потеря данных: удаление происходит без возможности восстановления. Рекомендуется делать резервные копии базы данных перед запуском.
Практические советы по безопасности и производительности
- Используйте
wp_delete_post($id, true)для полного удаления, но убедитесь в необходимости, чтобы не потерять важные данные. - Ограничьте период в днях для удаления, чтобы не удалять недавно добавленные товары.
- Для больших магазинов с тысячами товаров выполняйте удаление пакетами, например, по 50 товаров за один запуск, чтобы снизить нагрузку.
- Добавьте логирование удалённых товаров в отдельный файл или в таблицу базы для аудита и восстановления при необходимости.
Сравнение вариантов реализации удаления непроданных товаров
| Метод | Плюсы | Минусы |
|---|---|---|
| WP-Cron с кастомным кодом | Гибкость, можно настроить период, фильтры, удаление по критериям | Зависит от работы WP-Cron, нагрузка при больших объемах |
| Плагины очистки WooCommerce | Простота установки, интерфейс, дополнительные функции (очистка корзины, заказов) | Могут быть избыточными, не всегда поддерживают точные условия удаления |
| Ручное удаление через SQL-запросы | Быстро и сразу | Риск ошибок, потеря данных, сложность в поддержке |