From 7bab3d809d9f46d40fd894473db5b76fa3cfba3d Mon Sep 17 00:00:00 2001 From: dwindown Date: Wed, 19 Nov 2025 23:04:58 +0700 Subject: [PATCH] fix: PHP Fatal Error and attribute input UX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical Fixes: 1. ✅ PHP Fatal Error - FIXED Problem: call_user_func() error - Permissions::check_admin does not exist Cause: Method name mismatch in ProductsController.php Solution: Changed all 8 occurrences from: 'permission_callback' => [Permissions::class, 'check_admin'] To: 'permission_callback' => [Permissions::class, 'check_admin_permission'] Affected routes: - GET /products - GET /products/:id - POST /products - PUT /products/:id - DELETE /products/:id - GET /products/categories - GET /products/tags - GET /products/attributes 2. ✅ Attribute Options Input - FIXED Problem: Cannot type anything after first word (cursor jumps) Cause: Controlled input with immediate state update on onChange Solution: Changed to uncontrolled input with onBlur Changes: - value → defaultValue (uncontrolled) - onChange → onBlur (update on blur) - Added key prop for proper re-rendering - Added onKeyDown for Enter key support - Updated help text: "press Enter or click away" Now you can: ✅ Type: Red, Blue, Green (naturally!) ✅ Type: Red | Blue | Green (pipe works too!) ✅ Press Enter to save ✅ Click away to save ✅ No cursor jumping! Result: - Products index page loads without PHP error - Attribute options input works naturally - Both comma and pipe separators supported --- .../Products/partials/tabs/VariationsTab.tsx | 13 ++++++++++--- includes/Api/ProductsController.php | 16 ++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx b/admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx index 38b111c..c242967 100644 --- a/admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx +++ b/admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx @@ -136,8 +136,9 @@ export function VariationsTab({
{ + key={`options-${index}-${attr.options.length}`} + defaultValue={attr.options.join(', ')} + onBlur={(e) => { const input = e.target.value; // Split by comma or pipe, trim whitespace const options = input @@ -146,11 +147,17 @@ export function VariationsTab({ .filter(Boolean); updateAttribute(index, 'options', options); }} + onKeyDown={(e) => { + // Update on Enter key + if (e.key === 'Enter') { + e.currentTarget.blur(); + } + }} placeholder={__('Red, Blue, Green (comma or pipe separated)')} className="mt-1.5" />

- {__('Type naturally: Red, Blue, Green (comma or | works)')} + {__('Type naturally: Red, Blue, Green (press Enter or click away)')}

diff --git a/includes/Api/ProductsController.php b/includes/Api/ProductsController.php index 67d8b59..00c382a 100644 --- a/includes/Api/ProductsController.php +++ b/includes/Api/ProductsController.php @@ -28,56 +28,56 @@ class ProductsController { register_rest_route('woonoow/v1', '/products', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_products'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Get single product register_rest_route('woonoow/v1', '/products/(?P\d+)', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_product'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Create product register_rest_route('woonoow/v1', '/products', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'create_product'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Update product register_rest_route('woonoow/v1', '/products/(?P\d+)', [ 'methods' => 'PUT', 'callback' => [__CLASS__, 'update_product'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Delete product register_rest_route('woonoow/v1', '/products/(?P\d+)', [ 'methods' => 'DELETE', 'callback' => [__CLASS__, 'delete_product'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Get product categories register_rest_route('woonoow/v1', '/products/categories', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_categories'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Get product tags register_rest_route('woonoow/v1', '/products/tags', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_tags'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); // Get product attributes register_rest_route('woonoow/v1', '/products/attributes', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_attributes'], - 'permission_callback' => [Permissions::class, 'check_admin'], + 'permission_callback' => [Permissions::class, 'check_admin_permission'], ]); }