- 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
213 lines
7.0 KiB
Markdown
213 lines
7.0 KiB
Markdown
# Product Create/Update Flow Audit Report
|
||
|
||
**Date:** 2026-01-29
|
||
**Scope:** Full trace of product creation, update, SKU validation, variation handling, virtual product setting, and customer-facing add-to-cart
|
||
|
||
---
|
||
|
||
## Executive Summary
|
||
|
||
**Total Issues Found: 4**
|
||
- **CRITICAL:** 2
|
||
- **WARNING:** 1
|
||
- **INFO:** 1
|
||
|
||
---
|
||
|
||
## Critical Issues
|
||
|
||
### 🔴 Issue #1: SKU Validation Blocks Variation Updates
|
||
|
||
**Severity:** CRITICAL
|
||
**Location:** [ProductsController.php#L1009](file:///Users/dwindown/Local%20Sites/woonoow/app/public/wp-content/plugins/woonoow/includes/Api/ProductsController.php#L1009)
|
||
|
||
**Problem:**
|
||
When updating a variable product, the `save_product_variations` method sets SKU unconditionally:
|
||
```php
|
||
if (isset($var_data['sku'])) $variation->set_sku($var_data['sku']);
|
||
```
|
||
|
||
WooCommerce validates that SKU must be unique across all products. When updating a variation that already has that SKU, WooCommerce throws an exception because it sees the SKU as a duplicate.
|
||
|
||
**Root Cause:**
|
||
WooCommerce's `set_sku()` method checks for uniqueness but doesn't know the variation already owns that SKU during the update.
|
||
|
||
**Fix Required:**
|
||
Before setting SKU, check if the new SKU is the same as the current SKU:
|
||
```php
|
||
if (isset($var_data['sku'])) {
|
||
$current_sku = $variation->get_sku();
|
||
$new_sku = $var_data['sku'];
|
||
// Only set if different (to avoid WC duplicate check issue)
|
||
if ($current_sku !== $new_sku) {
|
||
$variation->set_sku($new_sku);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 🔴 Issue #2: Variation Selection Fails (Attribute Format Mismatch)
|
||
|
||
**Severity:** CRITICAL
|
||
**Location:**
|
||
- Backend: [ShopController.php#L363-365](file:///Users/dwindown/Local%20Sites/woonoow/app/public/wp-content/plugins/woonoow/includes/Frontend/ShopController.php#L363)
|
||
- Frontend: [Product/index.tsx#L97-127](file:///Users/dwindown/Local%20Sites/woonoow/app/public/wp-content/plugins/woonoow/customer-spa/src/pages/Product/index.tsx#L97)
|
||
|
||
**Problem:**
|
||
"Please select all product options" error appears even when a variation is selected.
|
||
|
||
**Root Cause:**
|
||
Format mismatch between backend API and frontend matching logic:
|
||
|
||
| Source | Format | Example |
|
||
|--------|--------|---------|
|
||
| API `variations.attributes` | `attribute_pa_color: "red"` | Lowercase, prefixed |
|
||
| API `attributes` | `name: "Color"` | Human-readable |
|
||
| Frontend `selectedAttributes` | `Color: "Red"` | Human-readable, case preserved |
|
||
|
||
The matching logic at lines 100-120 has complex normalization but may fail at edge cases:
|
||
- Taxonomy attributes use `pa_` prefix (e.g., `attribute_pa_color`)
|
||
- Custom attributes use direct prefix (e.g., `attribute_size`)
|
||
- The comparison normalizes both sides but attribute names in `selectedAttributes` are human-readable labels
|
||
|
||
**Fix Required:**
|
||
Improve variation matching by normalizing attribute names consistently:
|
||
|
||
```typescript
|
||
// In find matching variation logic:
|
||
const variation = (product.variations as any[]).find(v => {
|
||
return Object.entries(selectedAttributes).every(([attrName, attrValue]) => {
|
||
const normalizedAttrName = attrName.toLowerCase();
|
||
const normalizedValue = attrValue.toLowerCase();
|
||
|
||
// Try all possible attribute key formats
|
||
const possibleKeys = [
|
||
`attribute_${normalizedAttrName}`,
|
||
`attribute_pa_${normalizedAttrName}`,
|
||
normalizedAttrName
|
||
];
|
||
|
||
for (const key of possibleKeys) {
|
||
if (key in v.attributes) {
|
||
return v.attributes[key].toLowerCase() === normalizedValue;
|
||
}
|
||
}
|
||
return false;
|
||
});
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Warning Issues
|
||
|
||
### 🟡 Issue #3: Virtual Product Setting May Not Persist for Variable Products
|
||
|
||
**Severity:** WARNING
|
||
**Location:** [ProductsController.php#L496-498](file:///Users/dwindown/Local%20Sites/woonoow/app/public/wp-content/plugins/woonoow/includes/Api/ProductsController.php#L496)
|
||
|
||
**Problem:**
|
||
User reports cannot change product to virtual. Investigation shows:
|
||
- Admin-SPA correctly sends `virtual: true` in payload
|
||
- Backend `update_product` correctly calls `$product->set_virtual()`
|
||
- However, for variable products, virtual status may need to be set on each variation
|
||
|
||
**Observation:**
|
||
The backend code at lines 496-498 handles virtual correctly:
|
||
```php
|
||
if (isset($data['virtual'])) {
|
||
$product->set_virtual((bool) $data['virtual']);
|
||
}
|
||
```
|
||
|
||
**Potential Issue:**
|
||
WooCommerce may ignore parent product's virtual flag for variable products. Each variation may need to be set as virtual individually.
|
||
|
||
**Fix Required:**
|
||
When saving variations, also propagate virtual flag:
|
||
```php
|
||
// In save_product_variations, after setting other fields:
|
||
if ($product->is_virtual()) {
|
||
$variation->set_virtual(true);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Info Issues
|
||
|
||
### ℹ️ Issue #4: Missing Error Handling in Add-to-Cart Backend
|
||
|
||
**Severity:** INFO
|
||
**Location:** [CartController.php#L202-203](file:///Users/dwindown/Local%20Sites/woonoow/app/public/wp-content/plugins/woonoow/includes/Api/Controllers/CartController.php#L202)
|
||
|
||
**Observation:**
|
||
When `add_to_cart()` returns false, the error message is generic:
|
||
```php
|
||
if (!$cart_item_key) {
|
||
return new WP_Error('add_to_cart_failed', 'Failed to add product to cart', ['status' => 400]);
|
||
}
|
||
```
|
||
|
||
WooCommerce may have more specific notices in `wc_notice` stack that could provide better error messages.
|
||
|
||
**Enhancement:**
|
||
```php
|
||
if (!$cart_item_key) {
|
||
$notices = wc_get_notices('error');
|
||
$message = !empty($notices) ? $notices[0]['notice'] : 'Failed to add product to cart';
|
||
wc_clear_notices();
|
||
return new WP_Error('add_to_cart_failed', $message, ['status' => 400]);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Code Flow Summary
|
||
|
||
### Product Update Flow
|
||
```mermaid
|
||
sequenceDiagram
|
||
Admin SPA->>ProductsController: PUT /products/{id}
|
||
ProductsController->>WC_Product: set_name, set_sku, etc.
|
||
ProductsController->>WC_Product: set_virtual, set_downloadable
|
||
ProductsController->>ProductsController: save_product_variations()
|
||
ProductsController->>WC_Product_Variation: set_sku (BUG: no duplicate check)
|
||
WC_Product_Variation-->>WooCommerce: validate_sku()
|
||
WooCommerce-->>ProductsController: Exception (duplicate SKU)
|
||
```
|
||
|
||
### Add-to-Cart Flow
|
||
```mermaid
|
||
sequenceDiagram
|
||
Customer SPA->>Product Page: Select variation
|
||
Product Page->>useState: selectedAttributes = {Color: "Red"}
|
||
Product Page->>useEffect: Find matching variation
|
||
Note right of Product Page: Mismatch: API has attribute_pa_color
|
||
Product Page-->>useState: selectedVariation = null
|
||
Customer->>Product Page: Click Add to Cart
|
||
Product Page->>Customer: "Please select all product options"
|
||
```
|
||
|
||
---
|
||
|
||
## Files to Modify
|
||
|
||
| File | Change |
|
||
|------|--------|
|
||
| `ProductsController.php` | Fix SKU check in `save_product_variations` |
|
||
| `Product/index.tsx` | Fix variation matching logic |
|
||
| `ProductsController.php` | Propagate virtual to variations |
|
||
| `CartController.php` | (Optional) Improve error messages |
|
||
|
||
---
|
||
|
||
## Verification Plan
|
||
|
||
After fixes:
|
||
1. Create a variable product with SKU on variations
|
||
2. Edit the product without changing SKU → should save successfully
|
||
3. Add products to cart → verify variation selection works
|
||
4. Test virtual product setting on simple and variable products
|