fix: PHP Fatal Error and attribute input UX
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
This commit is contained in:
@@ -136,8 +136,9 @@ export function VariationsTab({
|
|||||||
<div>
|
<div>
|
||||||
<Label>{__('Options')}</Label>
|
<Label>{__('Options')}</Label>
|
||||||
<Input
|
<Input
|
||||||
value={attr.options.join(', ')}
|
key={`options-${index}-${attr.options.length}`}
|
||||||
onChange={(e) => {
|
defaultValue={attr.options.join(', ')}
|
||||||
|
onBlur={(e) => {
|
||||||
const input = e.target.value;
|
const input = e.target.value;
|
||||||
// Split by comma or pipe, trim whitespace
|
// Split by comma or pipe, trim whitespace
|
||||||
const options = input
|
const options = input
|
||||||
@@ -146,11 +147,17 @@ export function VariationsTab({
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
updateAttribute(index, 'options', options);
|
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)')}
|
placeholder={__('Red, Blue, Green (comma or pipe separated)')}
|
||||||
className="mt-1.5"
|
className="mt-1.5"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
{__('Type naturally: Red, Blue, Green (comma or | works)')}
|
{__('Type naturally: Red, Blue, Green (press Enter or click away)')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,56 +28,56 @@ class ProductsController {
|
|||||||
register_rest_route('woonoow/v1', '/products', [
|
register_rest_route('woonoow/v1', '/products', [
|
||||||
'methods' => 'GET',
|
'methods' => 'GET',
|
||||||
'callback' => [__CLASS__, 'get_products'],
|
'callback' => [__CLASS__, 'get_products'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get single product
|
// Get single product
|
||||||
register_rest_route('woonoow/v1', '/products/(?P<id>\d+)', [
|
register_rest_route('woonoow/v1', '/products/(?P<id>\d+)', [
|
||||||
'methods' => 'GET',
|
'methods' => 'GET',
|
||||||
'callback' => [__CLASS__, 'get_product'],
|
'callback' => [__CLASS__, 'get_product'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create product
|
// Create product
|
||||||
register_rest_route('woonoow/v1', '/products', [
|
register_rest_route('woonoow/v1', '/products', [
|
||||||
'methods' => 'POST',
|
'methods' => 'POST',
|
||||||
'callback' => [__CLASS__, 'create_product'],
|
'callback' => [__CLASS__, 'create_product'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Update product
|
// Update product
|
||||||
register_rest_route('woonoow/v1', '/products/(?P<id>\d+)', [
|
register_rest_route('woonoow/v1', '/products/(?P<id>\d+)', [
|
||||||
'methods' => 'PUT',
|
'methods' => 'PUT',
|
||||||
'callback' => [__CLASS__, 'update_product'],
|
'callback' => [__CLASS__, 'update_product'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Delete product
|
// Delete product
|
||||||
register_rest_route('woonoow/v1', '/products/(?P<id>\d+)', [
|
register_rest_route('woonoow/v1', '/products/(?P<id>\d+)', [
|
||||||
'methods' => 'DELETE',
|
'methods' => 'DELETE',
|
||||||
'callback' => [__CLASS__, 'delete_product'],
|
'callback' => [__CLASS__, 'delete_product'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get product categories
|
// Get product categories
|
||||||
register_rest_route('woonoow/v1', '/products/categories', [
|
register_rest_route('woonoow/v1', '/products/categories', [
|
||||||
'methods' => 'GET',
|
'methods' => 'GET',
|
||||||
'callback' => [__CLASS__, 'get_categories'],
|
'callback' => [__CLASS__, 'get_categories'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get product tags
|
// Get product tags
|
||||||
register_rest_route('woonoow/v1', '/products/tags', [
|
register_rest_route('woonoow/v1', '/products/tags', [
|
||||||
'methods' => 'GET',
|
'methods' => 'GET',
|
||||||
'callback' => [__CLASS__, 'get_tags'],
|
'callback' => [__CLASS__, 'get_tags'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get product attributes
|
// Get product attributes
|
||||||
register_rest_route('woonoow/v1', '/products/attributes', [
|
register_rest_route('woonoow/v1', '/products/attributes', [
|
||||||
'methods' => 'GET',
|
'methods' => 'GET',
|
||||||
'callback' => [__CLASS__, 'get_attributes'],
|
'callback' => [__CLASS__, 'get_attributes'],
|
||||||
'permission_callback' => [Permissions::class, 'check_admin'],
|
'permission_callback' => [Permissions::class, 'check_admin_permission'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user