Files
WooNooW/CUSTOMER_SPA_ARCHITECTURE.md
Dwindi Ramadhana f397ef850f feat: Add product images support with WP Media Library integration
- Add WP Media Library integration for product and variation images
- Support images array (URLs) conversion to attachment IDs
- Add images array to API responses (Admin & Customer SPA)
- Implement drag-and-drop sortable images in Admin product form
- Add image gallery thumbnails in Customer SPA product page
- Initialize WooCommerce session for guest cart operations
- Fix product variations and attributes display in Customer SPA
- Add variation image field in Admin SPA

Changes:
- includes/Api/ProductsController.php: Handle images array, add to responses
- includes/Frontend/ShopController.php: Add images array for customer SPA
- includes/Frontend/CartController.php: Initialize WC session for guests
- admin-spa/src/lib/wp-media.ts: Add openWPMediaGallery function
- admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx: WP Media + sortable images
- admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx: Add variation image field
- customer-spa/src/pages/Product/index.tsx: Add gallery thumbnails display
2025-11-26 16:18:43 +07:00

11 KiB

WooNooW Customer SPA Architecture

🎯 Core Decision: Full SPA Takeover (No Hybrid)

What We're NOT Doing (Lessons Learned)

REJECTED: Hybrid SSR + SPA approach

  • WordPress renders HTML (SSR)
  • React hydrates on top (SPA)
  • WooCommerce hooks inject content
  • Theme controls layout

PROBLEMS EXPERIENCED:

  • ✗ Script loading hell (spent 3+ hours debugging)
  • ✗ React Refresh preamble errors
  • ✗ Cache conflicts
  • ✗ Theme conflicts
  • ✗ Hook compatibility nightmare
  • ✗ Inconsistent UX (some pages SSR, some SPA)
  • ✗ Not truly "single-page" - full page reloads

What We're Doing Instead

APPROVED: Full SPA Takeover

  • React controls ENTIRE page (including <html>, <body>)
  • Zero WordPress theme involvement
  • Zero WooCommerce template rendering
  • Pure client-side routing
  • All data via REST API

BENEFITS:

  • ✓ Clean separation of concerns
  • ✓ True SPA performance
  • ✓ No script loading issues
  • ✓ No theme conflicts
  • ✓ Predictable behavior
  • ✓ Easy to debug

🏗️ Architecture Overview

System Diagram

┌─────────────────────────────────────────────────────┐
│                  WooNooW Plugin                     │
├─────────────────────────────────────────────────────┤
│                                                     │
│  ┌──────────────────┐      ┌──────────────────┐   │
│  │   Admin SPA      │      │  Customer SPA    │   │
│  │   (React)        │      │  (React)         │   │
│  │                  │      │                  │   │
│  │ - Products       │      │ - Shop           │   │
│  │ - Orders         │      │ - Product Detail │   │
│  │ - Customers      │      │ - Cart           │   │
│  │ - Analytics      │      │ - Checkout       │   │
│  │ - Settings       │◄─────┤ - My Account     │   │
│  │   └─ Customer    │      │                  │   │
│  │      SPA Config  │      │ Uses settings    │   │
│  └────────┬─────────┘      └────────┬─────────┘   │
│           │                         │             │
│           └────────┬────────────────┘             │
│                    │                              │
│         ┌──────────▼──────────┐                   │
│         │   REST API Layer    │                   │
│         │  (PHP Controllers)  │                   │
│         └──────────┬──────────┘                   │
│                    │                              │
│         ┌──────────▼──────────┐                   │
│         │  WordPress Core     │                   │
│         │  + WooCommerce      │                   │
│         │  (Data Layer Only)  │                   │
│         └─────────────────────┘                   │
└─────────────────────────────────────────────────────┘

🔧 Three-Mode System

Mode 1: Admin Only (Default)

✅ Admin SPA: Active (product management, orders, etc.)
❌ Customer SPA: Inactive
→ User uses their own theme/page builder for frontend

Mode 2: Full SPA (Complete takeover)

✅ Admin SPA: Active
✅ Customer SPA: Full Mode (takes over entire site)
→ WooNooW controls everything
→ Choose from 4 layouts: Classic, Modern, Boutique, Launch

Mode 3: Checkout-Only SPA 🆕 (Hybrid approach)

✅ Admin SPA: Active
✅ Customer SPA: Checkout Mode (partial takeover)
→ Only overrides: Checkout → Thank You → My Account
→ User keeps theme/page builder for landing pages
→ Perfect for single product sellers with custom landing pages

Settings UI:

Admin SPA > Settings > Customer SPA

Customer SPA Mode:
○ Disabled (Use your own theme)
○ Full SPA (Take over entire storefront)
● Checkout Only (Override checkout pages only)

If Checkout Only selected:
  Pages to override:
  [✓] Checkout
  [✓] Thank You (Order Received)
  [✓] My Account
  [ ] Cart (optional)

🔌 Technical Implementation

1. Customer SPA Activation Flow

// When user enables Customer SPA in Admin SPA:

1. Admin SPA sends: POST /wp-json/woonoow/v1/settings/customer-spa
   {
     "enabled": true,
     "layout": "modern",
     "colors": {...},
     ...
   }

