Диагностика задачи: зачем удалять товар после первого заказа в WooCommerce
В некоторых бизнес-сценариях требуется, чтобы товар в магазине исчезал сразу после его первой покупки. Например, это может быть уникальный лот, цифровой продукт с ограниченным числом лицензий или эксклюзивное предложение. По умолчанию WooCommerce не предоставляет функционала для автоматического удаления товара после первого заказа. Нужно реализовать это самостоятельно через хуки и кастомный код.
Как определить, что товар был куплен впервые
Для начала нужно понять, как отследить первую покупку товара. WooCommerce хранит данные о заказах и их содержимом. В нашем случае, при создании нового заказа, мы проверим, есть ли уже заказы с данным товаром.
Пример кода для проверки первого заказа с товаром
function is_first_order_for_product( $product_id ) {
$args = array(
'limit' => 1,
'status' => array('completed', 'processing'),
'return' => 'ids',
'meta_query' => array(),
);
$orders = wc_get_orders( $args );
foreach ( $orders as $order_id ) {
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item ) {
if ( $item->get_product_id() == $product_id ) {
return false; // Уже есть заказ с этим товаром
}
}
}
return true; // Заказов с этим товаром нет
}Однако такой подход неэффективен, так как он перебирает все заказы. Лучше проверить количество заказов с данным товаром напрямую в базе с помощью WP_Query или SQL.
Пошаговое решение: автоматическое удаление товара после первого заказа
Реализация состоит из двух частей:
- Отслеживание события создания заказа и проверка, содержит ли он товар, который нужно удалить.
- Удаление товара из базы данных и очистка связанных данных.
Обработка события завершения заказа
Подключаемся к хуку woocommerce_order_status_completed, который вызывается при смене статуса заказа на "завершен". Это гарантирует, что платеж прошёл успешно.
add_action( 'woocommerce_order_status_completed', 'wc_delete_product_after_first_order' );
function wc_delete_product_after_first_order( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) return;
foreach ( $order->get_items() as $item ) {
$product_id = $item->get_product_id();
// Проверяем, был ли это первый заказ с этим товаром
if ( wc_is_first_order_for_product( $product_id ) ) {
wp_delete_post( $product_id, true ); // Безвозвратно удаляем товар
}
}
}Оптимизированная функция проверки первого заказа
Чтобы не перебирать заказы вручную, используем SQL-запрос для проверки наличия заказов с данным товаром:
function wc_is_first_order_for_product( $product_id ) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT COUNT(*) 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 p.ID = oi.order_id
WHERE oi.order_item_type = 'line_item'
AND oim.meta_key = '_product_id'
AND oim.meta_value = %d
AND p.post_type = 'shop_order'
AND p.post_status IN ('wc-completed', 'wc-processing')",
$product_id
);
$count = $wpdb->get_var( $query );
return ( $count == 1 ); // Если ровно 1 заказ (текущий), значит первый
}Проверка результата после внедрения
- Создайте тестовый товар с уникальным названием.
- Оформите заказ, добавив этот товар.
- После смены статуса заказа на "завершен" товар должен исчезнуть из каталога и админки.
- Проверьте, что при попытке просмотреть товар по ID возвращается 404.
- Убедитесь, что другие товары не удаляются.
Частые ошибки и как их исправить
- Товар не удаляется после заказа: Проверьте, что статус заказа действительно меняется на
completed. Возможно, ваш магазин использует другой статус для подтверждённых заказов. - Удаляются все товары заказа: Если хотите ограничить удаление только определёнными товарами, добавьте фильтр по ID или категории.
- Ошибка при удалении из-за прав доступа: Убедитесь, что код выполняется с правами администратора и в нужном контексте (на сервере, не в AJAX без авторизации).
Практические советы по безопасности и производительности
- Используйте
wp_delete_post( $product_id, true )для полного удаления, чтобы не оставлять мусор в базе. - Если товаров много, и вы хотите массово проверять, используйте отдельный WP-CLI скрипт.
- Логируйте удаление товаров в отдельный файл для аудита и возможного восстановления.
- Если у вас есть плагины кеширования, очистите кеш после удаления товара.
Дополнительные рекомендации: ограничение удаления по условию
Если нужно удалять не все товары, а только из определённой категории или с меткой, добавьте проверку:
function wc_delete_product_after_first_order( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) return;
foreach ( $order->get_items() as $item ) {
$product_id = $item->get_product_id();
// Проверяем категорию
if ( has_term( 'unique-items', 'product_cat', $product_id ) ) {
if ( wc_is_first_order_for_product( $product_id ) ) {
wp_delete_post( $product_id, true );
}
}
}
}Сравнительная таблица вариантов реализации удаления товаров после заказа
| Метод | Плюсы | Минусы | Компромисс |
|---|---|---|---|
| Плагин для удаления товаров после продажи | Простота, готовое решение | Редко встречаются, могут быть платными и ограниченными | Использование плагина для базовых сценариев |
| Кастомный код с хуками WooCommerce | Полный контроль, гибкость | Требует навыков программирования, возможно ошибки | Идеально для уникальных требований |
| Ручное удаление товаров после заказа | Простота | Не автоматизировано, риск ошибок, требует времени | Для единичных или очень редких товаров |