# WooNooW API Routes Standard ## Namespace All routes use: `woonoow/v1` ## Route Naming Convention ### Pattern ``` /{resource} # List/Create /{resource}/{id} # Get/Update/Delete single item /{resource}/{action} # Special actions /{resource}/{id}/{sub} # Sub-resources ``` ### Rules 1. ✅ Use **plural nouns** for resources (`/products`, `/orders`, `/customers`) 2. ✅ Use **kebab-case** for multi-word resources (`/pickup-locations`) 3. ✅ Use **specific action names** to avoid conflicts (`/products/search`, `/orders/preview`) 4. ❌ Never create generic routes that might conflict (`/products` vs `/products`) 5. ❌ Never use verbs as resource names (`/get-products` ❌, use `/products` ✅) --- ## Current Routes Registry ### Products Module (`ProductsController.php`) ``` GET /products # List products (admin) GET /products/{id} # Get single product POST /products # Create product PUT /products/{id} # Update product DELETE /products/{id} # Delete product GET /products/categories # List categories POST /products/categories # Create category GET /products/tags # List tags POST /products/tags # Create tag GET /products/attributes # List attributes ``` ### Orders Module (`OrdersController.php`) ``` GET /orders # List orders GET /orders/{id} # Get single order POST /orders # Create order PUT /orders/{id} # Update order DELETE /orders/{id} # Delete order POST /orders/preview # Preview order totals GET /products/search # Search products for order form (⚠️ Special route) GET /customers/search # Search customers for order form (⚠️ Special route) ``` **⚠️ Important:** - `/products/search` is owned by OrdersController (NOT ProductsController) - This is for lightweight product search in order forms - ProductsController owns `/products` for full product management ### Customers Module (`CustomersController.php` - Future) ``` GET /customers # List customers GET /customers/{id} # Get single customer POST /customers # Create customer PUT /customers/{id} # Update customer DELETE /customers/{id} # Delete customer ``` **⚠️ Important:** - `/customers/search` is already used by OrdersController - CustomersController will own `/customers` for full customer management - No conflict because routes are specific ### Coupons Module (`CouponsController.php`) ✅ IMPLEMENTED ``` GET /coupons # List coupons (with pagination, search, filter) GET /coupons/{id} # Get single coupon POST /coupons # Create coupon PUT /coupons/{id} # Update coupon DELETE /coupons/{id} # Delete coupon POST /coupons/validate # Validate coupon code (OrdersController) ``` **Implementation Details:** - **List:** Supports pagination (`page`, `per_page`), search (`search`), filter by type (`discount_type`) - **Create:** Validates code uniqueness, requires `code`, `amount`, `discount_type` - **Update:** Full coupon data update, code cannot be changed after creation - **Delete:** Supports force delete via query param - **Validate:** Handled by OrdersController for order context **Note:** - `/coupons/validate` is in OrdersController (order-specific validation) - CouponsController owns `/coupons` for coupon CRUD management - No conflict because validate is a specific action route ### Settings Module (`SettingsController.php`) ``` GET /settings # Get all settings PUT /settings # Update settings GET /settings/store # Get store settings GET /settings/tax # Get tax settings GET /settings/shipping # Get shipping settings GET /settings/payments # Get payment settings ``` ### Analytics Module (`AnalyticsController.php`) ``` GET /analytics/overview # Dashboard overview GET /analytics/products # Product analytics GET /analytics/orders # Order analytics GET /analytics/customers # Customer analytics ``` --- ## Conflict Prevention Rules ### 1. Resource Ownership Each resource has ONE primary controller: - `/products` → `ProductsController` - `/orders` → `OrdersController` - `/customers` → `CustomersController` (future) - `/coupons` → `CouponsController` (future) ### 2. Cross-Resource Operations When one module needs data from another resource, use **specific action routes**: **✅ Good:** ```php // OrdersController needs product search register_rest_route('woonoow/v1', '/products/search', [...]); // OrdersController needs customer search register_rest_route('woonoow/v1', '/customers/search', [...]); // OrdersController needs coupon validation register_rest_route('woonoow/v1', '/orders/validate-coupon', [...]); ``` **❌ Bad:** ```php // OrdersController trying to own /products register_rest_route('woonoow/v1', '/products', [...]); // CONFLICT! // OrdersController trying to own /customers register_rest_route('woonoow/v1', '/customers', [...]); // CONFLICT! ``` ### 3. Sub-Resource Pattern Use sub-resources for related data: **✅ Good:** ```php // Order-specific coupons GET /orders/{id}/coupons # List coupons applied to order POST /orders/{id}/coupons # Apply coupon to order DELETE /orders/{id}/coupons/{code} # Remove coupon from order // Order-specific notes GET /orders/{id}/notes # List order notes POST /orders/{id}/notes # Add order note ``` ### 4. Action Routes Use descriptive action names to avoid conflicts: **✅ Good:** ```php POST /orders/preview # Preview order totals POST /orders/calculate-shipping # Calculate shipping GET /products/search # Search products (lightweight) GET /coupons/validate # Validate coupon code ``` **❌ Bad:** ```php POST /orders/calc # Too vague GET /search # Too generic GET /validate # Too generic ``` --- ## Registration Order WordPress REST API uses **first-registered-wins** for route conflicts. ### Controller Registration Order (in `Routes.php`): ```php 1. SettingsController 2. ProductsController # Registers /products first 3. OrdersController # Can use /products/search (no conflict) 4. CustomersController # Will register /customers 5. CouponsController # Will register /coupons 6. AnalyticsController ``` **⚠️ Critical:** - ProductsController MUST register before OrdersController - This ensures `/products` is owned by ProductsController - OrdersController can safely use `/products/search` (different path) --- ## Testing for Conflicts ### 1. Check Route Registration ```php // Add to Routes.php temporarily add_action('rest_api_init', function() { $routes = rest_get_server()->get_routes(); error_log('WooNooW Routes: ' . print_r($routes['woonoow/v1'], true)); }, 999); ``` ### 2. Test API Endpoints ```bash # Test product list (should hit ProductsController) curl -X GET "https://site.local/wp-json/woonoow/v1/products" # Test product search (should hit OrdersController) curl -X GET "https://site.local/wp-json/woonoow/v1/products/search?s=test" # Test customer search (should hit OrdersController) curl -X GET "https://site.local/wp-json/woonoow/v1/customers/search?s=john" ``` ### 3. Frontend API Calls ```typescript // ProductsApi - Full product management ProductsApi.list() → GET /products ProductsApi.get(id) → GET /products/{id} ProductsApi.create(data) → POST /products // OrdersApi - Product search for orders ProductsApi.search(query) → GET /products/search // CustomersApi - Customer search for orders CustomersApi.search(query) → GET /customers/search ``` --- ## Future Considerations ### When Adding New Modules: 1. **Check existing routes** - Review this document 2. **Choose specific names** - Avoid generic routes 3. **Use sub-resources** - For related data 4. **Update this document** - Add new routes to registry 5. **Test for conflicts** - Use testing methods above ### Reserved Routes (Do Not Use): ``` /products # ProductsController /orders # OrdersController /customers # CustomersController (future) /coupons # CouponsController (future) /settings # SettingsController /analytics # AnalyticsController ``` ### Safe Action Routes: ``` /products/search # OrdersController (lightweight search) /customers/search # OrdersController (lightweight search) /orders/preview # OrdersController (order preview) /coupons/validate # CouponsController (coupon validation) ``` --- ## Summary ✅ **Do:** - Use plural nouns for resources - Use specific action names - Use sub-resources for related data - Register controllers in correct order - Update this document when adding routes ❌ **Don't:** - Create generic routes that might conflict - Use verbs as resource names - Register same route in multiple controllers - Forget to test for conflicts **Remember:** First-registered-wins! Always check existing routes before adding new ones.