Files
WooNooW/CUSTOMER_SPA_SETTINGS.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 Settings

📍 Settings Location

Admin SPA > Settings > Customer SPA

(NOT in wp-admin, but in our React admin interface)


📊 Settings Schema

TypeScript Interface

interface CustomerSPASettings {
  // Mode
  mode: 'disabled' | 'full' | 'checkout_only';
  
  // Checkout-Only mode settings
  checkoutPages?: {
    checkout: boolean;
    thankyou: boolean;
    account: boolean;
    cart: boolean;
  };
  
  // Layout (for full mode)
  layout: 'classic' | 'modern' | 'boutique' | 'launch';
  
  // Branding
  branding: {
    logo: string;      // URL
    favicon: string;   // URL
    siteName: string;
  };
  
  // Colors (Design Tokens)
  colors: {
    primary: string;    // #3B82F6
    secondary: string;  // #8B5CF6
    accent: string;     // #10B981
    background: string; // #FFFFFF
    text: string;       // #1F2937
  };
  
  // Typography
  typography: {
    preset: 'professional' | 'modern' | 'elegant' | 'tech' | 'custom';
    customFonts?: {
      heading: string;
      body: string;
    };
  };
  
  // Navigation
  menus: {
    primary: number;  // WP menu ID
    footer: number;   // WP menu ID
  };
  
  // Homepage
  homepage: {
    sections: Array<{
      id: string;
      type: 'hero' | 'featured' | 'categories' | 'testimonials' | 'newsletter' | 'custom';
      enabled: boolean;
      order: number;
      config: Record<string, any>;
    }>;
  };
  
  // Product Page
  product: {
    layout: 'standard' | 'gallery' | 'minimal';
    showRelatedProducts: boolean;
    showReviews: boolean;
  };
  
  // Checkout
  checkout: {
    style: 'onepage' | 'multistep';
    enableGuestCheckout: boolean;
    showTrustBadges: boolean;
    showOrderSummary: 'sidebar' | 'inline';
  };
}

Default Settings

const DEFAULT_SETTINGS: CustomerSPASettings = {
  mode: 'disabled',
  checkoutPages: {
    checkout: true,
    thankyou: true,
    account: true,
    cart: false,
  },
  layout: 'modern',
  branding: {
    logo: '',
    favicon: '',
    siteName: get_bloginfo('name'),
  },
  colors: {
    primary: '#3B82F6',
    secondary: '#8B5CF6',
    accent: '#10B981',
    background: '#FFFFFF',
    text: '#1F2937',
  },
  typography: {
    preset: 'professional',
  },
  menus: {
    primary: 0,
    footer: 0,
  },
  homepage: {
    sections: [
      { id: 'hero-1', type: 'hero', enabled: true, order: 0, config: {} },
      { id: 'featured-1', type: 'featured', enabled: true, order: 1, config: {} },
      { id: 'categories-1', type: 'categories', enabled: true, order: 2, config: {} },
    ],
  },
  product: {
    layout: 'standard',
    showRelatedProducts: true,
    showReviews: true,
  },
  checkout: {
    style: 'onepage',
    enableGuestCheckout: true,
    showTrustBadges: true,
    showOrderSummary: 'sidebar',
  },
};

🔌 REST API Endpoints

Get Settings

GET /wp-json/woonoow/v1/settings/customer-spa

Response:

{
  "enabled": true,
  "layout": "modern",
  "colors": {
    "primary": "#3B82F6",
    "secondary": "#8B5CF6",
    "accent": "#10B981"
  },
  ...
}

Update Settings

POST /wp-json/woonoow/v1/settings/customer-spa
Content-Type: application/json

{
  "enabled": true,
  "layout": "modern",
  "colors": {
    "primary": "#FF6B6B"
  }
}

Response:

{
  "success": true,
  "data": {
    "enabled": true,
    "layout": "modern",
    "colors": {
      "primary": "#FF6B6B",
      "secondary": "#8B5CF6",
      "accent": "#10B981"
    },
    ...
  }
}

🎨 Customization Options

1. Layout Options (4 Presets)

Classic Layout

  • Traditional ecommerce design
  • Header with logo + horizontal menu
  • Sidebar filters on shop page
  • Grid product listing
  • Footer with widgets
  • Best for: B2B, traditional retail

Modern Layout (Default)

  • Minimalist, clean design
  • Centered logo
  • Top filters (no sidebar)
  • Large product cards with hover effects
  • Simplified footer
  • Best for: Fashion, lifestyle brands

Boutique Layout

  • Fashion/luxury focused
  • Full-width hero sections
  • Masonry grid layout
  • Elegant typography
  • Minimal UI elements
  • Best for: High-end fashion, luxury goods

Launch Layout 🆕 (Single Product Funnel)

  • Landing page: User's custom design (Elementor/Divi) - NOT controlled by WooNooW
  • WooNooW takes over: From checkout onwards (after CTA click)
  • No traditional header/footer on checkout/thank you/account pages
  • Streamlined checkout (one-page, minimal fields, no cart)
  • Upsell/downsell on thank you page
  • Direct product access in My Account
  • Best for:
    • Digital products (courses, ebooks, software)
    • SaaS trials → paid conversion
    • Webinar funnels
    • High-ticket consulting
    • Limited-time offers
    • Product launches

Flow: Landing Page (Custom) → [CTA to /checkout] → Checkout (SPA) → Thank You (SPA) → My Account (SPA)

Note: This is essentially Checkout-Only mode with funnel-optimized design.

2. Color Customization

Primary Color:

  • Used for: Buttons, links, active states
  • Default: #3B82F6 (Blue)

