Диагностика проблемы: зачем автоматически удалять товары
В интернет-магазинах на WooCommerce со временем скапливаются товары, которые уже не продаются, устарели или были сняты с производства. Такие товары занимают место в базе и могут негативно влиять на производительность сайта и пользовательский опыт. Ручное удаление большого числа записей неудобно и рискованно из-за возможных ошибок.
Автоматизация удаления неактуальных товаров позволяет:
- поддерживать базу данных в актуальном состоянии;
- ускорить работу сайта и админ-панели;
- исключить появление устаревших товаров в выдаче;
- снизить нагрузку на бэкапы и кэш.
Как определить неактуальные товары
Классические критерии отбора товаров для удаления:
- Отсутствие заказов по товару за последние N месяцев;
- Статус товара — «черновик», «удален» или «приватный»;
- Товары без остатка на складе (stock = 0) и без заказов;
- Отсутствие активности (просмотров, обновлений) за длительный период.
Для практического решения мы возьмём критерий: товары без заказов за последние 6 месяцев и с нулевым остатком.
Пошаговое решение: скрипт автоматического удаления
Шаг 1. Написание функции удаления по критериям
function wpset_delete_inactive_products() {
global $wpdb;
// Определяем дату 6 месяцев назад
$date_limit = date('Y-m-d H:i:s', strtotime('-6 months'));
// Получаем ID товаров без заказов за последние 6 месяцев
$product_ids = $wpdb->get_col($wpdb->prepare(
"SELECT p.ID FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->prefix}woocommerce_order_items oi ON oi.order_item_name = p.ID
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
LEFT JOIN {$wpdb->posts} o ON o.ID = oi.order_id
WHERE p.post_type = 'product'
AND (o.post_date < %s OR o.post_date IS NULL)
AND p.ID NOT IN (
SELECT order_item_meta.meta_value FROM {$wpdb->prefix}woocommerce_order_itemmeta order_item_meta
WHERE order_item_meta.meta_key = '_product_id'
)
AND p.post_status = 'publish'", $date_limit
));
if (empty($product_ids)) {
return 'No inactive products found';
}
$deleted_count = 0;
foreach ($product_ids as $product_id) {
$stock = get_post_meta($product_id, '_stock', true);
if ((int)$stock === 0) {
wp_trash_post($product_id); // Перемещаем в корзину
$deleted_count++;
}
}
return "Deleted {$deleted_count} inactive products.";
}Шаг 2. Запуск функции по расписанию с WP-Cron
add_action('wpset_daily_delete_inactive_products', 'wpset_delete_inactive_products');
if (!wp_next_scheduled('wpset_daily_delete_inactive_products')) {
wp_schedule_event(time(), 'daily', 'wpset_daily_delete_inactive_products');
}Шаг 3. Ручной запуск для тестирования
add_action('admin_init', function() {
if (isset($_GET['run_delete_inactive'])) {
echo wpset_delete_inactive_products();
exit;
}
});Для запуска вручную откройте в браузере https://ваш-сайт/wp-admin/?run_delete_inactive=1
Проверка результата после внедрения
- Проверьте, что товары с нулевым остатком и без заказов за последние 6 месяцев переместились в корзину;
- В админке WooCommerce - Товары - Корзина должны появиться удалённые записи;
- Запустите скрипт вручную через GET-параметр и убедитесь в выводе количества удалённых товаров;
- Контролируйте логи сервера на ошибки во время запуска WP-Cron.
Частые ошибки и как их исправить
- Неверный подсчёт товаров без заказов: из-за сложной структуры заказов WooCommerce SQL-запрос может возвращать неверные результаты. Проверьте запрос отдельно в phpMyAdmin и корректно ли связываются таблицы.
- Функция wp_trash_post не срабатывает: убедитесь, что у пользователя, запускающего код, есть права на удаление продуктов. Для автоматического запуска через WP-Cron права не нужны, но при ручном запуске — да.
- WP-Cron не запускается: если сайт мало посещаем, WP-Cron может не срабатывать. Настройте системный cron на сервере для вызова wp-cron.php.
- Удаление товаров с остатком: проверьте точность чтения метаполя
_stock— иногда используется_stock_statusили сторонние склады.
Практические советы по безопасности и производительности
- Перед удалением товаров лучше перемещать их в корзину, а не удалять сразу — для возможности восстановления.
- Ограничьте частоту запуска скрипта — например, раз в сутки, чтобы не нагружать базу.
- Для больших магазинов добавьте пагинацию в обработке ID товаров, чтобы не превышать лимиты памяти и времени выполнения скрипта.
- Используйте
wp_defer_term_counting(true)перед удалением иwp_defer_term_counting(false)после для оптимизации обновления таксономий. - Резервные копии базы данных обязательны перед внедрением автоматического удаления.
Сравнение методов удаления неактуальных товаров
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
| Ручное удаление в админке | Админ вручную удаляет товары | Полный контроль | Долго, риск пропустить |
| Плагины очистки базы | Автоматизация через сторонние плагины | Простота настройки | Зависимость от стороннего кода, нагрузка |
| Собственный WP-Cron скрипт | Кодовое решение под нужные критерии | Гибкость, точечное удаление | Требует тестирования, поддержки |