Files
WooNooW/CUSTOMER_DATA_FLOW_ANALYSIS.md
dwindown 275b045b5f docs: Update PROJECT_SOP and add customer data flow analysis
1. Updated PROJECT_SOP.md:
 Added mobile card linkable pattern with full example
 Added submenu mobile hiding rules and behavior matrix
 Documented stopPropagation pattern for checkboxes
 Added ChevronRight icon requirement
 Documented active:scale animation for tap feedback
 Added spacing rules (space-y-3 for cards)

2. Created CUSTOMER_DATA_FLOW_ANALYSIS.md:
 Comprehensive analysis of customer data flow
 Documented 2 customer types: Guest vs Site Member
 Identified validation issues in OrdersController
 Found weak ! empty() checks allowing bad data
 Documented inconsistent validation between controllers
 Created action items for fixes
 Added test cases for all scenarios

Key Findings:
 OrdersController uses ! empty() - allows 'Indonesia' string
 No phone number sanitization in order creation
 No validation that phone is actually a phone number
 CustomersController has better validation (isset + sanitize)

Next: Investigate source of 'Indonesia' value and implement fixes
2025-11-20 23:52:23 +07:00

8.4 KiB

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.phpcreate_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

// 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:

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:

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.phpupdate_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:

$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:

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:

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:

// 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:

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