Found the issue from debug log:
- WooCommerce stores as: attribute_Color (exact case match)
- We were trying: attribute_color (lowercase) ❌
Fixed:
- Use 'attribute_' + exact attribute name
- get_post_meta with true flag returns single value (not array)
Result:
- Variation #362: {"Color": "Red"} ✅
- Variation #363: {"Color": "Blue"} ✅
Removed debug logging as requested.
Added logging to see ALL meta keys and values for variations.
This will show us exactly how WooCommerce stores the attribute values.
Check debug.log for:
Variation #362 ALL META: Array(...)
This will reveal the actual meta key format.
Fixed empty attribute values in variations.
WooCommerce stores variation attributes in post meta:
- Key format: 'attribute_' + lowercase attribute name
- Example: 'attribute_color' → 'red'
Changes:
1. Try lowercase: attribute_color
2. Fallback to sanitized: attribute_pa-color
3. Capitalize name for display: Color
This should now show:
- Before: {"Color": ""}
- After: {"Color": "Red"} or {"Color": "Blue"}
Test by refreshing edit product page.
Wrapped entire get_products() in try-catch.
Will log:
- START when function begins
- END SUCCESS when completes
- ERROR + stack trace if exception thrown
This will reveal if there's a PHP error causing silent failure.
Testing if [__CLASS__, 'get_products'] is callable.
If NO, PHP cannot call the method (maybe method doesn't exist or wrong visibility).
If YES but still not called, WordPress routing issue.
Added logging to verify:
1. register_routes() is called
2. register_rest_route() returns success/failure
This will show if route registration is actually working.
If we see FAILED, it means another plugin/route is conflicting.
If we see SUCCESS but get_products() not called, routing issue.
Added logging at 3 critical points:
1. rest_api_init hook firing
2. Before ProductsController::register_routes()
3. After ProductsController::register_routes()
4. Inside ProductsController::get_products()
This will show us:
- Is rest_api_init hook firing?
- Is ProductsController being registered?
- Is get_products() being called when we hit /products?
Expected log sequence:
1. WooNooW Routes: rest_api_init hook fired
2. WooNooW Routes: Registering ProductsController routes
3. WooNooW Routes: ProductsController routes registered
4. WooNooW ProductsController::get_products() CALLED (when API called)
If any are missing, we know where the problem is.
Fixed 2 issues:
1. Frontend Showing Stale Data - FIXED
Problem: Table shows "Simple" even though API returns "variable"
Root Cause: React Query caching old data
Solution (index.tsx):
- Added staleTime: 0 (always fetch fresh)
- Added gcTime: 0 (don't cache)
- Forces React Query to fetch from API every time
Result: Table will show correct product type
2. Variation Attribute Values - IMPROVED
Problem: attributes show { "Color": "" } instead of { "Color": "Red" }
Improvements:
- Use wc_attribute_label() for proper attribute names
- Better handling of global vs custom attributes
- Added debug logging to see raw WooCommerce data
Debug Added:
- Logs raw variation attributes to debug.log
- Check: wp-content/debug.log
- Shows what WooCommerce actually returns
Note: If attribute values still empty, it means:
- Variations not properly saved in WooCommerce
- Need to re-save product or regenerate variations
Test:
1. Refresh products page
2. Should show correct type (variable)
3. Check debug.log for variation attribute data
4. If still empty, re-save the variable product
Fixed 2 critical issues:
1. API Response Caching - FIXED
Problem: API returns old data without type, status fields
Root Cause: WordPress REST API response caching
Solution:
- Added no-cache headers to response:
* Cache-Control: no-cache, no-store, must-revalidate
* Pragma: no-cache
* Expires: 0
- Added debug logging to verify data structure
- Forces fresh data on every request
Result: API will return fresh data with all fields
2. Variation Attribute Values Missing - FIXED
Problem: Shows "color:" instead of "color: Red"
Root Cause: API returns slugs not human-readable values
Before:
attributes: { "pa_color": "red" }
After:
attributes: { "Color": "Red" }
Solution:
- Remove 'pa_' prefix from attribute names
- Capitalize attribute names
- Convert taxonomy slugs to term names
- Return human-readable format
Code:
- Clean name: pa_color → Color
- Get term: red (slug) → Red (name)
- Format: { Color: Red }
Result: Variations show "color: Red" correctly
Test:
1. Hard refresh browser (Ctrl+Shift+R or Cmd+Shift+R)
2. Check products list - should show type and prices
3. Edit variable product - should show "color: Red"
Fixed 3 critical issues:
1. ✅ Price and Type Column Display
Problem: Columns showing empty even though data exists
Root Cause: price_html returns empty string for products without prices
Solution:
- Added fallback chain in index.tsx:
1. Try price_html (formatted HTML)
2. Fallback to regular_price (plain number)
3. Fallback to "—" (dash)
- Added fallback for type: {product.type || '—'}
Now displays:
- Formatted price if available
- Plain price if no HTML
- Dash if no price at all
2. ✅ Redirect After Create Product
Problem: Stays on form after creating product
Expected: Return to products index
Solution:
- Changed New.tsx redirect from:
navigate(`/products/${response.id}`) → navigate('/products')
- Removed conditional logic
- Always redirect to index after successful create
User flow now:
Create product → Success toast → Back to products list ✅
3. ✅ Edit Form Not Loading Data
Problem: Edit form shows empty fields instead of product data
Root Cause: Missing fields in API response (virtual, downloadable, featured)
Solution:
- Added to format_product_full() in ProductsController.php:
* $data['virtual'] = $product->is_virtual();
* $data['downloadable'] = $product->is_downloadable();
* $data['featured'] = $product->is_featured();
Now edit form receives complete data:
- Basic info (name, type, status, descriptions)
- Pricing (SKU, regular_price, sale_price)
- Inventory (manage_stock, stock_quantity, stock_status)
- Categories & tags
- Virtual, downloadable, featured flags
- Attributes & variations (for variable products)
Result:
✅ Products list shows prices and types correctly
✅ Creating product redirects to index
✅ Editing product loads all data properly
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
Fixed Issues:
1. TypeScript error on .indeterminate property (line 332)
- Cast checkbox element to any for indeterminate access
2. API error handling for categories/tags endpoints
- Added is_wp_error() checks
- Return empty array on error instead of 500
Next: Implement modern tabbed product form (Shopify-style)