Диагностика проблемы: зачем автоматизировать удаление товаров без остатков и заказов
В крупных магазинах на WooCommerce накапливаются товары, которые уже не продаются: остатков нет, а заказов по ним не было. Такие товары занимают место в базе, замедляют админку и усложняют управление каталогом. Ручное удаление занимает много времени и часто приводит к ошибкам.
Как определить товары для удаления
- Остаток товара равен нулю или меньше.
- Отсутствуют завершённые заказы с этим товаром.
- Товар не является вариацией с активными запасами.
Правильно определить товары для удаления — ключ к корректной очистке каталога без потери данных.
Пошаговое решение: автоматическое удаление товаров без остатков и заказов
Реализуем WP-Cron задачу, которая будет запускаться раз в день и удалять товары с нулевым остатком и без заказов.
1. Создание функции для выборки товаров
function wpdownload_get_products_to_delete() {
global $wpdb;
// Получаем ID товаров с нулевым или отрицательным запасом
$products = $wpdb->get_col(
"SELECT p.ID FROM {$wpdb->prefix}posts p
LEFT JOIN {$wpdb->prefix}wc_product_meta_lookup pm ON p.ID = pm.product_id
WHERE p.post_type = 'product'
AND p.post_status = 'publish'
AND (pm.stock_quantity IS NULL OR pm.stock_quantity <= 0)"
);
if (empty($products)) {
return [];
}
// Исключаем товары, которые встречаются в заказах
$placeholders = implode(',', array_fill(0, count($products), '%d'));
$query = $wpdb->prepare(
"SELECT DISTINCT order_item_meta.meta_value as product_id
FROM {$wpdb->prefix}woocommerce_order_items order_items
JOIN {$wpdb->prefix}woocommerce_order_itemmeta order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id
JOIN {$wpdb->prefix}posts orders ON orders.ID = order_items.order_id
WHERE order_item_meta.meta_key IN ('_product_id', '_variation_id')
AND orders.post_status IN ('wc-completed', 'wc-processing')
AND order_item_meta.meta_value IN ($placeholders)",
...$products
);
$products_in_orders = $wpdb->get_col($query);
// Возвращаем товары, которых нет в заказах
return array_diff($products, $products_in_orders ?: []);
}2. Функция удаления товаров
function wpdownload_delete_products(array $product_ids) {
foreach ($product_ids as $product_id) {
wp_delete_post($product_id, true); // true — удаление без возможности восстановления
}
}3. Создание WP-Cron задачи
function wpdownload_schedule_product_cleanup() {
if (!wp_next_scheduled('wpdownload_daily_product_cleanup')) {
wp_schedule_event(time(), 'daily', 'wpdownload_daily_product_cleanup');
}
}
add_action('wp', 'wpdownload_schedule_product_cleanup');
add_action('wpdownload_daily_product_cleanup', function() {
$products_to_delete = wpdownload_get_products_to_delete();
if ($products_to_delete) {
wpdownload_delete_products($products_to_delete);
}
});Проверка результата после внедрения
Чтобы убедиться, что автоматическое удаление работает:
- В админке WooCommerce зайдите в список товаров и проверьте, что товары с нулевым остатком и без заказов исчезают после запуска задачи.
- Запустите задачу вручную, вызвав функцию из консоли или добавив временный вызов
wpdownload_delete_products(wpdownload_get_products_to_delete());в файл functions.php (не забудьте потом удалить). - Проверьте логи сервера или плагина для отладки, если используется, чтобы убедиться, что ошибок нет.
Частые ошибки и как исправить
- Удаляются товары с активными заказами: Проверьте корректность запроса, особенно фильтр по статусам заказов (
wc-completed,wc-processing). - Не удаляются товары с нулевым остатком: Убедитесь, что индекс
wc_product_meta_lookup.stock_quantityактуален и данные синхронизированы (запуститеwp wc product meta lookup syncили аналог). - Задача WP-Cron не запускается: Проверьте, что на сайте есть трафик для запуска WP-Cron или настройте системный cron для wp-cron.php.
- Удаление не учитывает вариации: Исправьте запрос, добавив проверку вариаций и их запасов отдельно.
Практические советы по безопасности и производительности
- Удаление с
wp_delete_post($id, true)— без восстановления. Для безопасных операций сначала можно использоватьwp_trash_post($id), чтобы проверить результаты. - Если товаров очень много, разбейте удаление на партии по 50-100 штук, чтобы не перегружать сервер.
- Добавьте логирование удалённых товаров в отдельный файл для аудита.
- Используйте транзакции базы данных, если позволяет версия MySQL, чтобы избежать частичного удаления.
Сравнение вариантов реализации удаления товаров
| Метод | Плюсы | Минусы |
|---|---|---|
| Ручное удаление через админку | Простота, контроль | Долго, риск пропустить товары |
| Плагин для очистки каталога | Автоматизация, интерфейс | Доп. нагрузка, возможны конфликты |
| Код с WP-Cron и запросами SQL (как в статье) | Точный контроль, производительность | Требует навыков, опасность ошибок без тестов |