Added comprehensive product/category restrictions to coupon form
Features Added:
1. Product Selectors:
- Products (include) - multiselect with search
- Exclude products - multiselect with search
- Shows product names with searchable dropdown
- Badge display for selected items
2. Category Selectors:
- Product categories (include) - multiselect
- Exclude categories - multiselect
- Shows category names with search
- Badge display for selected items
3. API Integration:
- Added ProductsApi.list() endpoint
- Added ProductsApi.categories() endpoint
- Fetch products and categories on form load
- React Query caching for performance
4. Form Data:
- Added product_ids field
- Added excluded_product_ids field
- Added product_categories field
- Added excluded_product_categories field
- Proper number/string conversion
UI/UX Improvements:
- Searchable multiselect dropdowns
- Badge display with X to remove
- Shows +N more when exceeds display limit
- Clear placeholder text
- Helper text for each field
- Consistent spacing and layout
Technical:
- Uses MultiSelect component (shadcn-based)
- React Query for data fetching
- Proper TypeScript types
- Number array handling
Note: Brands field not included yet (requires WooCommerce Product Brands extension check)
Result:
- Full WooCommerce coupon restrictions support
- Clean, searchable UI
- Production ready
ROOT CAUSE FOUND!
OrdersController registered /products BEFORE ProductsController:
- OrdersController::init() called first (line 25 in Routes.php)
- ProductsController::register_routes() called later (line 95)
- WordPress uses FIRST matching route
- OrdersController /products was winning!
This explains EVERYTHING:
✅ Route registered: SUCCESS
✅ Callback is_callable: YES
✅ Permissions: ALLOWED
✅ Request goes to /woonoow/v1/products
❌ But OrdersController::products() was handling it!
Solution:
1. Changed OrdersController route from /products to /products/search
2. Updated ProductsApi.search() to use /products/search
3. Now /products is free for ProductsController!
Result:
- /products → ProductsController::get_products() (full product list)
- /products/search → OrdersController::products() (lightweight search for orders)
This will finally make ProductsController work!
## Fixes:
1. ✅ Suggested rates now inside Tax Rates card as help notice
- Shows as blue notice box
- Only shows rates not yet added
- Auto-hides when all suggested rates added
2. ✅ Add Rate button now works
- Fixed mutation to properly invalidate queries
- Shows success toast
- Updates list immediately
3. ✅ Add Tax Rate dialog no longer blank
- Replaced shadcn Select with native select
- Form now submits properly
- All fields visible
4. ✅ Tax toggle now functioning
- Changed onChange to onCheckedChange
- Added required id prop
- Properly typed checked parameter
## Additional:
- Added api.put() method to api.ts
- Improved UX with suggested rates as contextual help