Critical bug: Hook called after conditional return
Problem:
- useEffect at line 107 was AFTER early returns (lines 83-102)
- When loading/error states triggered early return
- Hook order changed between renders
- React detected hook order violation
- Component broke with blank screen
Rules of Hooks violation:
❌ Before:
1. All hooks (useState, useQuery, etc.)
2. Early return if loading
3. Early return if error
4. useEffect (line 107) ← WRONG! After conditional returns
✅ After:
1. All hooks including ALL useEffects
2. Early return if loading
3. Early return if error
4. Render
Fix:
- Moved useEffect from line 107 to line 62
- Now before any early returns
- Changed product?.meta to productQ.data?.meta
- Hooks always called in same order
- No conditional hook calls
Result:
✅ Product edit form loads correctly
✅ No React warnings
✅ Follows Rules of Hooks
✅ Consistent hook order every render
Critical bug: Tab buttons were submitting the form
Problem:
- Buttons inside <form> default to type="submit"
- Clicking any tab triggered form submission
- Form would submit instead of switching tabs
- Very disruptive UX
Fix:
- Added type="button" to all tab buttons
- Mobile horizontal tabs
- Desktop vertical tabs
- Now tabs only switch sections, no submit
Changes:
1. Mobile tab buttons: type="button"
2. Desktop tab buttons: type="button"
Result:
✅ Tabs switch sections without submitting
✅ Form only submits via submit button
✅ Proper form behavior
Applied VerticalTabForm to ProductFormTabbed
Changes:
1. Replaced horizontal Tabs with VerticalTabForm
2. Converted TabsContent to FormSection components
3. Removed activeTab state (scroll spy handles this)
4. Dynamic tabs based on product type
- Simple: General, Inventory, Organization
- Variable: General, Inventory, Variations, Organization
Benefits:
✅ Consistent layout with Coupons form
✅ Better space utilization
✅ Narrower content area (more readable)
✅ Scroll spy navigation
✅ Click to scroll to section
✅ Professional UI
Layout:
- Desktop: 250px sidebar + content area
- Sidebar: Sticky with icons
- Content: Scrollable with smooth navigation
- Mobile: Keeps original horizontal tabs (future)
Removed:
- TabsList, TabsTrigger components
- activeTab state and setActiveTab calls
- Manual tab switching on validation errors
Result:
Both Products and Coupons now use same vertical tab pattern
Forms are more professional and easier to navigate
Implemented: Frontend Components for Level 1 Compatibility
Created Components:
- MetaFields.tsx - Generic meta field renderer
- useMetaFields.ts - Hook for field registry
Integrated Into:
- Orders/Edit.tsx - Meta fields after OrderForm
- Products/Edit.tsx - Meta fields after ProductForm
Features:
- Supports: text, textarea, number, date, select, checkbox
- Groups fields by section
- Zero coupling with specific plugins
- Renders any registered fields dynamically
- Read-only mode support
How It Works:
1. Backend exposes meta via API (Phase 1)
2. PHP registers fields via MetaFieldsRegistry (Phase 3 - next)
3. Fields localized to window.WooNooWMetaFields
4. useMetaFields hook reads registry
5. MetaFields component renders fields
6. User edits fields
7. Form submission includes meta
8. Backend saves via update_order_meta_data()
Result:
- Generic, reusable components
- Zero plugin-specific code
- Works with any registered fields
- Clean separation of concerns
Next: Phase 3 - PHP MetaFieldsRegistry system
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 4 major UX issues:
1. Stock Column - Show Infinity Symbol
Problem: Stock shows badge even when not managed
Solution:
- Check manage_stock flag
- If true: Show StockBadge with quantity
- If false: Show ∞ (infinity symbol) for unlimited
Result: Clear visual for unlimited stock
2. Type Column & Price Display
Problem: Type column empty, price ignores sale price
Solution:
- Type: Show badge with product.type (simple, variable, etc.)
- Price: Respect sale price hierarchy:
1. price_html (WooCommerce formatted)
2. sale_price (show strikethrough regular + green sale)
3. regular_price (normal display)
4. — (dash for no price)
Result:
- Type visible with badge styling
- Sale prices show with strikethrough
- Clear visual hierarchy
3. Rich Text Editor for Description
Problem: Description shows raw HTML in textarea
Solution:
- Created RichTextEditor component with Tiptap
- Toolbar: Bold, Italic, H2, Lists, Quote, Undo/Redo
- Integrated into GeneralTab
Features:
- WYSIWYG editing
- Keyboard shortcuts
- Clean toolbar UI
- Saves as HTML
Result: Professional rich text editing experience
4. Inline Create Categories & Tags
Problem: Cannot create new categories/tags in product form
Solution:
- Added input + "Add" button above each list
- Press Enter or click Add to create
- Auto-selects newly created item
- Shows loading state
- Toast notifications
Result:
- No need to leave product form
- Seamless workflow
- Better UX
Files Changed:
- index.tsx: Stock ∞, sale price display, type badge
- GeneralTab.tsx: RichTextEditor integration
- OrganizationTab.tsx: Inline create UI
- RichTextEditor.tsx: New reusable component
Note: Variation attribute value issue (screenshot 1) needs API data format investigation
Critical fix for edit mode data loading.
Problem:
- Click Edit on any product
- Form shows empty fields
- Product data fetch happens but form does not update
Root Cause:
React useState only uses initial value ONCE on mount.
When initial prop updates after API fetch, state does not update.
Solution:
Added useEffect to sync state with initial prop when it changes.
Result:
- Edit form loads all product data correctly
- All 15 fields populate from API response
- Categories and tags pre-selected
- Attributes and variations loaded
- Ready to edit and save
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)