Диагностика проблемы: зачем удалять товары без заказов и остатков
В интернет-магазинах на WooCommerce со временем накапливаются товары, которые не продаются и не имеют остатков на складе. Они занимают место в базе данных и усложняют навигацию для администраторов. Автоматическое удаление таких товаров помогает поддерживать базу в актуальном состоянии и ускоряет работу магазина.
Как определить товары для удаления
Для автоматического удаления нам нужно выбрать товары, у которых одновременно:
- Отсутствуют остатки на складе (
stock_quantity = 0илиmanage_stock = yesиstock_status = 'outofstock'). - Отсутствуют заказы с этими товарами в статусах, которые считаются завершёнными или активными (например,
completed,processing).
Пошаговое решение: код для удаления товаров без заказов и остатков
Добавьте следующий код в файл functions.php вашей темы или создайте отдельный плагин для удобства и безопасности:
function wc_delete_products_without_orders_and_stock() {
// Получаем ID товаров с остатком 0 или без управления запасом
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => '_stock_status',
'value' => 'outofstock',
),
array(
'key' => '_manage_stock',
'value' => 'yes',
),
),
'fields' => 'ids',
);
$products = get_posts($args);
if (empty($products)) {
return;
}
foreach ($products as $product_id) {
// Проверяем, есть ли заказы с этим товаром
global $wpdb;
$order_items = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(oi.order_item_id) FROM {$wpdb->prefix}woocommerce_order_items oi
JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
JOIN {$wpdb->prefix}posts p ON oi.order_id = p.ID
WHERE oi.order_item_type = 'line_item'
AND oim.meta_key = '_product_id' AND oim.meta_value = %d
AND p.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold')",
$product_id
));
if (empty($order_items)) {
// Дополнительно проверяем остаток
$stock_qty = get_post_meta($product_id, '_stock', true);
$manage_stock = get_post_meta($product_id, '_manage_stock', true);
$stock_status = get_post_meta($product_id, '_stock_status', true);
$no_stock = false;
if ($manage_stock === 'yes' && ($stock_qty === '' || intval($stock_qty) <= 0)) {
$no_stock = true;
} elseif ($stock_status === 'outofstock') {
$no_stock = true;
}
if ($no_stock) {
// Удаляем товар окончательно
wp_delete_post($product_id, true);
}
}
}
}
// Для безопасности запускаем функцию вручную по хуку
// Например, крон или через admin_init (только для теста, убрать после)
add_action('admin_init', function() {
if (current_user_can('manage_woocommerce') && isset($_GET['run_wc_cleanup'])) {
wc_delete_products_without_orders_and_stock();
wp_redirect(admin_url('edit.php?post_type=product&wc_cleanup=done'));
exit;
}
});Для запуска перейдите в админку по адресу https://ваш-сайт/wp-admin/edit.php?post_type=product&run_wc_cleanup=1. После выполнения произойдёт удаление товаров, отвечающих условиям.
Проверка результата после внедрения
- Проверьте список товаров в админке WooCommerce. Товары без заказов и остатков должны исчезнуть.
- Для проверки можно использовать SQL-запрос в базе, чтобы убедиться, что удалённые товары отсутствуют в таблице
wp_postsс типомproduct. - Проверьте, что заказы с этими товарами остаются без изменений.
Частые ошибки и как их исправить
- Ошибка: Товары не удаляются.
Причина: Неправильные статусы заказов в условии или кэширование.
Исправление: Проверьте, что статусы заказов в запросе соответствуют вашим настройкам WooCommerce. Очистите кэш сайта и базы данных. - Ошибка: Удаляются товары с остатками.
Причина: Некорректно проверяется количество на складе.
Исправление: Проверьте мета-поля_stock,_manage_stock,_stock_status. Возможно, нужно адаптировать логику под вашу схему учёта запасов. - Ошибка: Функция запускается слишком часто и грузит сервер.
Исправление: Запускайте функцию вручную или через WP Cron с долгими интервалами. Не привязывайте к хукам с частым срабатыванием.
Практические советы по безопасности и производительности
- Всегда делайте резервную копию базы данных перед массовым удалением товаров.
- Для больших магазинов разбивайте удаление на партии по 50-100 товаров, чтобы избежать таймаутов.
- Используйте пользовательские роли и проверки доступа (как в примере,
current_user_can('manage_woocommerce')), чтобы запускать удаление только авторизованные администраторы. - Если хотите автоматизировать процесс, настройте WP Cron с запуском раз в неделю или месяц.
- Для удобства добавьте логирование удалённых товаров в файл или таблицу базы, чтобы можно было восстановить по необходимости.
Сравнение вариантов реализации удаления товаров
| Вариант | Описание | Плюсы | Минусы |
|---|---|---|---|
| Через SQL-запросы напрямую | Удаление продуктов через запросы к базе данных | Очень быстро для больших объёмов | Риск нарушить целостность данных, обойти хуки WooCommerce |
Через WP-функции wp_delete_post |
Удаление через API WordPress с учётом всех хуков | Безопасно, с очищением мета и связанных данных | Медленнее, нагрузка на сервер при большом количестве товаров |
| Использование плагинов для очистки | Готовые решения для удаления неактивных товаров | Удобно, интерфейс, поддержка | Могут быть избыточными или содержать ненужные функции |