2. PHP saves to wp_options:
   update_option('woonoow_customer_spa_enabled', true);
   update_option('woonoow_customer_spa_settings', $settings);

3. PHP activates template override:
   - template_include filter returns spa-full-page.php
   - Dequeues all theme scripts/styles
   - Outputs minimal HTML with React mount point

4. React SPA loads and takes over entire page

2. Template Override (PHP)

File: includes/Frontend/TemplateOverride.php

public static function use_spa_template($template) {
    $mode = get_option('woonoow_customer_spa_mode', 'disabled');
    
    // Mode 1: Disabled
    if ($mode === 'disabled') {
        return $template; // Use normal theme
    }
    
    // Mode 3: Checkout-Only (partial SPA)
    if ($mode === 'checkout_only') {
        $checkout_pages = get_option('woonoow_customer_spa_checkout_pages', [
            'checkout' => true,
            'thankyou' => true,
            'account'  => true,
            'cart'     => false,
        ]);
        
        if (($checkout_pages['checkout'] && is_checkout()) ||
            ($checkout_pages['thankyou'] && is_order_received_page()) ||
            ($checkout_pages['account'] && is_account_page()) ||
            ($checkout_pages['cart'] && is_cart())) {
            return plugin_dir_path(__DIR__) . '../templates/spa-full-page.php';
        }
        
        return $template; // Use theme for other pages
    }
    
    // Mode 2: Full SPA
    if ($mode === 'full') {
        // Override all WooCommerce pages
        if (is_woocommerce() || is_cart() || is_checkout() || is_account_page()) {
            return plugin_dir_path(__DIR__) . '../templates/spa-full-page.php';
        }
    }
    
    return $template;
}

3. SPA Template (Minimal HTML)

File: templates/spa-full-page.php

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php wp_title('|', true, 'right'); ?><?php bloginfo('name'); ?></title>
    <?php wp_head(); // Loads WooNooW scripts only ?>
</head>
<body <?php body_class('woonoow-spa'); ?>>
    <!-- React mount point -->
    <div id="woonoow-customer-app"></div>
    
    <?php wp_footer(); ?>
</body>
</html>

That's it! No WordPress theme markup, no WooCommerce templates.

4. React SPA Entry Point

File: customer-spa/src/main.tsx

import React from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';

// Get config from PHP
const config = window.woonoowCustomer;

// Mount React app
const root = document.getElementById('woonoow-customer-app');
if (root) {
  createRoot(root).render(
    <React.StrictMode>
      <BrowserRouter>
        <App config={config} />
      </BrowserRouter>
    </React.StrictMode>
  );
}

5. React Router (Client-Side Only)

File: customer-spa/src/App.tsx

import { Routes, Route } from 'react-router-dom';
import { ThemeProvider } from './contexts/ThemeContext';
import Layout from './components/Layout';
import Shop from './pages/Shop';
import Product from './pages/Product';
import Cart from './pages/Cart';
import Checkout from './pages/Checkout';
import Account from './pages/Account';

export default function App({ config }) {
  return (
    <ThemeProvider config={config.theme}>
      <Layout>
        <Routes>
          <Route path="/shop" element={<Shop />} />
          <Route path="/product/:slug" element={<Product />} />
          <Route path="/cart" element={<Cart />} />
          <Route path="/checkout" element={<Checkout />} />
          <Route path="/my-account/*" element={<Account />} />
        </Routes>
      </Layout>
    </ThemeProvider>
  );
}

Key Point: React Router handles ALL navigation. No page reloads!


📋 Implementation Roadmap

Phase 1: Core Infrastructure (DONE)

  • Full-page SPA template
  • Script loading (Vite dev server)
  • React Refresh preamble fix
  • Template override system
  • Dequeue conflicting scripts

Phase 2: Settings System (NEXT)

  • Create Settings REST API endpoint
  • Build Settings UI in Admin SPA
  • Implement color picker component
  • Implement layout selector
  • Save/load settings from wp_options

Phase 3: Theme System

  • Create 3 master layouts (Classic, Modern, Boutique)
  • Implement design token system
  • Build ThemeProvider
  • Apply theme to all components

Phase 4: Homepage Builder

  • Create section components (Hero, Featured, etc.)
  • Build drag-drop section manager
  • Section configuration modals
  • Dynamic section rendering

Phase 5: Navigation

  • Fetch WP menus via REST API
  • Render menus in SPA
  • Mobile menu component
  • Mega menu support

Phase 6: Pages

  • Shop page (product grid)
  • Product detail page
  • Cart page
  • Checkout page
  • My Account pages

Decision Log

Decision Rationale Date
Full SPA takeover (no hybrid) Hybrid SSR+SPA caused script loading hell, cache issues, theme conflicts Nov 22, 2024
Settings in Admin SPA (not wp-admin) Consistent UX, better UI components, easier to maintain Nov 22, 2024
3 master layouts (not infinite) SaaS approach: curated options > infinite flexibility Nov 22, 2024
Design tokens (not custom CSS) Maintainable, predictable, accessible Nov 22, 2024
Client-side routing only True SPA performance, no page reloads Nov 22, 2024