Проблема: как автоматически удалять товары, относящиеся к устаревшим заказам в WooCommerce
В магазинах на WooCommerce часто возникает задача удалить товары, которые связаны с заказами, которые не подтверждаются или считаются устаревшими (например, неоплаченные или отменённые заказы старше определённого срока). Это помогает поддерживать актуальность ассортимента и упрощает управление каталого.
Диагностика задачи
Перед реализацией автоматического удаления необходимо:
- Определить, какие статусы заказов считать устаревшими (например,
cancelled,failed,pendingстарше 30 дней). - Понять, какие товары удалить. Обычно это товары, которые не связаны с другими активными заказами или не продаются в других местах.
- Оценить риски — удаление товара необратимо, нужно делать резервные копии.
Пошаговое решение: реализация удаления товаров по устаревшим заказам
Реализуем функцию, которая на основе WP-Cron будет запускаться ежедневно и удалять товары, связанные с устаревшими заказами старше 30 дней.
1. Определяем устаревшие заказы
function get_old_orders_ids( $days = 30 ) {
global $wpdb;
$date_threshold = date( 'Y-m-d H:i:s', strtotime( "-{$days} days" ) );
$statuses = array('cancelled', 'failed', 'pending');
$placeholders = implode(',', array_fill(0, count($statuses), '%s'));
$query = $wpdb->prepare(
"SELECT ID FROM {$wpdb->prefix}posts WHERE post_type = 'shop_order' AND post_status IN ($placeholders) AND post_date < %s",
...array_merge($statuses, array($date_threshold))
);
return $wpdb->get_col($query);
}Функция возвращает ID заказов по статусам и дате.
2. Получаем товары из этих заказов
function get_products_from_orders( $order_ids ) {
$product_ids = array();
foreach ( $order_ids as $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) continue;
foreach ( $order->get_items() as $item ) {
$product_ids[] = $item->get_product_id();
}
}
return array_unique( $product_ids );
}3. Проверяем, что товары не связаны с активными заказами
Чтобы избежать удаления товаров, которые продаются в активных заказах, проверим наличие товаров в заказах со статусом processing или completed.
function filter_active_products( $product_ids ) {
$active_statuses = array('processing', 'completed');
$filtered = [];
foreach ( $product_ids as $product_id ) {
$args = array(
'limit' => 1,
'status' => $active_statuses,
'product_id' => $product_id
);
$orders = wc_get_orders( $args );
if ( empty( $orders ) ) {
$filtered[] = $product_id;
}
}
return $filtered;
}4. Удаляем товары программно
Удаление товаров — это удаление постов типа product. Используем wp_delete_post() с параметром $force_delete = true, чтобы удалить без отправки в корзину.
function delete_products_by_ids( $product_ids ) {
foreach ( $product_ids as $product_id ) {
wp_delete_post( $product_id, true );
}
}5. Объединяем все шаги в задачу WP-Cron
add_action( 'wp_loaded', function() {
if ( ! wp_next_scheduled( 'auto_delete_old_order_products' ) ) {
wp_schedule_event( time(), 'daily', 'auto_delete_old_order_products' );
}
});
add_action( 'auto_delete_old_order_products', function() {
$old_orders = get_old_orders_ids(30);
if ( empty($old_orders) ) return;
$products = get_products_from_orders($old_orders);
if ( empty($products) ) return;
$to_delete = filter_active_products($products);
if ( empty($to_delete) ) return;
delete_products_by_ids($to_delete);
});Проверка результата после внедрения
- Проверьте наличие запланированного события в WP-Cron через плагин WP Crontrol или вручную с помощью
wp cron event list. - Создайте тестовые заказы с разными статусами и товарами, подождите 1 день или измените дату вручную в базе, затем запустите крон вручную через WP Crontrol.
- Убедитесь, что удаляются только товары из устаревших заказов, которые не связаны с активными заказами.
- Проверьте логи ошибок сервера и WordPress для исключения сбоев.
Частые ошибки и как исправить
- Удаление нужных товаров: Не учитывается связь товара с активными заказами — добавьте проверку в
filter_active_products(). - Неправильный статус заказов: Убедитесь, что используете правильные статусы WooCommerce (например,
wc-cancelledв базе — в API этоcancelled). - Крон не запускается: Проверьте, работает ли WP-Cron, нет ли конфликтов с плагинами кеширования и не отключён ли php-функция
wp-cron.php. - Удаление без резервных копий: Всегда делайте бэкап базы и файлов перед внедрением автоматического удаления.
Практические советы по безопасности и производительности
- Резервное копирование: Перед удалением сделайте экспорт списка товаров, чтобы можно было восстановить при ошибках.
- Ограничение нагрузки: Если товаров много, делайте удаление пакетами по 50–100 штук с последующим повторным запуском.
- Логирование: Добавьте логирование удалённых товаров в файл, чтобы отслеживать действия.
- Безопасность: Ограничьте права на выполнение крона только администраторам, если запускаете вручную.
Сравнение вариантов реализации автоматического удаления товаров
| Вариант | Описание | Плюсы | Минусы |
|---|---|---|---|
| Плагин для очистки товаров | Использование готовых плагинов (например, WP Bulk Delete) | Простота настройки, UI для выбора | Ограниченная гибкость, нагрузка, сторонний код |
| Кастомный код с WP-Cron | Реализация на PHP под конкретные условия | Гибкость, оптимизация под задачи, прозрачность | Нужно самостоятельно поддерживать, риск ошибок |
| Ручное удаление через админку | Админ удаляет товары вручную | Полный контроль | Трудозатратно, не подходит для больших магазинов |