Диагностика проблемы: зачем запрещать новые заказы на предоплаченные товары
В WooCommerce иногда требуется ограничить возможность создавать новые заказы на товары, которые уже были предоплачены или находятся в специальном статусе. Это актуально, если товары выпускаются ограниченным тиражом, или заказчик уже оплатил партию товаров и повторный заказ нежелателен, чтобы избежать дублирования платежей и ошибок в учёте.
Чаще всего такие ограничения нужны в кастомных магазинах с предоплатой или подписками, где стандартных настроек WooCommerce недостаточно для точной фильтрации заказов.
Как проверить, что заказ создаётся на предоплаченный товар
Для реализации запрета необходимо определить критерии, по которым товар считается предоплаченным. Варианты:
- Наличие мета-поля
_prepaidсо значениемyesу товара. - Присутствие категории или тега, например,
prepaid. - Специальный статус или пользовательская таксономия.
Для диагностики можно вывести список товаров в корзине с их мета-полями и таксономиями:
add_action('woocommerce_check_cart_items', function() {
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$prepaid = get_post_meta($product->get_id(), '_prepaid', true);
error_log('Product ID: ' . $product->get_id() . ', prepaid: ' . $prepaid);
}
});Просмотр логов error_log (например, через плагин Debug Log) покажет, какие товары помечены как предоплаченные.
Пошаговое решение: запрет создания новых заказов с предоплаченными товарами
1. Добавляем мета-поле «_prepaid» к товарам
В админке WooCommerce в режиме редактирования товара добавьте пользовательское поле _prepaid со значением yes для тех товаров, на которые нужно запретить повторный заказ.
2. Блокируем оформление заказа, если в корзине есть такие товары
В файл functions.php вашей дочерней темы или в кастомный плагин добавьте следующий код:
add_action('woocommerce_check_cart_items', function() {
foreach (WC()->cart->get_cart() as $cart_item) {
$product = $cart_item['data'];
$prepaid = get_post_meta($product->get_id(), '_prepaid', true);
if ($prepaid === 'yes') {
wc_add_notice('Вы не можете оформить заказ: в корзине есть предоплаченные товары.', 'error');
break;
}
}
});Этот хук срабатывает при проверке корзины перед оформлением заказа. При обнаружении предоплаченного товара оформление блокируется с выводом ошибки.
3. Дополнительно: удаление таких товаров из корзины
Если нужно не только запретить оформление, но и очистить корзину от этих товаров, добавьте:
add_action('woocommerce_check_cart_items', function() {
$removed = false;
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$prepaid = get_post_meta($product->get_id(), '_prepaid', true);
if ($prepaid === 'yes') {
WC()->cart->remove_cart_item($cart_item_key);
$removed = true;
}
}
if ($removed) {
wc_add_notice('Предоплаченные товары были удалены из корзины.', 'notice');
}
});Проверка результата после внедрения
Чтобы проверить, что запрет работает:
- Добавьте в корзину товар с мета-полем
_prepaid = yes. - Перейдите к оформлению заказа.
- Должна появиться ошибка, и оформление будет заблокировано.
- Если включено удаление, товар должен автоматически удаляться из корзины с уведомлением.
Для полноты тестирования попробуйте добавить в корзину обычные товары — оформление должно пройти без ошибок.
Частые ошибки и как их исправить
- Ошибка: Запрет не срабатывает — мета-поле не читается.
Причина: Неверный ключ мета-поля или оно не сохранено.
Решение: Проверьте через базу данных или админку, что_prepaidдействительно хранится у товара. - Ошибка: Запрет срабатывает на все товары.
Причина: Логика проверки мета-поля реализована с ошибкой (например, сравнение сtrueвместо строкиyes).
Решение: Убедитесь, что условие строго проверяет значение'yes'. - Ошибка: После удаления товара из корзины оформление всё равно заблокировано.
Причина: Кэширование или конфликт с другими плагинами.
Решение: Очистите кэш и проверьте совместимость плагинов.
Практические советы по безопасности и производительности
- Используйте транзиенты или объектный кэш для частой проверки статуса предоплаты, если товаров много и проверка мета-полей нагружает базу.
- При добавлении мета-поля используйте стандартные методы WordPress (
update_post_meta) и избегайте прямых SQL-запросов. - Оповещайте пользователя понятным сообщением, чтобы избежать повторных попыток оформить заказ с запрещёнными товарами.
- Регулярно проверяйте актуальность мета-данных, чтобы не блокировать случайно обычные товары.
Сравнение способов реализации запрета оформления
| Метод | Плюсы | Минусы | Пример кода |
|---|---|---|---|
| Проверка мета-поля _prepaid | Гибко, легко добавить к товарам | Нужно вручную выставлять поле | Пример выше |
| Проверка категории/тега prepaid | Можно массово применять через категории | Нужно фильтровать таксономии | |
| Хранение статуса в отдельной таблице | Оптимально при большом количестве товаров | Сложнее поддерживать, требует кастомной логики | Требует отдельной реализации |