- Add LicenseConnect.tsx focused OAuth confirmation page in customer SPA - Add /licenses/oauth/validate and /licenses/oauth/confirm API endpoints - Update App.tsx to render license-connect outside BaseLayout (no header/footer) - Add license_activation_method field to product settings in Admin SPA - Create LICENSING_MODULE.md with comprehensive OAuth flow documentation - Update API_ROUTES.md with license module endpoints
388 lines
14 KiB
Markdown
388 lines
14 KiB
Markdown
# 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.
|