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
This commit is contained in:
547
CUSTOMER_SPA_SETTINGS.md
Normal file
547
CUSTOMER_SPA_SETTINGS.md
Normal file
@@ -0,0 +1,547 @@
|
||||
# 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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```http
|
||||
GET /wp-json/woonoow/v1/settings/customer-spa
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"layout": "modern",
|
||||
"colors": {
|
||||
"primary": "#3B82F6",
|
||||
"secondary": "#8B5CF6",
|
||||
"accent": "#10B981"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Update Settings
|
||||
|
||||
```http
|
||||
POST /wp-json/woonoow/v1/settings/customer-spa
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": true,
|
||||
"layout": "modern",
|
||||
"colors": {
|
||||
"primary": "#FF6B6B"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"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
|
||||
```typescript
|
||||
{
|
||||
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';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Featured Products
|
||||
```typescript
|
||||
{
|
||||
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
|
||||
```typescript
|
||||
{
|
||||
type: 'categories',
|
||||
config: {
|
||||
title: string;
|
||||
categoryIds: number[];
|
||||
columns: 2 | 3 | 4;
|
||||
showProductCount: boolean;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Testimonials
|
||||
```typescript
|
||||
{
|
||||
type: 'testimonials',
|
||||
config: {
|
||||
title: string;
|
||||
testimonials: Array<{
|
||||
name: string;
|
||||
avatar: string;
|
||||
rating: number;
|
||||
text: string;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Newsletter
|
||||
```typescript
|
||||
{
|
||||
type: 'newsletter',
|
||||
config: {
|
||||
title: string;
|
||||
description: string;
|
||||
placeholder: string;
|
||||
buttonText: string;
|
||||
mailchimpListId?: string;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 Storage
|
||||
|
||||
### WordPress Options Table
|
||||
|
||||
Settings are stored in `wp_options`:
|
||||
|
||||
```php
|
||||
// Option name: woonoow_customer_spa_enabled
|
||||
// Value: boolean (true/false)
|
||||
|
||||
// Option name: woonoow_customer_spa_settings
|
||||
// Value: JSON-encoded settings object
|
||||
```
|
||||
|
||||
### PHP Implementation
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```php
|
||||
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());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Customer SPA Architecture](./CUSTOMER_SPA_ARCHITECTURE.md)
|
||||
- [Customer SPA Theme System](./CUSTOMER_SPA_THEME_SYSTEM.md)
|
||||
- [API Routes](./API_ROUTES.md)
|
||||
Reference in New Issue
Block a user