Почему важно отключать неактивные товары в WooCommerce
Автоматическое отключение товаров, которые долго не продавались, помогает держать каталог актуальным, уменьшает нагрузку на базу данных и улучшает пользовательский опыт. Особенно это актуально для магазинов с большим ассортиментом и сезонными товарами.
Диагностика проблемы: как определить товары для отключения
Первый шаг — понять, какие товары считаются неактивными. Обычно это товары, у которых с момента последней покупки прошло больше определённого периода (например, 6 месяцев). Однако WooCommerce по умолчанию не хранит дату последней продажи для товара, поэтому нужно получить эти данные из заказов.
Для диагностики можно выполнить SQL-запрос к базе данных, чтобы увидеть дату последней покупки для каждого товара:
SELECT p.ID AS product_id, MAX(o.post_date) AS last_order_date
FROM wp_posts p
LEFT JOIN wp_woocommerce_order_items oi ON oi.order_item_id IN (
SELECT order_item_id FROM wp_woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = p.ID
)
LEFT JOIN wp_posts o ON o.ID = oi.order_id AND o.post_status IN ('wc-completed', 'wc-processing')
WHERE p.post_type = 'product'
GROUP BY p.ID
ORDER BY last_order_date ASC
LIMIT 10;Этот запрос покажет 10 товаров с самыми старыми датами последних заказов. Если дата отсутствует — таких товаров не покупали.
Пошаговое решение: автоматическое отключение товаров
1. Создаем функцию для получения даты последней покупки товара
function get_last_purchase_date( $product_id ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT MAX(p.post_date) FROM {$wpdb->posts} p
INNER JOIN {$wpdb->prefix}woocommerce_order_items oi ON p.ID = oi.order_id
INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
WHERE p.post_type = 'shop_order'
AND p.post_status IN ('wc-completed', 'wc-processing')
AND oim.meta_key = '_product_id'
AND oim.meta_value = %d",
$product_id
);
return $wpdb->get_var( $query );
}2. Функция для массового отключения товаров старше заданного периода
function disable_inactive_products( $days_inactive = 180 ) {
$args = [
'post_type' => 'product',
'posts_per_page' => -1,
'fields' => 'ids',
];
$products = get_posts( $args );
$now = current_time( 'timestamp' );
foreach ( $products as $product_id ) {
$last_purchase = get_last_purchase_date( $product_id );
if ( ! $last_purchase ) {
// Товар никогда не покупался, отключаем
wp_update_post([
'ID' => $product_id,
'post_status' => 'draft'
]);
continue;
}
$last_purchase_ts = strtotime( $last_purchase );
if ( $now - $last_purchase_ts > DAY_IN_SECONDS * $days_inactive ) {
wp_update_post([
'ID' => $product_id,
'post_status' => 'draft'
]);
}
}
}3. Запуск процесса через WP-Cron
Чтобы отключение происходило регулярно, добавим задачу в планировщик WordPress:
if ( ! wp_next_scheduled( 'disable_inactive_products_daily' ) ) {
wp_schedule_event( time(), 'daily', 'disable_inactive_products_daily' );
}
add_action( 'disable_inactive_products_daily', function() {
disable_inactive_products( 180 ); // 180 дней — период неактивности
});Проверка результата после внедрения
- Выполните запрос в базе, чтобы убедиться, что статус товаров изменился на
draft. - Через админку WooCommerce проверьте список товаров — отключённые должны быть в статусе "Черновик" и не отображаться на сайте.
- Для теста можно уменьшить период неактивности, например, до 1 дня, и запустить функцию вручную:
disable_inactive_products(1);
Частые ошибки и как их исправить
- Товары не отключаются: проверьте права пользователя, под которым запускается WP-Cron, и нет ли ошибок в логах сервера.
- Даты покупок не определяются: убедитесь, что в базе есть заказы со статусами
wc-completedилиwc-processing, и что метаполя_product_idкорректно заполнены. - Большая нагрузка при массовом обновлении: разбейте отключение на порции, например, по 50 товаров за запуск, чтобы не перегружать сервер.
Практические советы по производительности и безопасности
- Используйте транзиенты или кеширование даты последней покупки, чтобы не выполнять тяжёлые запросы каждый раз.
- Добавьте проверку nonce и прав доступа, если запускаете функцию вручную через админку.
- Резервное копирование базы перед внедрением автоматического отключения — обязательный шаг.
- Для магазинов с большим количеством заказов и товаров лучше вынести логику в отдельный WP-CLI скрипт и запускать через cron на уровне сервера.
Сравнение способов реализации автоматического отключения
| Метод | Плюсы | Минусы |
|---|---|---|
| Код в functions.php + WP-Cron | Полный контроль, бесплатный, гибкий | Нагрузка на сайт, требуется тестирование |
| Плагин автоматизации (например, WP All Import + кастомные скрипты) | Простота настройки, интерфейс | Платно, ограниченная кастомизация |
| WP-CLI скрипт с cron на сервере | Высокая производительность, нет нагрузки на сайт | Требует доступа к серверу, навыков командной строки |