Secondary Color:

  • Used for: Badges, accents, secondary buttons
  • Default: #8B5CF6 (Purple)

Accent Color:

  • Used for: Success states, CTAs, highlights
  • Default: #10B981 (Green)

Background & Text:

  • Auto-calculated for proper contrast
  • Supports light/dark mode

3. Typography Presets

Professional

  • Heading: Inter
  • Body: Lora
  • Use case: Corporate, B2B

Modern

  • Heading: Poppins
  • Body: Roboto
  • Use case: Tech, SaaS

Elegant

  • Heading: Playfair Display
  • Body: Source Sans Pro
  • Use case: Fashion, Luxury

Tech

  • Heading: Space Grotesk
  • Body: IBM Plex Mono
  • Use case: Electronics, Gadgets

Custom

  • Upload custom fonts
  • Specify font families

4. Homepage Sections

Available section types:

Hero Banner

{
  type: 'hero',
  config: {
    image: string;        // Background image URL
    heading: string;      // Main heading
    subheading: string;   // Subheading
    ctaText: string;      // Button text
    ctaLink: string;      // Button URL
    alignment: 'left' | 'center' | 'right';
  }
}
{
  type: 'featured',
  config: {
    title: string;
    productIds: number[];  // Manual selection
    autoSelect: boolean;   // Auto-select featured products
    limit: number;         // Number of products to show
    columns: 2 | 3 | 4;
  }
}

Category Grid

{
  type: 'categories',
  config: {
    title: string;
    categoryIds: number[];
    columns: 2 | 3 | 4;
    showProductCount: boolean;
  }
}

Testimonials

{
  type: 'testimonials',
  config: {
    title: string;
    testimonials: Array<{
      name: string;
      avatar: string;
      rating: number;
      text: string;
    }>;
  }
}

Newsletter

{
  type: 'newsletter',
  config: {
    title: string;
    description: string;
    placeholder: string;
    buttonText: string;
    mailchimpListId?: string;
  }
}

💾 Storage

WordPress Options Table

Settings are stored in wp_options:

// Option name: woonoow_customer_spa_enabled
// Value: boolean (true/false)

// Option name: woonoow_customer_spa_settings
// Value: JSON-encoded settings object

PHP Implementation

// Get settings
$settings = get_option('woonoow_customer_spa_settings', []);

// Update settings
update_option('woonoow_customer_spa_settings', $settings);

// Check if enabled
$enabled = get_option('woonoow_customer_spa_enabled', false);

🔒 Permissions

Who Can Modify Settings?

  • Capability required: manage_woocommerce
  • Roles: Administrator, Shop Manager

REST API Permission Check

public function update_settings_permission_check() {
    return current_user_can('manage_woocommerce');
}

🎯 Settings UI Components

Admin SPA Components

  1. Enable/Disable Toggle

    • Component: Switch
    • Shows warning when enabling
  2. Layout Selector

    • Component: LayoutPreview
    • Visual preview of each layout
    • Radio button selection
  3. Color Picker

    • Component: ColorPicker
    • Supports hex, rgb, hsl
    • Live preview
  4. Typography Selector

    • Component: TypographyPreview
    • Shows font samples
    • Dropdown selection
  5. Homepage Section Builder

    • Component: SectionBuilder
    • Drag-and-drop reordering
    • Add/remove/configure sections
  6. Menu Selector

    • Component: MenuDropdown
    • Fetches WP menus via API
    • Dropdown selection

📤 Data Flow

Settings Update Flow

1. User changes setting in Admin SPA
   ↓
2. React state updates (optimistic UI)
   ↓
3. POST to /wp-json/woonoow/v1/settings/customer-spa
   ↓
4. PHP validates & saves to wp_options
   ↓
5. Response confirms save
   ↓
6. React Query invalidates cache
   ↓
7. Customer SPA receives new settings on next load

Settings Load Flow (Customer SPA)

1. PHP renders spa-full-page.php
   ↓
2. wp_head() outputs inline script:
   window.woonoowCustomer = {
     theme: <?php echo json_encode($settings); ?>
   }
   ↓
3. React app reads window.woonoowCustomer
   ↓
4. ThemeProvider applies settings
   ↓
5. CSS variables injected
   ↓
6. Components render with theme

🧪 Testing

Unit Tests

describe('CustomerSPASettings', () => {
  it('should load default settings', () => {
    const settings = getDefaultSettings();
    expect(settings.enabled).toBe(false);
    expect(settings.layout).toBe('modern');
  });
  
  it('should validate color format', () => {
    expect(isValidColor('#FF6B6B')).toBe(true);
    expect(isValidColor('invalid')).toBe(false);
  });
  
  it('should merge partial updates', () => {
    const current = getDefaultSettings();
    const update = { colors: { primary: '#FF0000' } };
    const merged = mergeSettings(current, update);
    expect(merged.colors.primary).toBe('#FF0000');
    expect(merged.colors.secondary).toBe('#8B5CF6'); // Unchanged
  });
});

Integration Tests

class CustomerSPASettingsTest extends WP_UnitTestCase {
    public function test_save_settings() {
        $settings = ['enabled' => true, 'layout' => 'modern'];
        update_option('woonoow_customer_spa_settings', $settings);
        
        $saved = get_option('woonoow_customer_spa_settings');
        $this->assertEquals('modern', $saved['layout']);
    }
    
    public function test_rest_api_requires_permission() {
        wp_set_current_user(0); // Not logged in
        
        $request = new WP_REST_Request('POST', '/woonoow/v1/settings/customer-spa');
        $response = rest_do_request($request);
        
        $this->assertEquals(401, $response->get_status());
    }
}