Documentation Cleanup: ✅ Archived 6 obsolete/completed docs to archive/: - CUSTOMER_DATA_FLOW_ANALYSIS.md - CALCULATION_EFFICIENCY_AUDIT.md - PHASE_COMPLETE.md - PRODUCT_FORM_UX_IMPROVEMENTS.md - PROGRESS_NOTE.md - TASKS_SUMMARY.md New Documentation: ✅ CUSTOMER_SPA_MASTER_PLAN.md - Comprehensive strategy Includes: 1. Architecture Overview - Hybrid plugin architecture - customer-spa folder structure - Frontend/Backend separation 2. Deployment Modes - Shortcode Mode (default, works with any theme) - Full SPA Mode (maximum performance) - Hybrid Mode (best of both worlds) 3. Feature Scope - Phase 1: Core Commerce (MVP) - Phase 2: Enhanced Features - Phase 3: Advanced Features 4. UX Best Practices - Research-backed patterns (Baymard Institute) - Cart UX (drawer, mini cart, shipping threshold) - Checkout UX (progress, guest, autocomplete) - Product Page UX (images, CTA, social proof) 5. Technical Stack - React 18 + Vite - Zustand + React Query - TailwindCSS + shadcn/ui - PWA with Workbox 6. Implementation Roadmap - 10 sprints (20 weeks) - Foundation → Catalog → Cart → Account → Polish 7. API Requirements - 15+ new endpoints needed - Shop, Cart, Checkout, Account APIs 8. Performance Targets - Core Web Vitals - Bundle sizes - Load times 9. Settings & Configuration - Frontend mode selection - Feature toggles - Customization options 10. Migration Strategy - From WooCommerce default - Rollback plan - Success metrics Result: Clear, actionable plan for Customer SPA development!
346 lines
8.4 KiB
Markdown
346 lines
8.4 KiB
Markdown
# Customer Data Flow Analysis
|
|
|
|
## Issue Report
|
|
**Problem:** Customer `billing_phone` shows "Indonesia" instead of phone number
|
|
**Source:** Customer created via Order module
|
|
**Impact:** Incorrect customer data stored in database
|
|
|
|
## Data Flow Investigation
|
|
|
|
### A. Customer as Guest (Not Site Member)
|
|
|
|
#### 1. Order Creation Flow
|
|
**File:** `OrdersController.php` → `create_order()` method
|
|
|
|
**Steps:**
|
|
1. Order form submits billing data including `phone`
|
|
2. Data flows through `$billing['phone']` parameter
|
|
3. Order billing is set via `$order->set_billing_phone($billing['phone'])`
|
|
4. **No WC_Customer object created** - guest orders only store data in order meta
|
|
|
|
**Code Location:** Lines 780-1120
|
|
|
|
```php
|
|
// Guest customer - data only in order
|
|
$order->set_billing_first_name($billing['first_name'] ?? '');
|
|
$order->set_billing_last_name($billing['last_name'] ?? '');
|
|
$order->set_billing_email($billing['email'] ?? '');
|
|
$order->set_billing_phone($billing['phone'] ?? ''); // ← Data here
|
|
// ... more fields
|
|
```
|
|
|
|
**Issue:** Guest customers don't have WC_Customer records, so viewing them in Customer module will fail or show incorrect data.
|
|
|
|
---
|
|
|
|
### B. Customer as Site Member
|
|
|
|
#### 1. Existing Member - Order Creation
|
|
**File:** `OrdersController.php` → Lines 1020-1064
|
|
|
|
**Flow:**
|
|
1. User exists, found by email
|
|
2. **Upgrade subscriber to customer role** (if needed)
|
|
3. Create `WC_Customer` object
|
|
4. **Update customer data** from order billing/shipping
|
|
5. Save customer
|
|
6. Link order to customer
|
|
|
|
**Code:**
|
|
```php
|
|
if ($user) {
|
|
// Upgrade role if needed
|
|
if (in_array('subscriber', (array) $user->roles, true)) {
|
|
$user->set_role('customer');
|
|
}
|
|
|
|
// Update customer billing & shipping data
|
|
$customer = new \WC_Customer($user->ID);
|
|
|
|
// Update billing address
|
|
if (! empty($billing['first_name'])) $customer->set_billing_first_name($billing['first_name']);
|
|
if (! empty($billing['last_name'])) $customer->set_billing_last_name($billing['last_name']);
|
|
if (! empty($billing['email'])) $customer->set_billing_email($billing['email']);
|
|
if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']); // ← HERE
|
|
// ... more fields
|
|
|
|
$customer->save();
|
|
}
|
|
```
|
|
|
|
**Validation:** Uses `! empty()` check
|
|
**Problem:** If `$billing['phone']` contains "Indonesia" (non-empty string), it will be saved!
|
|
|
|
---
|
|
|
|
#### 2. New Member - Auto-Registration
|
|
**File:** `OrdersController.php` → Lines 1065-1118
|
|
|
|
**Flow:**
|
|
1. User doesn't exist
|
|
2. Auto-register setting is ON
|
|
3. Create WordPress user
|
|
4. Create `WC_Customer` object
|
|
5. Set billing/shipping from order data
|
|
6. Save customer
|
|
7. Send welcome email
|
|
|
|
**Code:**
|
|
```php
|
|
elseif ($register_member) {
|
|
// Create user
|
|
$user_id = wp_insert_user($userdata);
|
|
|
|
if (!is_wp_error($user_id)) {
|
|
$customer = new \WC_Customer($user_id);
|
|
|
|
// Billing address
|
|
if (! empty($billing['first_name'])) $customer->set_billing_first_name($billing['first_name']);
|
|
// ...
|
|
if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']); // ← HERE
|
|
// ...
|
|
|
|
$customer->save();
|
|
}
|
|
}
|
|
```
|
|
|
|
**Same Issue:** `! empty()` check allows "Indonesia" to be saved.
|
|
|
|
---
|
|
|
|
### C. Customer Module Direct Edit
|
|
|
|
**File:** `CustomersController.php` → `update_customer()` method (Lines 232-310)
|
|
|
|
**Flow:**
|
|
1. Receive customer data via PUT request
|
|
2. Update WordPress user meta
|
|
3. Update `WC_Customer` billing/shipping
|
|
4. Save customer
|
|
|
|
**Code:**
|
|
```php
|
|
$customer = new WC_Customer($id);
|
|
|
|
// Billing address
|
|
if (!empty($data['billing'])) {
|
|
$billing = $data['billing'];
|
|
if (isset($billing['first_name'])) $customer->set_billing_first_name(...);
|
|
// ...
|
|
if (isset($billing['phone'])) $customer->set_billing_phone(sanitize_text_field($billing['phone']));
|
|
// ...
|
|
}
|
|
|
|
$customer->save();
|
|
```
|
|
|
|
**Validation:** Uses `isset()` check (better than `! empty()`)
|
|
**Sanitization:** Uses `sanitize_text_field()` ✅
|
|
|
|
---
|
|
|
|
## Root Cause Analysis
|
|
|
|
### Possible Sources of "Indonesia" Value
|
|
|
|
1. **Frontend Default Value**
|
|
- Check `OrderForm.tsx` for default country/phone values
|
|
- Check if "Indonesia" is being set as placeholder or default
|
|
|
|
2. **Backend Fallback**
|
|
- Check if WooCommerce has default country settings
|
|
- Check if there's a fallback to country name instead of phone
|
|
|
|
3. **Data Validation Issue**
|
|
- `! empty()` check allows ANY non-empty string
|
|
- No validation that phone is actually a phone number
|
|
- No sanitization before saving
|
|
|
|
4. **Virtual Products Case**
|
|
- When cart has only virtual products, address fields are hidden
|
|
- Phone field might still be submitted with wrong value
|
|
|
|
---
|
|
|
|
## Issues Found
|
|
|
|
### 1. ❌ Weak Validation in OrdersController
|
|
|
|
**Problem:**
|
|
```php
|
|
if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']);
|
|
```
|
|
|
|
- `! empty()` allows "Indonesia", "test", "abc", etc.
|
|
- No phone number format validation
|
|
- No sanitization
|
|
|
|
**Should Be:**
|
|
```php
|
|
if (isset($billing['phone']) && $billing['phone'] !== '') {
|
|
$customer->set_billing_phone(sanitize_text_field($billing['phone']));
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2. ❌ No Data Sanitization in Order Creation
|
|
|
|
**Problem:**
|
|
- Direct assignment without sanitization
|
|
- Allows any string value
|
|
- No format validation
|
|
|
|
**Should Add:**
|
|
- `sanitize_text_field()` for all text fields
|
|
- Phone number format validation
|
|
- Empty string handling
|
|
|
|
---
|
|
|
|
### 3. ❌ Inconsistent Validation Between Controllers
|
|
|
|
**OrdersController:**
|
|
- Uses `! empty()` check
|
|
- No sanitization
|
|
|
|
**CustomersController:**
|
|
- Uses `isset()` check ✅
|
|
- Has `sanitize_text_field()` ✅
|
|
|
|
**Should:** Use same validation pattern everywhere
|
|
|
|
---
|
|
|
|
### 4. ❌ Virtual Products Address Handling
|
|
|
|
**Current Behavior:**
|
|
- Frontend hides address fields for virtual products
|
|
- But phone field is ALWAYS shown
|
|
- Backend might receive wrong data
|
|
|
|
**Check:**
|
|
- OrderForm.tsx line 1023: `setBPhone(data.billing.phone || '');`
|
|
- Does this fallback to something else?
|
|
|
|
---
|
|
|
|
## Action Items
|
|
|
|
### 1. Fix OrdersController Validation
|
|
|
|
**File:** `OrdersController.php`
|
|
**Lines:** 1039-1047, 1088-1096
|
|
|
|
**Change:**
|
|
```php
|
|
// OLD (Lines 1042)
|
|
if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']);
|
|
|
|
// NEW
|
|
if (isset($billing['phone']) && trim($billing['phone']) !== '') {
|
|
$customer->set_billing_phone(sanitize_text_field($billing['phone']));
|
|
}
|
|
```
|
|
|
|
Apply to:
|
|
- Existing member update (lines 1039-1047)
|
|
- New member creation (lines 1088-1096)
|
|
|
|
---
|
|
|
|
### 2. Add Phone Number Validation
|
|
|
|
**Create Helper Function:**
|
|
```php
|
|
private static function sanitize_phone($phone) {
|
|
if (empty($phone)) {
|
|
return '';
|
|
}
|
|
|
|
// Remove non-numeric characters except + and spaces
|
|
$phone = preg_replace('/[^0-9+\s-]/', '', $phone);
|
|
|
|
// Trim whitespace
|
|
$phone = trim($phone);
|
|
|
|
// If result is empty or just symbols, return empty
|
|
if (empty($phone) || preg_match('/^[+\s-]+$/', $phone)) {
|
|
return '';
|
|
}
|
|
|
|
return $phone;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 3. Check Frontend Data Source
|
|
|
|
**File:** `OrderForm.tsx`
|
|
**Line:** ~1023
|
|
|
|
**Check:**
|
|
- Where does `data.billing.phone` come from?
|
|
- Is there a default value being set?
|
|
- Is "Indonesia" coming from country field?
|
|
|
|
---
|
|
|
|
### 4. Test Cases
|
|
|
|
**A. Guest Customer:**
|
|
1. Create order with phone = "08123456789"
|
|
2. Check order billing_phone
|
|
3. Verify no WC_Customer created
|
|
|
|
**B. Existing Member:**
|
|
1. Create order with existing customer
|
|
2. Phone = "08123456789"
|
|
3. Check WC_Customer billing_phone updated
|
|
4. Create another order with same customer
|
|
5. Phone = "08198765432"
|
|
6. Verify WC_Customer phone updated to new value
|
|
|
|
**C. New Member (Auto-register):**
|
|
1. Create order with new email
|
|
2. Auto-register ON
|
|
3. Phone = "08123456789"
|
|
4. Verify WC_Customer created with correct phone
|
|
|
|
**D. Virtual Products:**
|
|
1. Create order with only virtual products
|
|
2. Verify phone field behavior
|
|
3. Check what value is submitted
|
|
|
|
---
|
|
|
|
## Expected Behavior
|
|
|
|
### Order Creation with Existing Member
|
|
1. Order billing data should update WC_Customer data
|
|
2. Phone should be validated and sanitized
|
|
3. Empty phone should clear WC_Customer phone (not set to country name)
|
|
|
|
### Order Creation with New Member
|
|
1. WC_Customer should be created with correct data
|
|
2. Phone should be validated and sanitized
|
|
3. No fallback to country name
|
|
|
|
### Virtual Products
|
|
1. Phone field should still work correctly
|
|
2. No address fields needed
|
|
3. Phone should not default to country name
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. ✅ Update PROJECT_SOP.md with mobile UX patterns
|
|
2. 🔄 Find source of "Indonesia" value
|
|
3. ⏳ Fix validation in OrdersController
|
|
4. ⏳ Add phone sanitization helper
|
|
5. ⏳ Test all scenarios
|
|
6. ⏳ Document fix in commit message
|