Диагностика проблемы: зачем отключать товары без продаж
В интернет-магазинах на WooCommerce иногда накапливаются товары, которые длительное время не продаются. Это негативно влияет на пользовательский опыт и SEO, а также усложняет управление каталогом. Автоматическое отключение таких товаров позволяет поддерживать актуальность ассортимента без ручного труда.
Как определить товары без продаж
WooCommerce хранит данные о продажах в таблицах базы данных, в частности через статус заказов и связь с товарами. Чтобы найти товары без продаж за определённый период, стоит ориентироваться на мета-данные заказов и дату публикации товаров.
Пример запроса для выявления товаров без продаж за 90 дней
SELECT p.ID FROM wp_posts p
LEFT JOIN wp_woocommerce_order_items oi ON p.ID = oi.order_item_id
LEFT JOIN wp_posts o ON oi.order_id = o.ID AND o.post_status IN ('wc-completed', 'wc-processing')
WHERE p.post_type = 'product' AND (o.ID IS NULL OR o.post_date < DATE_SUB(NOW(), INTERVAL 90 DAY))
AND p.post_date < DATE_SUB(NOW(), INTERVAL 90 DAY);Однако для автоматизации лучше использовать WP-функции и хуки.
Пошаговое решение: автоматическое отключение товаров без продаж
1. Создаём функцию для проверки продаж товара
function has_sales_in_period( $product_id, $days = 90 ) {
global $wpdb;
$date_threshold = date('Y-m-d H:i:s', strtotime("-{$days} days"));
$count = $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT( DISTINCT oi.order_item_id ) FROM {$wpdb->prefix}woocommerce_order_items oi
INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
INNER JOIN {$wpdb->prefix}posts o ON o.ID = oi.order_id
WHERE o.post_status IN ('wc-completed', 'wc-processing')
AND o.post_date > %s
AND oim.meta_key = '_product_id' AND oim.meta_value = %d",
$date_threshold, $product_id
) );
return (int) $count > 0;
}2. Функция для отключения товаров без продаж
function disable_products_without_sales() {
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'post_status' => 'publish',
'date_query' => array(
array(
'column' => 'post_date',
'before' => '90 days ago',
),
),
'fields' => 'ids',
);
$products = get_posts($args);
foreach ( $products as $product_id ) {
if ( !has_sales_in_period( $product_id, 90 ) ) {
// Отключаем товар
wp_update_post(array(
'ID' => $product_id,
'post_status' => 'draft',
));
}
}
}3. Автоматизация через WP-Cron
Добавьте задачу в расписание WordPress, чтобы запускать проверку регулярно:
if ( ! wp_next_scheduled( 'disable_products_without_sales_daily' ) ) {
wp_schedule_event( time(), 'daily', 'disable_products_without_sales_daily' );
}
add_action( 'disable_products_without_sales_daily', 'disable_products_without_sales' );Проверка результата после внедрения
- Проверьте, что после запуска скрипта товары без продаж за последние 90 дней изменили статус на "Черновик".
- Для теста можно снизить период с 90 дней до 1 дня и создать тестовый товар без продаж.
- Используйте панель администратора WooCommerce — вкладка "Товары" — фильтр по статусу, чтобы убедиться в изменениях.
Частые ошибки и как их исправить
- Неверный период проверки: если товары не отключаются, проверьте дату публикации товара и период проверки продаж.
- Отсутствие заказов с нужным статусом: функция учитывает только заказы со статусом
wc-completedиwc-processing. Если у вас другие статусы, добавьте их. - Проблемы с WP-Cron: при отсутствии реального посещения сайта задачи могут не запускаться. Настройте системный cron для wp-cron.php или запускайте вручную.
- Права пользователя: убедитесь, что скрипт выполняется с правами, позволяющими изменять статус товаров.
Практические советы по производительности и безопасности
- Для магазинов с большим каталогом товаров разбивайте обновление на партии, чтобы избежать превышения лимита памяти или времени выполнения:
function disable_products_batch( $batch_size = 50 ) {
static $offset = 0;
$args = array(
'post_type' => 'product',
'posts_per_page' => $batch_size,
'post_status' => 'publish',
'date_query' => array(
array(
'column' => 'post_date',
'before' => '90 days ago',
),
),
'fields' => 'ids',
'offset' => $offset,
);
$products = get_posts($args);
foreach ( $products as $product_id ) {
if ( !has_sales_in_period( $product_id, 90 ) ) {
wp_update_post(array(
'ID' => $product_id,
'post_status' => 'draft',
));
}
}
$offset += $batch_size;
if ( count($products) === $batch_size ) {
wp_schedule_single_event( time() + 10, 'disable_products_batch_hook' );
} else {
$offset = 0; // Сброс после окончания
}
}
add_action( 'disable_products_batch_hook', 'disable_products_batch' );- Для повышения безопасности избегайте запуска функций напрямую в шаблонах или без проверки nonce, используйте WP-Cron.
- Резервное копирование базы данных перед автоматическим изменением статусов — обязательный шаг.
Сравнение подходов отключения товаров без продаж
| Метод | Плюсы | Минусы |
|---|---|---|
| Ручное отключение через панель | Просто, без кода | Трудозатратно при большом каталоге |
| SQL-запросы для массового обновления | Быстрое обновление | Риск ошибок, требует доступа к БД |
| Автоматизация через WP-Cron + PHP | Полная автоматизация, безопасно | Нужно писать и тестировать код |