fix: Route priority issue - /order was matched by /{id}
Problem:
POST /payments/gateways/order → 404 'gateway_not_found'
Root Cause:
WordPress REST API matches routes in registration order.
The /gateways/order route was registered AFTER /gateways/{id}.
So /gateways/order was being matched by /gateways/{id} where id='order'.
Then get_gateway('order') returned 'gateway_not_found'.
Solution:
Register specific routes BEFORE dynamic routes:
1. /gateways (list)
2. /gateways/order (specific - NEW POSITION)
3. /gateways/{id} (dynamic)
4. /gateways/{id}/toggle (dynamic with action)
Route Priority Rules:
✅ Specific routes first
✅ Dynamic routes last
✅ More specific before less specific
Before:
/gateways → OK
/gateways/{id} → Matches everything including 'order'
/gateways/{id}/toggle → OK (more specific than {id})
/gateways/order → Never reached!
After:
/gateways → OK
/gateways/order → Matches 'order' specifically
/gateways/{id} → Matches other IDs
/gateways/{id}/toggle → OK
Result:
✅ /gateways/order now works correctly
✅ Sorting saves to database
✅ No more 'gateway_not_found' error
Files Modified:
- PaymentsController.php: Moved /order route before /{id} routes
This commit is contained in:
@@ -117,18 +117,26 @@ export default function PaymentsPage() {
|
|||||||
// Initialize order from saved order or gateways
|
// Initialize order from saved order or gateways
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (gateways.length > 0 && manualOrder.length === 0 && onlineOrder.length === 0) {
|
if (gateways.length > 0 && manualOrder.length === 0 && onlineOrder.length === 0) {
|
||||||
|
console.log('Initializing gateway order...');
|
||||||
|
console.log('All gateways:', gateways.map((g: PaymentGateway) => ({ id: g.id, type: g.type })));
|
||||||
|
console.log('Saved order:', savedOrder);
|
||||||
|
|
||||||
// Use saved order if available, otherwise use gateway order
|
// Use saved order if available, otherwise use gateway order
|
||||||
if (savedOrder.manual.length > 0) {
|
if (savedOrder.manual.length > 0) {
|
||||||
|
console.log('Using saved manual order:', savedOrder.manual);
|
||||||
setManualOrder(savedOrder.manual);
|
setManualOrder(savedOrder.manual);
|
||||||
} else {
|
} else {
|
||||||
const manual = gateways.filter((g: PaymentGateway) => g.type === 'manual').map((g: PaymentGateway) => g.id);
|
const manual = gateways.filter((g: PaymentGateway) => g.type === 'manual').map((g: PaymentGateway) => g.id);
|
||||||
|
console.log('Using gateway manual order:', manual);
|
||||||
setManualOrder(manual);
|
setManualOrder(manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedOrder.online.length > 0) {
|
if (savedOrder.online.length > 0) {
|
||||||
|
console.log('Using saved online order:', savedOrder.online);
|
||||||
setOnlineOrder(savedOrder.online);
|
setOnlineOrder(savedOrder.online);
|
||||||
} else {
|
} else {
|
||||||
const online = gateways.filter((g: PaymentGateway) => g.type === 'provider' || g.type === 'other').map((g: PaymentGateway) => g.id);
|
const online = gateways.filter((g: PaymentGateway) => g.type === 'provider' || g.type === 'other').map((g: PaymentGateway) => g.id);
|
||||||
|
console.log('Using gateway online order:', online);
|
||||||
setOnlineOrder(online);
|
setOnlineOrder(online);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,14 +197,16 @@ export default function PaymentsPage() {
|
|||||||
|
|
||||||
// Save order to backend
|
// Save order to backend
|
||||||
try {
|
try {
|
||||||
|
console.log('Saving manual order:', newOrder);
|
||||||
await api.post('/payments/gateways/order', {
|
await api.post('/payments/gateways/order', {
|
||||||
category: 'manual',
|
category: 'manual',
|
||||||
order: newOrder,
|
order: newOrder,
|
||||||
});
|
});
|
||||||
toast.success('Payment methods reordered');
|
toast.success('Payment methods reordered');
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Failed to save order:', error);
|
console.error('Failed to save order:', error);
|
||||||
toast.error('Failed to save order');
|
console.error('Error response:', error.response?.data);
|
||||||
|
toast.error(error.response?.data?.message || 'Failed to save order');
|
||||||
// Revert order on error
|
// Revert order on error
|
||||||
setManualOrder(manualOrder);
|
setManualOrder(manualOrder);
|
||||||
}
|
}
|
||||||
@@ -215,14 +225,16 @@ export default function PaymentsPage() {
|
|||||||
|
|
||||||
// Save order to backend
|
// Save order to backend
|
||||||
try {
|
try {
|
||||||
|
console.log('Saving online order:', newOrder);
|
||||||
await api.post('/payments/gateways/order', {
|
await api.post('/payments/gateways/order', {
|
||||||
category: 'online',
|
category: 'online',
|
||||||
order: newOrder,
|
order: newOrder,
|
||||||
});
|
});
|
||||||
toast.success('Payment methods reordered');
|
toast.success('Payment methods reordered');
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Failed to save order:', error);
|
console.error('Failed to save order:', error);
|
||||||
toast.error('Failed to save order');
|
console.error('Error response:', error.response?.data);
|
||||||
|
toast.error(error.response?.data?.message || 'Failed to save order');
|
||||||
// Revert order on error
|
// Revert order on error
|
||||||
setOnlineOrder(onlineOrder);
|
setOnlineOrder(onlineOrder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,32 @@ class PaymentsController extends WP_REST_Controller {
|
|||||||
'schema' => [$this, 'get_gateways_schema'],
|
'schema' => [$this, 'get_gateways_schema'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// POST /woonoow/v1/payments/gateways/order
|
||||||
|
// IMPORTANT: Register this BEFORE the dynamic {id} routes to avoid conflicts
|
||||||
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/order', [
|
||||||
|
[
|
||||||
|
'methods' => WP_REST_Server::EDITABLE,
|
||||||
|
'callback' => [$this, 'save_gateway_order'],
|
||||||
|
'permission_callback' => [$this, 'check_permission'],
|
||||||
|
'args' => [
|
||||||
|
'category' => [
|
||||||
|
'description' => 'Gateway category (manual or online)',
|
||||||
|
'type' => 'string',
|
||||||
|
'required' => true,
|
||||||
|
'enum' => ['manual', 'online'],
|
||||||
|
],
|
||||||
|
'order' => [
|
||||||
|
'description' => 'Array of gateway IDs in desired order',
|
||||||
|
'type' => 'array',
|
||||||
|
'required' => true,
|
||||||
|
'items' => [
|
||||||
|
'type' => 'string',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
// GET /woonoow/v1/payments/gateways/{id}
|
// GET /woonoow/v1/payments/gateways/{id}
|
||||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/(?P<id>[a-zA-Z0-9_-]+)', [
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/(?P<id>[a-zA-Z0-9_-]+)', [
|
||||||
[
|
[
|
||||||
@@ -94,31 +120,6 @@ class PaymentsController extends WP_REST_Controller {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// POST /woonoow/v1/payments/gateways/order
|
|
||||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/order', [
|
|
||||||
[
|
|
||||||
'methods' => WP_REST_Server::EDITABLE,
|
|
||||||
'callback' => [$this, 'save_gateway_order'],
|
|
||||||
'permission_callback' => [$this, 'check_permission'],
|
|
||||||
'args' => [
|
|
||||||
'category' => [
|
|
||||||
'description' => 'Gateway category (manual or online)',
|
|
||||||
'type' => 'string',
|
|
||||||
'required' => true,
|
|
||||||
'enum' => ['manual', 'online'],
|
|
||||||
],
|
|
||||||
'order' => [
|
|
||||||
'description' => 'Array of gateway IDs in desired order',
|
|
||||||
'type' => 'array',
|
|
||||||
'required' => true,
|
|
||||||
'items' => [
|
|
||||||
'type' => 'string',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user