Диагностика задачи: зачем удалять непроданные товары с учётом запаса
В интернет-магазинах на WooCommerce часто копится множество товаров, которые не продаются длительное время. Это влияет на производительность сайта, усложняет управление каталогом и портит пользовательский опыт. Многие решения автоматического удаления товаров ориентированы только на дату последней продажи или отсутствие заказов, но не учитывают остаток на складе. Если товар есть в наличии — его, возможно, не стоит удалять.
Задача: автоматизировать удаление товаров без продаж за заданный период и с остатком на складе равным нулю, чтобы не удалять товары, которые есть в наличии, но временно не продаются.
Пошаговое решение: написание собственного WP-Cron задания
1. Создание функции проверки условий и удаления товаров
Функция должна:
- Получить товары без продаж за последний, например, 180 дней;
- Проверить остаток на складе — если он равен 0;
- Автоматически удалить такие товары.
Пример кода для добавления в functions.php или собственный плагин:
function wpbit_delete_unsold_products_with_no_stock() {
$days = 180;
$date_query = array(
'after' => date('Y-m-d', strtotime("-" . $days . " days"))
);
// Получаем ID товаров без продаж за $days дней
global $wpdb;
$query = $wpdb->prepare(
"SELECT p.ID FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->prefix}woocommerce_order_items oi ON oi.order_id IN
(SELECT order_id FROM {$wpdb->prefix}woocommerce_order_itemmeta oim
WHERE oim.meta_key = '_product_id' AND oim.meta_value = p.ID)
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim2 ON oim2.order_item_id = oi.order_item_id
LEFT JOIN {$wpdb->posts} o ON o.ID = oi.order_id
WHERE p.post_type = 'product'
AND (o.post_date < DATE_SUB(NOW(), INTERVAL %d DAY) OR o.post_date IS NULL)
GROUP BY p.ID",
$days
);
$product_ids = $wpdb->get_col($query);
if (empty($product_ids)) {
return; // Нет товаров для удаления
}
foreach ($product_ids as $product_id) {
$stock_quantity = get_post_meta($product_id, '_stock', true);
$manage_stock = get_post_meta($product_id, '_manage_stock', true);
if ($manage_stock === 'yes' && intval($stock_quantity) === 0) {
wp_delete_post($product_id, true); // Удаляем товар полностью
}
}
}
2. Регистрация WP-Cron события для регулярного запуска
Добавьте в functions.php следующий код для запуска задачи ежедневно:
if (!wp_next_scheduled('wpbit_daily_delete_unsold_products')) {
wp_schedule_event(time(), 'daily', 'wpbit_daily_delete_unsold_products');
}
add_action('wpbit_daily_delete_unsold_products', 'wpbit_delete_unsold_products_with_no_stock');
Как проверить, что автоматическое удаление работает
- Включите журнал ошибок PHP и посмотрите записи после выполнения Cron (или добавьте временный
error_logвнутрь функции); - Создайте тестовый товар с нулевым остатком и без продаж за нужный период — после запуска Cron он должен исчезнуть;
- Проверьте, что товары с остатком > 0 не удаляются;
- Запустите Cron вручную через WP-CLI:
wp cron event run wpbit_daily_delete_unsold_products.
Частые ошибки и как их исправить
- Неправильный запрос к базе данных: SQL может не учитывать все заказы из-за сложной структуры WooCommerce. Решение — тестировать запросы на вашей базе и оптимизировать фильтры.
- Удаляются товары с остатком: проверьте метаданные
_manage_stockи_stock, иногда они могут быть пустыми или неактивными — добавьте проверкуif ($manage_stock !== 'yes'), чтобы пропускать такие товары. - Задание WP-Cron не запускается: удостоверьтесь, что на сайте есть трафик, запускающий WP-Cron, или настройте системный Cron на сервере.
Практические советы по безопасности и производительности
- Удаление товаров — необратимая операция, используйте
wp_trash_post($product_id)вместоwp_delete_postдля возможности восстановления; - Добавьте логирование удалённых товаров для аудита (например, в отдельный файл или таблицу);
- Если каталог большой, разбивайте запрос на части с пагинацией, чтобы избежать таймаутов;
- Для стабильной работы Cron на больших сайтах настройте системный Cron и отключите WP-Cron, избегая дублирующих запусков;
- Периодически проверяйте наличие товаров в корзинах и заказах, чтобы не удалять товары, которые могут быть в процессе оформления.
Сравнение подходов: плагин vs код vs ручное удаление
| Критерий | Плагин (например, WooCommerce Cleanup) | Код (как в статье) | Ручное удаление |
|---|---|---|---|
| Гибкость | Средняя, зависит от возможностей плагина | Максимальная, можно адаптировать под любые условия | Минимальная, требует времени и ошибок |
| Автоматизация | Да, обычно есть настройки Cron | Полная, по расписанию | Нет |
| Производительность | Может быть ресурсоёмким | Оптимизируемый под сайт | Зависит от оператора |
| Риск удаления нужных товаров | Средний, зависит от плагина | Низкий при правильной настройке | Высокий, человеческий фактор |