# 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
