Диагностика задачи: зачем и когда удалять товар после первого заказа
В WooCommerce иногда требуется автоматически удалять товар из каталога после того, как он был куплен впервые. Это актуально для ограниченных серий, уникальных лотов, эксклюзивных предложений или цифровых товаров с ограниченным доступом. Решение должно работать без постоянного вмешательства и не влиять на производительность сайта.
Пошаговое решение: автоматическое удаление товара после первого заказа
1. Добавление кода в functions.php или в кастомный плагин
Для реализации задачи нужно использовать хук WooCommerce woocommerce_thankyou, который срабатывает после успешного оформления заказа. В обработчике мы проверим, есть ли товар в базе заказов, и если это первый заказ, удалим продукт.
add_action('woocommerce_thankyou', 'wc_delete_product_after_first_order', 10, 1);
function wc_delete_product_after_first_order($order_id) {
if (!$order_id) return;
$order = wc_get_order($order_id);
if (!$order) return;
foreach ($order->get_items() as $item) {
$product_id = $item->get_product_id();
// Проверяем, был ли этот товар куплен раньше
$args = [
'limit' => 1,
'status' => ['completed', 'processing'],
'exclude' => [$order_id], // Исключаем текущий заказ
'meta_query' => [
[
'key' => '_product_id',
'value' => $product_id,
'compare' => '=',
],
],
];
$orders = wc_get_orders($args);
// Если других заказов с этим товаром нет, удаляем товар
if (empty($orders)) {
wp_delete_post($product_id, true); // true - удаление без возможности восстановления
}
}
}
Важно: В данном примере используется wc_get_orders с meta_query, однако для поиска товаров в заказах придется проверить товары в каждом заказе вручную, так как мета _product_id не хранится в заказах по умолчанию. Поэтому правильнее сделать перебор заказов и их товаров для проверки.
2. Альтернативный, точный вариант проверки прошлых заказов с товаром
function has_product_been_ordered_before($product_id, $exclude_order_id) {
$args = [
'limit' => -1,
'status' => ['completed', 'processing'],
];
$orders = wc_get_orders($args);
foreach ($orders as $order) {
if ($order->get_id() == $exclude_order_id) continue;
foreach ($order->get_items() as $item) {
if ($item->get_product_id() == $product_id) {
return true;
}
}
}
return false;
}
add_action('woocommerce_thankyou', 'wc_delete_product_after_first_order_precise', 10, 1);
function wc_delete_product_after_first_order_precise($order_id) {
if (!$order_id) return;
$order = wc_get_order($order_id);
if (!$order) return;
foreach ($order->get_items() as $item) {
$product_id = $item->get_product_id();
if (!has_product_been_ordered_before($product_id, $order_id)) {
wp_delete_post($product_id, true);
}
}
}
Проверка результата после внедрения
- Оформите тестовый заказ с уникальным товаром, который еще не покупался.
- После успешного оформления проверьте в админке WooCommerce, что товар удален из каталога.
- Попробуйте оформить повторный заказ с тем же товаром (если возможно) — он должен быть недоступен.
- Проверьте логи ошибок PHP и WooCommerce на предмет исключений.
Частые ошибки и как их исправить
- Товар не удаляется: проверьте, что ID товара корректно получен и что функция
wp_delete_post()вызывается. - Проверка прошлых заказов занимает слишком много времени: уменьшите количество проверяемых заказов, добавьте кэширование или используйте SQL-запросы напрямую для оптимизации.
- Удаляется не тот товар: убедитесь, что используете
$item->get_product_id(), а не$item->get_variation_id(), если нужно удалить родительский товар. - Ошибки доступа (недостаточно прав): убедитесь, что скрипт выполняется с правами администратора, или используйте функции WordPress с правильными правами.
Практические советы по безопасности и производительности
- Удаление товара — операция необратимая, используйте
wp_delete_post($product_id, false)для перемещения в корзину, чтобы иметь возможность восстановления. - Если товаров много, подумайте об оптимизации поиска заказов с помощью прямых SQL-запросов через $wpdb.
- Добавьте логирование удалений для аудита:
error_log('Product '.$product_id.' deleted after first order '.$order_id); - Проверьте совместимость вашего решения с кеширующими плагинами и CDN, так как удаление товара может не сразу отражаться на фронтенде.
Сравнение вариантов реализации
| Метод | Плюсы | Минусы |
|---|---|---|
Простой вызов wp_delete_post в woocommerce_thankyou | Простая реализация, быстрое внедрение | Плохо масштабируется, может удалить товары ошибочно при высокой нагрузке |
Проверка истории заказов через перебор wc_get_orders | Точная проверка, надежность | Высокая нагрузка при большом количестве заказов, требует оптимизации |
| Использование прямых SQL-запросов для поиска заказов с товаром | Максимальная производительность, масштабируемость | Сложность реализации, риск ошибок при изменениях структуры БД |