# 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 ``` ### Licensing Module (`LicensesController.php`) ``` # Admin Endpoints (admin auth required) GET /licenses # List licenses (with pagination, search) GET /licenses/{id} # Get single license POST /licenses # Create license PUT /licenses/{id} # Update license DELETE /licenses/{id} # Delete license # Public Endpoints (for client software validation) POST /licenses/validate # Validate license key POST /licenses/activate # Activate license on domain POST /licenses/deactivate # Deactivate license from domain # OAuth Endpoints (user auth required) GET /licenses/oauth/validate # Validate OAuth state and license ownership POST /licenses/oauth/confirm # Confirm activation and generate token ``` **Implementation Details:** - **List:** Supports pagination (`page`, `per_page`), search by key/email - **activate:** Supports Simple API and OAuth modes - **OAuth flow:** `oauth/validate` + `oauth/confirm` for secure user verification - See `LICENSING_MODULE.md` for full OAuth flow documentation --- ## 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 ### Frontend Module (Customer-Facing) ✅ IMPLEMENTED #### **ShopController.php** ``` GET /shop/products # List products (public) GET /shop/products/{id} # Get single product (public) GET /shop/categories # List categories (public) GET /shop/search # Search products (public) ``` **Implementation Details:** - **List:** Supports pagination, category filter, search, orderby - **Single:** Returns detailed product info (variations, gallery, related products) - **Categories:** Returns categories with images and product count - **Search:** Lightweight product search (max 10 results) #### **CartController.php** ``` GET /cart # Get cart contents POST /cart/add # Add item to cart POST /cart/update # Update cart item quantity POST /cart/remove # Remove item from cart POST /cart/apply-coupon # Apply coupon to cart POST /cart/remove-coupon # Remove coupon from cart ``` **Implementation Details:** - Uses WooCommerce cart session - Returns full cart data (items, totals, coupons) - Public endpoints (no auth required) - Validates product existence before adding #### **AccountController.php** ``` GET /account/orders # Get customer orders (auth required) GET /account/orders/{id} # Get single order (auth required) GET /account/profile # Get customer profile (auth required) POST /account/profile # Update profile (auth required) POST /account/password # Update password (auth required) GET /account/addresses # Get addresses (auth required) POST /account/addresses # Update addresses (auth required) GET /account/downloads # Get digital downloads (auth required) ``` **Implementation Details:** - All endpoints require `is_user_logged_in()` - Order endpoints verify customer owns the order - Profile/address updates use WC_Customer class - Password update verifies current password **Note:** - Frontend routes are customer-facing (public or logged-in users) - Admin routes (ProductsController, OrdersController) are admin-only - No conflicts because frontend uses `/shop`, `/cart`, `/account` prefixes ### WooCommerce Hook Bridge ### Get Hooks for Context - **GET** `/woonoow/v1/hooks/{context}` - **Purpose:** Capture and return WooCommerce action hook output for compatibility with plugins - **Parameters:** - `context` (required): 'product', 'shop', 'cart', or 'checkout' - `product_id` (optional): Product ID for product context - **Response:** `{ success: true, context: string, hooks: { hook_name: html_output } }` - **Example:** `/woonoow/v1/hooks/product?product_id=123` --- ## Customer-Facing Frontend Routes are customer-facing (public or logged-in users) - Admin routes (ProductsController, OrdersController) are admin-only - No conflicts because frontend uses `/shop`, `/cart`, `/account` prefixes ### Reserved Routes (Do Not Use): ``` /products # ProductsController (admin) /orders # OrdersController (admin) /customers # CustomersController (admin) /coupons # CouponsController (admin) /settings # SettingsController (admin) /analytics # AnalyticsController (admin) /shop # ShopController (customer) /cart # CartController (customer) /account # AccountController (customer) ``` ### 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.