Диагностика проблемы: зачем и когда нужно отключать товары автоматически
В интернет-магазинах на WooCommerce часто возникает задача временно или постоянно отключать товары из каталога при выполнении определённых условий: отсутствие на складе, истечение срока годности, низкая популярность или завершение акции. Ручное управление этим процессом неудобно и ошибочно, особенно при большом ассортименте.
Типичная ошибка — пытаться удалять товары, что приводит к потере данных и SEO. Лучше переводить товары в статус «черновик» или отключать их отображение.
Как определить, что товар нужно отключить
Для автоматизации необходимо чётко определить критерии, по которым товар должен быть выключен. Примеры:
- Товар отсутствует на складе (
stock_quantity= 0) - Товар не продаётся более 90 дней (
last_sale_date- требуется хранить в метаполях) - Дата окончания акции прошла (
sale_end_dateв метаполях) - Товар помечен флагом «неактивен» в пользовательском поле
Пошаговое решение: автоматическое отключение товаров по запасам и дате
1. Создаём пользовательское поле для даты последней продажи
WooCommerce по умолчанию не хранит дату последней продажи, поэтому можно добавить метаполе _last_sale_date и обновлять его при каждом заказе.
add_action('woocommerce_order_status_completed', 'update_last_sale_date_for_products', 10, 1);function update_last_sale_date_for_products( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) return; $date = current_time('mysql'); foreach ( $order->get_items() as $item ) { $product_id = $item->get_product_id(); update_post_meta( $product_id, '_last_sale_date', $date ); }}2. Создаём функцию, которая отключает товары
Проверяем товары на складе и дату последней продажи. Если условия выполнены, меняем статус товара на «черновик».
function auto_disable_products() { $args = array( 'post_type' => 'product', 'posts_per_page' => -1, 'post_status' => 'publish', ); $products = get_posts( $args ); $today = current_time('Y-m-d H:i:s'); foreach ( $products as $product_post ) { $stock = get_post_meta( $product_post->ID, '_stock', true ); $last_sale = get_post_meta( $product_post->ID, '_last_sale_date', true ); $disable = false; if ( intval($stock) === 0 ) { $disable = true; } elseif ( $last_sale ) { $diff = ( strtotime($today) - strtotime($last_sale) ) / (60*60*24); // в днях if ( $diff > 90 ) { $disable = true; } } if ( $disable ) { // меняем статус на черновик $post_update = array( 'ID' => $product_post->ID, 'post_status' => 'draft' ); wp_update_post( $post_update ); } }}3. Автоматизируем запуск с помощью WP-Cron
Добавим ежедневное событие для проверки товаров.
if ( ! wp_next_scheduled( 'auto_disable_products_daily' ) ) { wp_schedule_event( time(), 'daily', 'auto_disable_products_daily' );}add_action( 'auto_disable_products_daily', 'auto_disable_products' );Как проверить, что автоматическое отключение сработало
- Создайте тестовый товар с количеством 0 или без продаж более 90 дней (можно вручную установить дату в метаполе
_last_sale_date) - Запустите функцию вручную через WP-CLI:
wp eval 'auto_disable_products();'и проверьте статус товара в админке (должен стать «черновик») - Проверьте, что при следующем cron-запуске статусы обновляются автоматически
Частые ошибки и способы их устранения
- Отсутствие данных о последней продаже: без обновления метаполя
_last_sale_dateотключение по дате не сработает. Проверьте, что хукwoocommerce_order_status_completedподключён и работает. - Функция слишком тяжёлая для cron: при большом каталоге нужно разбивать запросы на части с помощью пагинации, иначе возможны тайм-ауты.
- Статус товара не меняется: проверьте права пользователя, под которым запускается cron, и корректность ID товара.
Практические советы по безопасности и производительности
- Для больших магазинов не используйте
posts_per_page = -1, а разбивайте запрос на порции по 100 товаров. - Добавьте логи в функцию для отслеживания отключаемых товаров, например, записывайте ID в отдельный лог-файл.
- Проверьте совместимость с плагинами кэширования и очистку кэша после изменения статуса товара (например, с помощью
wc_delete_product_transients($product_id)). - Не удаляйте товары — меняйте статус, чтобы сохранить SEO и историю продаж.
- Используйте WP-Cron вместо системных cron для совместимости с хостингом, но если возможно, настройте системный cron для стабильности.
Сравнение вариантов реализации отключения товаров
| Вариант | Плюсы | Минусы |
|---|---|---|
| Ручное отключение в админке | Простота, контроль | Много времени, ошибки при большом каталоге |
| Автоматизация через WP-Cron и код | Полная автоматизация, гибкость настроек | Требует навыков, возможно увеличение нагрузки |
| Плагины автоматизации (например, WPRemark) | Готовые решения, поддержка | Потенциальные ограничения, цена |