Диагностика проблемы: зачем и когда нужно удалять неактивные товары
В интернет-магазинах на WooCommerce накапливаются товары, которые давно не продаются, устарели или не имеют заказов. Их хранение увеличивает объем базы данных, замедляет админку и мешает клиентам ориентироваться. Частая задача — автоматизировать удаление таких товаров по заданным правилам, например, если товар не продавался более 6 месяцев или не обновлялся.
Перед автоматизацией важно проверить, что именно считать «неактивным» товаром. Обычно критерии:
- Отсутствие заказов за последние N месяцев.
- Дата последнего обновления товара старше заданной.
- Статус товара — опубликован, черновик, или архив.
Как получить список неактивных товаров: WP_Query и SQL-запросы
Для начала нужно получить ID товаров, подходящих под критерии. Пример запроса на WP_Query для товаров без заказов за 6 месяцев:
$cutoff_date = date('Y-m-d', strtotime('-6 months'));
$args = [
'post_type' => 'product',
'posts_per_page' => -1,
'date_query' => [
[
'column' => 'post_modified',
'before' => $cutoff_date,
],
],
'meta_query' => [
[
'key' => '_last_order_date', // кастомное поле с датой последнего заказа
'value' => $cutoff_date,
'compare' => '<=',
'type' => 'DATE',
],
],
];
$query = new WP_Query($args);
$inactive_products = $query->posts;Важно: WooCommerce по умолчанию не хранит дату последнего заказа в метаполях товара, поэтому нужно самостоятельно обновлять поле _last_order_date при каждом заказе товара (см. следующий раздел).
Автоматическое обновление даты последнего заказа товара
Чтобы отслеживать дату последнего заказа, добавим хуки, которые обновляют метаполе товара при оформлении заказа:
add_action('woocommerce_order_status_completed', 'update_last_order_date_for_products');
function update_last_order_date_for_products($order_id) {
$order = wc_get_order($order_id);
if (!$order) return;
foreach ($order->get_items() as $item) {
$product_id = $item->get_product_id();
update_post_meta($product_id, '_last_order_date', current_time('Y-m-d'));
}
}Этот код записывает текущую дату в метаполе _last_order_date у каждого товара из заказа при его завершении.
Пошаговое решение: удаление неактивных товаров с WP-Cron
Чтобы не запускать удаление вручную, создадим WP-Cron задачу, которая будет выполняться, например, раз в неделю.
1. Добавляем функцию удаления
function delete_inactive_products() {
$cutoff_date = date('Y-m-d', strtotime('-6 months'));
$args = [
'post_type' => 'product',
'posts_per_page' => -1,
'date_query' => [
[
'column' => 'post_modified',
'before' => $cutoff_date,
],
],
'meta_query' => [
[
'key' => '_last_order_date',
'value' => $cutoff_date,
'compare' => '<=',
'type' => 'DATE',
],
[
'key' => '_last_order_date',
'compare' => 'EXISTS'
],
],
];
$query = new WP_Query($args);
foreach ($query->posts as $product) {
wp_delete_post($product->ID, true); // true — безвозвратное удаление
}
}2. Регистрируем WP-Cron событие
add_action('delete_inactive_products_event', 'delete_inactive_products');
if (!wp_next_scheduled('delete_inactive_products_event')) {
wp_schedule_event(time(), 'weekly', 'delete_inactive_products_event');
}3. Проверяем работу и логи
Для отладки полезно добавить логирование (например, в файл wp-content/debug.log):
function delete_inactive_products() {
if (!defined('WP_DEBUG') || !WP_DEBUG) return;
$cutoff_date = date('Y-m-d', strtotime('-6 months'));
$args = [...]; // см. выше
$query = new WP_Query($args);
foreach ($query->posts as $product) {
error_log('Удаление товара ID: ' . $product->ID);
wp_delete_post($product->ID, true);
}
}Как проверить, что удаление работает
- Проверьте наличие товаров с датой последнего заказа старше 6 месяцев и датой обновления поста.
- Запустите функцию удаления вручную, вызвав
delete_inactive_products()через консоль WP-CLI или временно в коде. - Проверьте, что товары удаляются (их нет в админке и базе).
- Если используете логирование, проверьте
debug.logна записи об удалении. - Для мониторинга WP-Cron используйте плагин
WP Crontrol, чтобы увидеть запланированные задачи.
Частые ошибки и как их исправить
- Нет метаполя
_last_order_date: WooCommerce не создает его по умолчанию, нужно добавить код из раздела «Автоматическое обновление даты последнего заказа». - Функция удаления не запускается: проверьте, активен ли WP-Cron и не блокируется ли планировщик хостингом. Для теста запустите вручную.
- Удаляются нужные товары: убедитесь в правильности условий
date_queryиmeta_query. Добавьте логирование для контроля. - Удаление слишком медленное: разбейте запрос на части с
posts_per_pageи запускайте удаление пакетами.
Практические советы по безопасности и производительности
- Перед удалением сделайте бэкап базы данных.
- Используйте
wp_delete_post($id, true)для полного удаления, иначе товары попадут в корзину. - Для крупных магазинов разбивайте удаление на партии с паузами, чтобы не перегружать сервер.
- Добавьте проверку прав пользователя, если функция будет запускаться вручную через админку.
- Оптимизируйте запросы, индексируйте метаполя, чтобы ускорить выборку.
- При необходимости замените WP-Cron на системный cron для стабильности.
Сравнение подходов: плагин vs код vs комбинированный
| Подход | Плюсы | Минусы | Примечания |
|---|---|---|---|
| Плагин автоудаления товаров | Простота настройки, интерфейс | Может быть избыточным, нагрузка, ограничения по логике | Подходит для простых задач |
| Код на сайте (WP-Cron + WP_Query) | Гибкость, контроль, оптимизация под задачи | Требует знаний, риски ошибок | Лучше для крупных магазинов и нестандартных условий |
| Комбинация: плагин + кастомный код | Удобство + гибкость | Сложнее отладка, возможны конфликты | Для опытных разработчиков |