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
394 lines
13 KiB
PHP
394 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* Payments REST API Controller
|
|
*
|
|
* Provides REST endpoints for payment gateway management.
|
|
*
|
|
* @package WooNooW
|
|
*/
|
|
|
|
namespace WooNooW\API;
|
|
|
|
use WooNooW\Compat\PaymentGatewaysProvider;
|
|
use WP_REST_Controller;
|
|
use WP_REST_Server;
|
|
use WP_REST_Request;
|
|
use WP_REST_Response;
|
|
use WP_Error;
|
|
|
|
class PaymentsController extends WP_REST_Controller {
|
|
|
|
/**
|
|
* Namespace
|
|
*/
|
|
protected $namespace = 'woonoow/v1';
|
|
|
|
/**
|
|
* Rest base
|
|
*/
|
|
protected $rest_base = 'payments';
|
|
|
|
/**
|
|
* Register routes
|
|
*/
|
|
public function register_routes() {
|
|
// GET /woonoow/v1/payments/gateways
|
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways', [
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [$this, 'get_gateways'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
],
|
|
'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}
|
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/(?P<id>[a-zA-Z0-9_-]+)', [
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [$this, 'get_gateway'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
'args' => [
|
|
'id' => [
|
|
'description' => 'Gateway ID',
|
|
'type' => 'string',
|
|
'required' => true,
|
|
],
|
|
],
|
|
],
|
|
]);
|
|
|
|
// POST /woonoow/v1/payments/gateways/{id}
|
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/(?P<id>[a-zA-Z0-9_-]+)', [
|
|
[
|
|
'methods' => WP_REST_Server::EDITABLE,
|
|
'callback' => [$this, 'save_gateway'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
'args' => [
|
|
'id' => [
|
|
'description' => 'Gateway ID',
|
|
'type' => 'string',
|
|
'required' => true,
|
|
],
|
|
],
|
|
],
|
|
]);
|
|
|
|
// POST /woonoow/v1/payments/gateways/{id}/toggle
|
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/gateways/(?P<id>[a-zA-Z0-9_-]+)/toggle', [
|
|
[
|
|
'methods' => WP_REST_Server::EDITABLE,
|
|
'callback' => [$this, 'toggle_gateway'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
'args' => [
|
|
'id' => [
|
|
'description' => 'Gateway ID',
|
|
'type' => 'string',
|
|
'required' => true,
|
|
],
|
|
'enabled' => [
|
|
'description' => 'Enable or disable gateway',
|
|
'type' => 'boolean',
|
|
'required' => true,
|
|
],
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get all payment gateways
|
|
*
|
|
* @param WP_REST_Request $request Request object
|
|
* @return WP_REST_Response|WP_Error Response object or error
|
|
*/
|
|
public function get_gateways(WP_REST_Request $request) {
|
|
try {
|
|
$gateways = PaymentGatewaysProvider::get_gateways();
|
|
|
|
// Get saved order
|
|
$manual_order = get_option('woonoow_payment_gateway_order_manual', []);
|
|
$online_order = get_option('woonoow_payment_gateway_order_online', []);
|
|
|
|
$response = rest_ensure_response([
|
|
'gateways' => $gateways,
|
|
'order' => [
|
|
'manual' => $manual_order,
|
|
'online' => $online_order,
|
|
],
|
|
]);
|
|
|
|
// Cache for 5 minutes
|
|
$response->header('Cache-Control', 'max-age=300');
|
|
|
|
return $response;
|
|
} catch (\Exception $e) {
|
|
return new WP_Error(
|
|
'get_gateways_failed',
|
|
$e->getMessage(),
|
|
['status' => 500]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get single payment gateway
|
|
*
|
|
* @param WP_REST_Request $request Request object
|
|
* @return WP_REST_Response|WP_Error Response object or error
|
|
*/
|
|
public function get_gateway(WP_REST_Request $request) {
|
|
$gateway_id = $request->get_param('id');
|
|
|
|
try {
|
|
$gateway = PaymentGatewaysProvider::get_gateway($gateway_id);
|
|
|
|
if ($gateway === null) {
|
|
return new WP_Error(
|
|
'gateway_not_found',
|
|
sprintf('Gateway "%s" not found', $gateway_id),
|
|
['status' => 404]
|
|
);
|
|
}
|
|
|
|
$response = rest_ensure_response($gateway);
|
|
|
|
// Cache for 5 minutes
|
|
$response->header('Cache-Control', 'max-age=300');
|
|
|
|
return $response;
|
|
} catch (\Exception $e) {
|
|
return new WP_Error(
|
|
'get_gateway_failed',
|
|
$e->getMessage(),
|
|
['status' => 500]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save gateway settings
|
|
*
|
|
* @param WP_REST_Request $request Request object
|
|
* @return WP_REST_Response|WP_Error Response object or error
|
|
*/
|
|
public function save_gateway(WP_REST_Request $request) {
|
|
$gateway_id = $request->get_param('id');
|
|
$settings = $request->get_json_params();
|
|
|
|
if (empty($settings)) {
|
|
return new WP_Error(
|
|
'missing_settings',
|
|
'No settings provided',
|
|
['status' => 400]
|
|
);
|
|
}
|
|
|
|
try {
|
|
// Debug: Log what we're saving
|
|
error_log(sprintf('[WooNooW] Saving gateway %s settings: %s', $gateway_id, json_encode($settings)));
|
|
|
|
$result = PaymentGatewaysProvider::save_gateway_settings($gateway_id, $settings);
|
|
|
|
if (is_wp_error($result)) {
|
|
error_log(sprintf('[WooNooW] Save failed: %s', $result->get_error_message()));
|
|
return $result;
|
|
}
|
|
|
|
// Clear cache before fetching updated gateway
|
|
wp_cache_flush();
|
|
|
|
// Return updated gateway data (fresh from DB)
|
|
$gateway = PaymentGatewaysProvider::get_gateway($gateway_id);
|
|
|
|
// Debug: Log success
|
|
error_log(sprintf('[WooNooW] Gateway %s settings saved successfully', $gateway_id));
|
|
|
|
return rest_ensure_response([
|
|
'success' => true,
|
|
'message' => 'Gateway settings saved successfully',
|
|
'gateway' => $gateway,
|
|
]);
|
|
} catch (\Exception $e) {
|
|
error_log(sprintf('[WooNooW] Save exception: %s', $e->getMessage()));
|
|
return new WP_Error(
|
|
'save_gateway_failed',
|
|
$e->getMessage(),
|
|
['status' => 500]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle gateway enabled status
|
|
*
|
|
* @param WP_REST_Request $request Request object
|
|
* @return WP_REST_Response|WP_Error Response object or error
|
|
*/
|
|
public function toggle_gateway(WP_REST_Request $request) {
|
|
$gateway_id = $request->get_param('id');
|
|
$enabled = $request->get_param('enabled');
|
|
|
|
// Convert to boolean (handles both bool and string "true"/"false")
|
|
$enabled = filter_var($enabled, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
|
|
if ($enabled === null) {
|
|
return new WP_Error(
|
|
'invalid_enabled_value',
|
|
'The "enabled" parameter must be a boolean',
|
|
['status' => 400]
|
|
);
|
|
}
|
|
|
|
try {
|
|
// Debug: Log what we're trying to do
|
|
error_log(sprintf('[WooNooW] Toggling gateway %s to %s', $gateway_id, $enabled ? 'enabled' : 'disabled'));
|
|
|
|
$result = PaymentGatewaysProvider::toggle_gateway($gateway_id, $enabled);
|
|
|
|
if (is_wp_error($result)) {
|
|
error_log(sprintf('[WooNooW] Toggle failed: %s', $result->get_error_message()));
|
|
return $result;
|
|
}
|
|
|
|
// Clear cache before fetching updated gateway
|
|
wp_cache_flush();
|
|
|
|
// Return updated gateway data (fresh from DB)
|
|
$gateway = PaymentGatewaysProvider::get_gateway($gateway_id);
|
|
|
|
// Debug: Log what we got back
|
|
error_log(sprintf('[WooNooW] Gateway %s after toggle: enabled=%s', $gateway_id, $gateway['enabled'] ? 'true' : 'false'));
|
|
|
|
return rest_ensure_response([
|
|
'success' => true,
|
|
'message' => $enabled ? 'Gateway enabled' : 'Gateway disabled',
|
|
'gateway' => $gateway,
|
|
]);
|
|
} catch (\Exception $e) {
|
|
error_log(sprintf('[WooNooW] Toggle exception: %s', $e->getMessage()));
|
|
return new WP_Error(
|
|
'toggle_gateway_failed',
|
|
$e->getMessage(),
|
|
['status' => 500]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save gateway order
|
|
*
|
|
* @param WP_REST_Request $request Request object
|
|
* @return WP_REST_Response|WP_Error Response object or error
|
|
*/
|
|
public function save_gateway_order(WP_REST_Request $request) {
|
|
$category = $request->get_param('category');
|
|
$order = $request->get_param('order');
|
|
|
|
// Validate category
|
|
if (!in_array($category, ['manual', 'online'], true)) {
|
|
return new WP_Error(
|
|
'invalid_category',
|
|
'Category must be either "manual" or "online"',
|
|
['status' => 400]
|
|
);
|
|
}
|
|
|
|
// Validate order is array
|
|
if (!is_array($order)) {
|
|
return new WP_Error(
|
|
'invalid_order',
|
|
'Order must be an array of gateway IDs',
|
|
['status' => 400]
|
|
);
|
|
}
|
|
|
|
// Save to WordPress options
|
|
$option_key = 'woonoow_payment_gateway_order_' . $category;
|
|
update_option($option_key, $order, false);
|
|
|
|
error_log(sprintf('[WooNooW] Saved %s gateway order: %s', $category, implode(', ', $order)));
|
|
|
|
return rest_ensure_response([
|
|
'success' => true,
|
|
'message' => 'Gateway order saved successfully',
|
|
'category' => $category,
|
|
'order' => $order,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Check permission
|
|
*
|
|
* @return bool True if user has permission
|
|
*/
|
|
public function check_permission() {
|
|
return current_user_can('manage_woocommerce');
|
|
}
|
|
|
|
/**
|
|
* Get gateways collection schema
|
|
*
|
|
* @return array Schema
|
|
*/
|
|
public function get_gateways_schema() {
|
|
return [
|
|
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
|
'title' => 'payment-gateways',
|
|
'type' => 'array',
|
|
'items' => [
|
|
'type' => 'object',
|
|
'properties' => [
|
|
'id' => [
|
|
'description' => 'Gateway ID',
|
|
'type' => 'string',
|
|
],
|
|
'title' => [
|
|
'description' => 'Gateway title',
|
|
'type' => 'string',
|
|
],
|
|
'description' => [
|
|
'description' => 'Gateway description',
|
|
'type' => 'string',
|
|
],
|
|
'enabled' => [
|
|
'description' => 'Whether gateway is enabled',
|
|
'type' => 'boolean',
|
|
],
|
|
'type' => [
|
|
'description' => 'Gateway type',
|
|
'type' => 'string',
|
|
'enum' => ['manual', 'provider', 'other'],
|
|
],
|
|
],
|
|
],
|
|
];
|
|
}
|
|
}
|