Диагностика проблемы: почему нужно ограничить отмену заказов по ролям
В интернет-магазинах на WooCommerce иногда возникает необходимость ограничить отмену заказов для разных групп пользователей. Например, для оптовиков или VIP-клиентов отмена заказа может быть запрещена, чтобы избежать потери прибыли и упростить обработку заказов. По умолчанию WooCommerce не предоставляет гибких настроек для управления отменой заказов по ролям пользователей, поэтому требуется вмешательство через код.
Как работает отмена заказа в WooCommerce
Отмена заказа в WooCommerce — это изменение статуса заказа на "Отменён" (cancelled). Пользователь может отменить заказ через личный кабинет, если статус заказа позволяет это сделать, а также администратор может делать это вручную. Для реализации ограничения нам нужно перехватить попытку отмены и проверить роль пользователя.
Пошаговое решение: запрет отмены заказа для определённых ролей
1. Определяем роли, для которых запрещена отмена
В примере запретим отмену для пользователей с ролью wholesale_customer и vip_client.
2. Добавляем фильтр на изменение статуса заказа
Используем хук woocommerce_before_order_object_save для проверки попытки смены статуса на cancelled.
add_action('woocommerce_before_order_object_save', function($order) {
if (!$order instanceof WC_Order) return;
// Получаем текущего пользователя
$user_id = get_current_user_id();
if (!$user_id) return; // Неавторизованный пользователь
$user = get_userdata($user_id);
$forbidden_roles = ['wholesale_customer', 'vip_client'];
// Проверяем, пытается ли изменить статус на отменён
$new_status = $order->get_status();
$old_status = $order->get_meta('_old_status');
// Сохраняем старый статус для следующей проверки
if (!$old_status) {
$order->update_meta_data('_old_status', $new_status);
return;
}
if ($new_status === 'cancelled' && in_array($old_status, ['processing', 'on-hold', 'pending'])) {
// Проверяем роль пользователя
foreach ($forbidden_roles as $role) {
if (in_array($role, $user->roles)) {
// Отменяем смену статуса
$order->set_status($old_status);
wc_add_notice('Отмена заказа запрещена для вашей роли пользователя.', 'error');
// Прерываем дальнейшее сохранение
remove_action('woocommerce_before_order_object_save', __FUNCTION__);
wp_die('Отмена заказа запрещена для вашей роли пользователя.');
}
}
}
// Обновляем мета с текущим статусом
$order->update_meta_data('_old_status', $new_status);
});3. Обработка отмены заказа из личного кабинета
Пользователь может отменять заказ через AJAX или форму. Для UX лучше отключить кнопку отмены, если роль пользователя запрещает отмену. Добавим JS через хук wp_footer и проверим роль.
add_action('wp_footer', function() {
if (!is_account_page()) return;
$user = wp_get_current_user();
$forbidden_roles = ['wholesale_customer', 'vip_client'];
foreach ($forbidden_roles as $role) {
if (in_array($role, $user->roles)) {
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('a.cancel-order').forEach(function(btn) {
btn.style.pointerEvents = 'none';
btn.style.opacity = '0.5';
btn.title = 'Отмена заказа запрещена для вашей роли';
});
});
</script>
<?php
break;
}
}
});Проверка результата после внедрения
- Авторизуйтесь под пользователем с ролью
wholesale_customerилиvip_client. - Перейдите в Личный кабинет → Заказы.
- Убедитесь, что кнопка отмены заказа либо неактивна, либо при попытке отмены появляется сообщение об ошибке.
- Попробуйте отменить заказ из админки — ограничение не действует для администратора.
Частые ошибки и как их исправить
- Ошибка: Смена статуса заказа не блокируется.
Причина: Хукwoocommerce_before_order_object_saveне срабатывает, потому что код добавлен в неподходящем месте или кэш мешает.
Решение: Убедитесь, что код добавлен в functions.php активной темы или в плагине, отключите кэширование и протестируйте. - Ошибка: Пользователь видит кнопку отмены, но при клике ничего не происходит.
Причина: JS не подключился из-за неправильных условий или кэширования.
Решение: Проверьте, что скрипт выводится на странице Личного кабинета, очистите кэш браузера. - Ошибка: При отмене заказа в админке не появляется сообщение об ошибке.
Причина:wp_die()прерывает работу без вывода сообщения в UI.
Решение: Для админки можно добавить уведомление черезadmin_noticesили использовать другой способ отмены статуса.
Практические советы по безопасности и производительности
- Проверяйте роли пользователей не через жёсткое сравнение, а через
in_array()с массивом ролей — это предотвращает проблемы с кастомными ролями. - Не используйте
wp_die()без явной необходимости — лучше возвращать ошибки через WooCommerce notices, чтобы не прерывать скрипт. - Кэшируйте данные пользователей и статусы заказов аккуратно, чтобы не потерять актуальность проверки.
- Для улучшения UX отключайте кнопку отмены на фронтенде для запрещённых ролей, а не только блокируйте серверный запрос.
- Тестируйте на разных ролях и сценариях, особенно если используете кастомные роли или плагин для управления ролями.
Сравнение способов реализации запрета отмены заказа
| Метод | Плюсы | Минусы |
|---|---|---|
Серверная проверка через woocommerce_before_order_object_save | Надёжно, блокирует отмену полностью | Менее дружелюбно в UX, требует правильного использования хуков |
| Отключение кнопки отмены через JS | Улучшает UX, предотвращает попытки отмены | Можно обойти, если отключен JS; требует серверной проверки |
| Полная замена шаблонов WooCommerce | Гибкий контроль интерфейса | Сложнее в поддержке, зависит от обновлений WooCommerce |