# WooNooW Page Editor Strategy - Final Decision Brief (v3)

## Overview
Extend WooNooW SPA to support structural pages and CPT templates with:
- **Unified Page Editor** for pages (page CPT) and CPT templates (post, portfolio, custom)
- **Native WordPress `page` CPT** for structural pages (SEO compatible)
- **Dynamic placeholders** for CPT templates (blog posts, portfolio items, etc.)
- **Dual rendering strategy** for bots vs humans (SSR + SPA redirect)
- **Zero page builder plugin dependencies**
- **Integrated admin UI** with collapsible sidebar

---

## Core Architecture

### Data Storage

#### Structural Pages (page CPT)
- **Location**: WordPress `wp_posts` table (post_type='page')
- **Structure Storage**: `wp_postmeta`, key: `_wn_page_structure`
- **Type**: Static content only (no placeholders)
- **Example**: Homepage, About, Contact, Terms, Privacy

#### CPT Templates
- **Location**: WordPress `wp_options` table
- **Storage Keys**: `wn_template_{cpt_name}`
  - `wn_template_post` (for blog posts)
  - `wn_template_portfolio` (for portfolio items)
  - `wn_template_custom_cpt` (for custom CPTs)
- **Type**: Dynamic content with placeholders
- **Applies To**: All items of that CPT (one template per CPT)

### Page Structure Storage Format

```json
{
  "type": "page|template",
  "sections": [
    {
      "id": "section-1",
      "type": "hero",
      "layoutVariant": "hero-left-image",
      "colorScheme": "primary",
      "props": {
        "title": {
          "type": "static",
          "value": "Welcome"
        },
        "subtitle": {
          "type": "static",
          "value": "Join us"
        },
        "image": {
          "type": "static",
          "value": "/uploads/hero.jpg"
        }
      }
    },
    {
      "id": "section-2",
      "type": "content",
      "props": {
        "content": {
          "type": "dynamic",
          "source": "post_content"
        }
      }
    },
    {
      "id": "section-3",
      "type": "feature-grid",
      "layoutVariant": "grid-3-columns",
      "props": {
        "heading": {
          "type": "static",
          "value": "Why Choose Us"
        }
      }
    }
  ]
}
```

### Field Types: Static vs Dynamic

**Static Fields** (Structural Pages):
```json
{
  "type": "static",
  "value": "Hardcoded text or value"
}
```

**Dynamic Fields** (CPT Templates):
```json
{
  "type": "dynamic",
  "source": "post_title|post_content|post_excerpt|post_featured_image|related_posts|..."
}
```

#### Available Dynamic Sources (per CPT)

**For `post` CPT:**
- `post_title` - Post title
- `post_excerpt` - Post excerpt
- `post_content` - Post body content
- `post_featured_image` - Featured image URL
- `post_author` - Author name
- `post_date` - Publication date
- `post_categories` - Category list
- `post_tags` - Tag list
- `related_posts` - Query for related posts (with count parameter)

**For Custom CPTs:**
- `{cpt_name}_title` - CPT item title
- `{cpt_name}_featured_image` - Featured image
- `{cpt_name}_field_{field_name}` - Custom meta fields
- Custom sources defined per CPT

---

## Unified Page Editor Concept

### Single Editor, Two Modes

**Mode 1: Structural Pages (Static)**
- Edit individual pages (page CPT)
- All content is static/hardcoded
- Examples: Home, About, Contact, Terms, Privacy
- SEO managed by Yoast/Rank Math

**Mode 2: CPT Templates (Dynamic)**
- Design template for entire CPT
- Content has dynamic placeholders
- One template applies to all items of that CPT
- Examples: Blog Post template, Portfolio template, News template

### Create New Page Flow

When user clicks `[+ Create Page]`:

```
Modal Dialog:
┌──────────────────────────────────┐
│ Create New Page                  │
├──────────────────────────────────┤
│                                  │
│ What are you creating?           │
│                                  │
│ ○ Structural Page                │
│   Static content (page CPT)       │
│   Examples: About, Contact       │
│   Permalink: /page-slug          │
│                                  │
│ ○ Blog Post Template             │
│   Dynamic template for posts     │
│   Applies to: /blog/*            │
│   Includes placeholders          │
│                                  │
│ ○ Portfolio Template             │
│   Dynamic template for portfolio │
│   Applies to: /portfolio/*       │
│   Includes placeholders          │
│                                  │
│ ○ Other CPT Template             │
│   [Select CPT ▼]                 │
│   Applies to: /cpt-base/*        │
│                                  │
│ [Cancel]  [Next]                 │
└──────────────────────────────────┘
```

### Editor Left Panel: Pages List (Unified)

```
Pages Sidebar

📄 STRUCTURAL PAGES
├─ ✓ Homepage (page)
├─ ○ About (page)
├─ ○ Contact (page)
└─ ○ Terms (page)

📋 TEMPLATES (Dynamic)
├─ ○ Blog Post (post)
│  └─ Applies to: /blog/*
├─ ○ Portfolio (portfolio)
│  └─ Applies to: /portfolio/*
├─ ○ News (custom_cpt)
│  └─ Applies to: /news/*
└─ ○ Custom CPT (custom_name)
   └─ Applies to: /custom-base/*

Visual indicators:
- 📄 = Structural page (static)
- 📋 = Template (dynamic)
```

---

## Rendering Strategy: Dual Path

### Path 1: Bot Detection → Server-Side Rendering (SSR)

**When**: Bot user agent detected  
**Action**: Serve pre-rendered HTML (no redirect)  
**Content**: All sections rendered as static HTML strings  
**Placeholders**: Replaced with actual post data at render time  
**Result**: ✅ Full content indexed by search engines

```
Bot visits /blog/my-article
  ↓
is_bot() === true
  ↓
Get post data + load post template
  ↓
Replace placeholders (post_title, post_content, etc.)
  ↓
Render sections to static HTML
  ↓
Output: <html><h1>Article Title</h1><p>Post content...</p></html>
  ↓
✓ Bot crawls full content
✓ All text indexed
✓ All links followable
✓ SEO perfect
```

### Path 2: Human Detection → SPA Redirect

**When**: Human user agent detected  
**Action**: HTTP 302 redirect to SPA single-page app  
**Destination**: Matches WordPress permalink structure
  - `/about` → `/store/about`
  - `/blog/slug` → `/store/blog/slug`
  - `/portfolio/slug` → `/store/portfolio/slug`
**Result**: ✅ Beautiful interactive React UI

```
Human visits /blog/my-article
  ↓
is_bot() === false
  ↓
HTTP 302 → /store/blog/my-article
  ↓
SPA loads at /store/blog/my-article
  ↓
React detects path base (/blog) → loads post template
  ↓
React fetches post data for "my-article"
  ↓
React replaces placeholders with post data
  ↓
Renders sections with React components
  ↓
✓ Interactive UI
✓ No page reload
✓ Great UX
```

### Bot Detection Logic

Detect bots by User-Agent string:
```php
$bot_patterns = [
  'googlebot', 'bingbot', 'slurp', 'duckduckbot',
  'baiduspider', 'yandexbot', 'crawler', 'robot',
  'spider', 'facebookexternalhit', 'twitterbot',
  'linkedinbot', 'whatsapp', 'slackbot', 'applebot'
];
```

---

## SPA Architecture (Enhanced)

### SPA Remains Centralized
- **Single page location**: WordPress page (configurable, e.g., `/store/`)
- **Single React router**: Handles all SPA routes
- **Routes**: 
  - `/` - Homepage (products)
  - `/shop` - Shop listing
  - `/product/:slug` - Product detail
  - `/cart` - Shopping cart
  - `/checkout` - Checkout
  - `/my-account/*` - User account
  - **NEW Dynamic Routes**:
    - `/:slug` - Structural page (About, Contact, etc.)
    - `/:pathBase/:slug` - CPT item (blog post, portfolio, etc.)

### Dynamic Route Matching

```tsx
// React Router detects what to render
const router = createBrowserRouter([
  // Existing routes (higher priority)
  { path: '/', element: <Shop /> },
  { path: '/shop', element: <Shop /> },
  { path: '/product/:slug', element: <Product /> },
  
  // NEW: Dynamic routes (lower priority)
  { path: '/:pathBase/:slug', element: <DynamicPageRenderer /> },
  { path: '/:slug', element: <DynamicPageRenderer /> },
]);

// DynamicPageRenderer logic
function DynamicPageRenderer() {
  const { pathBase, slug } = useParams();
  const [pageData, setPageData] = useState(null);
  
  useEffect(() => {
    // Determine what template to use
    if (!pathBase) {
      // /:slug → Structural page (About, Contact, etc.)
      fetchPage(slug);
    } else {
      // /:pathBase/:slug → CPT item
      detectCPTFromPath(pathBase); // /blog → post, /portfolio → portfolio
      fetchCPTTemplate(cptType);
      fetchPostData(slug);
    }
  }, [pathBase, slug]);
  
  return <PageRenderer pageData={pageData} />;
}
```

### No Multiple "SPA Islands"
- Pages route through same SPA instance
- Same styling, same theme variables, same JavaScript context

---

## Page Editor UI Layout (3-Column Design)

### Visual Layout
```
┌─────────────────────────────────────────────────────────────┐
│ [☰] WooNooW    Appearance > Pages > [Blog Post Template]   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│ ┌────────────┬──────────────────┬──────────────────────┐   │
│ │   Pages    │                  │                      │   │
│ │   Sidebar  │   Editor Panel   │  Settings + Preview  │   │
│ │            │                  │                      │   │
│ │ 📄 Home    │ SECTIONS         │ Page Settings        │   │
│ │ ○ About    │ ────────────────│ ├─ Type: Template    │   │
│ │ ○ Contact  │ 1. Hero Section │ ├─ CPT: post        │   │
│ │            │    [Image ◆]    │ └─ Permalink: /blog │   │
│ │ 📋 Posts   │ 2. Content      │                      │   │
│ │ ○ Portfolio│    [Post Body ◆]│ Section Settings     │   │
│ │ ○ News     │ 3. Related Posts│ ├─ Layout: Grid 3   │   │
│ │            │    [Query ◆]    │ ├─ Count: [3___]    │   │
│ │ [+ Create] │ 4. CTA Banner   │ └─ [Delete]         │   │
│ │            │                  │                      │   │
│ │            │ [+ Add Section] │ Preview             │   │
│ │            │                  │ [Desktop] [Mobile]  │   │
│ │            │ Legend:         │ ┌──────────────────┐│   │
│ │            │ [◆] = Dynamic   │ │ Live SPA Preview ││   │
│ │            │     placeholder │ │ (Real-time)      ││   │
│ │            │                  │ └──────────────────┘│   │
│ │            │                  │                      │   │
│ └────────────┴──────────────────┴──────────────────────┘   │
│                                                             │
│ [Discard Changes]  [Save Changes]  [Preview]               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### Settings Panel Behavior

**For Structural Pages (No Section Selected):**
```
Page Settings
├─ Type: Page (Structural)
├─ Title: About Us
├─ Slug: about
└─ SEO: Manage in Yoast [→]
```

**For Templates (No Section Selected):**
```
Template Settings
├─ Type: Template (Dynamic)
├─ CPT: Post
├─ Applies to: /blog/*
└─ Edit CPT permalink: [→]
```

**For Sections with Dynamic Fields:**
```
Section Settings: Hero

Layout Variant
[Hero Left Image ▼]

Title Field
○ Static: [____________]
◉ Dynamic: [Post Title ◆]

Image Field
○ Static: [Choose Image]
◉ Dynamic: [Featured Image ◆]

[Delete Section]
```

---

## Admin SPA Integration

### Navigation Location
- **Menu**: Appearance (existing)
- **Submenu**: Pages (NEW)
- **Path**: `/admin/appearance/pages`

### Sidebar Behavior

**Default (Expanded):**
- Admin sidebar shows full menu with labels
- Page editor takes remaining width (3-column layout)

**Collapsed:**
- Admin sidebar shows icons only (~60px width)
- Page editor expands to use more width
- Tooltips show on hover

**Layout dimensions:**

| State | Sidebar | Content Area | Pages List | Editor | Settings+Preview |
|-------|---------|--------------|-----------|--------|------------------|
| Expanded | 240px | ~1160px | 120px | 650px | 390px |
| Collapsed | 60px | ~1340px | 120px | 750px | 470px |

### No Full-Screen Takeover
- ✅ Part of admin SPA normal content flow
- ✅ User maintains context (can quickly jump to other admin sections)
- ✅ Sidebar collapse is user-controlled, not forced
- ✅ Can navigate back via breadcrumb or admin menu

### Escape Routes
1. Click WooNooW logo → Dashboard
2. Click any menu item in sidebar → Navigate to that section
3. Press ESC key → Back (with unsaved changes warning)
4. Click browser back button → Back (with unsaved changes warning)
5. Click breadcrumb "Appearance" → Back to Appearance settings

---

## SEO Preservation

### Yoast/Rank Math Integration
- ✅ Meta title, meta description managed by Yoast/Rank Math
- ✅ Canonical URLs managed by WordPress
- ✅ Open Graph tags managed by SEO plugins
- ✅ Structured data can be added to page template
- ✅ No changes needed to existing SEO workflow

### For CPT Items (Posts, Portfolio, etc.)
- Yoast/Rank Math still manages SEO for individual CPT items
- Templates don't interfere with SEO workflow
- Bot sees pre-rendered content with all placeholders filled

### What Bots See

**Example: Blog Post with Template**
```html
<h1>Article Title</h1>
<img src="/uploads/featured.jpg" alt="Article featured image" />
<article>
  <p>Article body content goes here...</p>
</article>
<section class="related-posts">
  <h2>Related Articles</h2>
  <div class="grid">
    <a href="/blog/related-1">Related Post 1</a>
    <a href="/blog/related-2">Related Post 2</a>
  </div>
</section>
```

- ✅ All text crawlable
- ✅ All links followable
- ✅ Structure preserved
- ✅ Meta tags present
- ✅ Images indexed

---

## API Endpoints

### Get All Pages & Templates
```
GET /wp-json/woonoow/v1/pages
```

**Response:**
```json
[
  {
    "id": 42,
    "type": "page",
    "slug": "home",
    "title": "Homepage",
    "icon": "page"
  },
  {
    "type": "template",
    "cpt": "post",
    "title": "Blog Post Template",
    "icon": "template",
    "permalink_base": "/blog/"
  }
]
```

### Get Page or Template Structure
```
GET /wp-json/woonoow/v1/pages/about
GET /wp-json/woonoow/v1/templates/post
```

**Response:**
```json
{
  "type": "page|template",
  "id": 42,
  "slug": "about",
  "title": "About Us",
  "url": "https://mystore.com/about",
  "seo": {
    "meta_title": "About Us | My Store",
    "meta_description": "Learn about our company...",
    "canonical": "https://mystore.com/about",
    "og_title": "About Us",
    "og_image": "https://mystore.com/og-image.jpg"
  },
  "structure": {
    "sections": [...]
  }
}
```

### Get Single Post with Template Applied
```
GET /wp-json/woonoow/v1/posts/{post_id}/with-template
```

**Response:**
```json
{
  "post": {
    "id": 123,
    "title": "Article Title",
    "content": "Article body...",
    "featured_image": "/uploads/image.jpg",
    "author": "John Doe",
    "date": "2026-01-11"
  },
  "template": {
    "sections": [...]
  },
  "rendered": {
    "sections": [
      {
        "type": "hero",
        "props": {
          "title": "Article Title",  // Placeholder filled
          "image": "/uploads/image.jpg"  // Placeholder filled
        }
      }
    ]
  }
}
```

### Save Page or Template Structure
```
POST /wp-json/woonoow/v1/pages/about
POST /wp-json/woonoow/v1/templates/post
```

**Request body:**
```json
{
  "sections": [...]
}
```

**Response:**
```json
{
  "success": true,
  "page": { ... }
}
```

---

## Implementation Phases

### Phase 1: Core Infrastructure (Priority)
- [ ] Add bot detection logic to `TemplateOverride.php`
- [ ] Build `PageSSR` class to render sections as HTML
- [ ] Build `PlaceholderRenderer` class to replace dynamic placeholders
- [ ] Create REST API endpoints:
  - `GET /wp-json/woonoow/v1/pages` (list all)
  - `GET /wp-json/woonoow/v1/pages/{slug}` (get page)
  - `GET /wp-json/woonoow/v1/templates/{cpt}` (get template)
  - `GET /wp-json/woonoow/v1/posts/{id}/with-template` (get post with template)
  - `POST /wp-json/woonoow/v1/pages/{slug}` (save page)
  - `POST /wp-json/woonoow/v1/templates/{cpt}` (save template)
- [ ] Update template_redirect hook:
  - Detect if structural page or CPT item
  - Load appropriate template
  - Replace placeholders (for CPT items)
  - Serve SSR for bots (exit without redirect)
  - Redirect humans to SPA with matching permalink structure
- [ ] Create React `DynamicPageRenderer` component
- [ ] Test bot crawling vs human browsing

### Phase 2: Admin SPA Integration
- [ ] Add "Pages" submenu to Appearance menu
- [ ] Create `/admin/appearance/pages` route
- [ ] Build `PageEditor` component with 3-column layout
- [ ] Implement sidebar collapse/expand functionality
- [ ] Add breadcrumb navigation
- [ ] Implement create page modal (structural vs template selection)
- [ ] Test navigation flow

### Phase 3: WooNooW Page Editor (UI)
- [ ] Build custom admin page editor UI (React)
- [ ] Section list with drag-to-reorder
- [ ] Section selector popup when clicking "+ Add Section"
- [ ] Layout variant dropdown per section
- [ ] Color scheme selector per section
- [ ] Form fields for section content:
  - Static field: text input
  - Dynamic field: dropdown with available sources
- [ ] Live SPA preview iframe (real-time updates)
- [ ] Desktop/Mobile preview toggle
- [ ] Save/Publish button → stores to postmeta or wp_options
- [ ] Visual indicator for dynamic placeholders ([◆])

### Phase 4: Section Library
- [ ] Define section types and their props schema
- [ ] Hero section renderer (SSR + React)
- [ ] Content section renderer (for post body)
- [ ] Feature grid renderer (SSR + React)
- [ ] Related items section (for related posts/CPT items)
- [ ] CTA banner renderer (SSR + React)
- [ ] Add more sections as needed

### Phase 5: Polish & Launch
- [ ] Caching for SSR (cache rendered HTML for 1 hour)
- [ ] Unsaved changes warning (ESC key, browser back, menu click)
- [ ] Test SEO with Google Search Console
- [ ] Test with bot simulators (curl with bot user agents)
- [ ] Test dynamic placeholder rendering
- [ ] Documentation for merchants
- [ ] Documentation for developers (extending sections, custom placeholders)

---

## Database Schema

### Structural Pages (page CPT)
```sql
wp_posts:
├─ id: 42
├─ post_type: 'page'
├─ post_name: 'about'
├─ post_title: 'About Us'
├─ post_status: 'publish'
└─ post_modified: '2026-01-11 20:58:00'

wp_postmeta:
├─ post_id: 42, meta_key: '_wn_page_structure'
│  value: {"type": "page", "sections": [...]}
├─ post_id: 42, meta_key: '_yoast_wpseo_title'
│  value: "About Us | My Store"
├─ post_id: 42, meta_key: '_yoast_wpseo_metadesc'
│  value: "Learn about our company..."
├─ post_id: 42, meta_key: '_yoast_wpseo_canonical'
│  value: "https://mystore.com/about"
└─ post_id: 42, meta_key: '_yoast_wpseo_opengraph-image'
   value: "https://mystore.com/og-image.jpg"
```

### CPT Templates
```sql
wp_options:
├─ option_name: 'wn_template_post'
│  option_value: {"type": "template", "cpt": "post", "sections": [...]}
├─ option_name: 'wn_template_portfolio'
│  option_value: {"type": "template", "cpt": "portfolio", "sections": [...]}
└─ option_name: 'wn_template_custom_cpt'
   option_value: {"type": "template", "cpt": "custom_cpt", "sections": [...]}
```

---

## Target Users & Experience

### Tech-Savvy Users (Developers/Agencies)
**Use Case**: Building custom stores with WooNooW  
**Tools**: WooNooW CSS variables, class documentation, section schema  
**Value**: Framework for rapid SPA development, design system enforcement  

### Non-Tech Merchants
**Use Case**: Quick store setup with predefined pages and templates  
**Tools**: WooNooW Page Editor (constrained choices, no freestyle design)  
**Value**: Professional pages in minutes, consistent styling across all CPTs  

### Both
**Result**: Consistent visual identity across structural pages + dynamic CPT items  

---

## Decision Summary

| Aspect | Decision |
|--------|----------|
| **Editor Type** | Single unified editor for pages + CPT templates |
| **Structural Pages** | Native `page` CPT, stored in postmeta |
| **CPT Templates** | Stored in wp_options (one per CPT) |
| **Field Types** | Static (hardcoded) or Dynamic (with placeholders) |
| **Available Placeholders** | post_title, post_content, featured_image, author, date, related_posts, etc. |
| **Page Builder Integration** | None (custom WooNooW editor only) |
| **Admin Location** | Appearance > Pages (single submenu) |
| **Editor Context** | Part of admin SPA (not full-screen) |
| **Sidebar Behavior** | Collapsible (expanded or icon-only) |
| **Create Flow** | Modal asks: Structural page or CPT template? |
| **SPA Routing** | Matches WordPress permalink structure |
| **Permalink Matching** | `/blog/slug` → `/store/blog/slug` |
| **SEO** | Yoast/Rank Math for pages, templates don't interfere |
| **Bot Handling** | No redirect, serve pre-rendered HTML with placeholders filled |
| **Human Handling** | HTTP 302 redirect to SPA with matching permalink structure |
| **SPA Location** | Single centralized page (e.g., `/store/`) |
| **Performance** | Cache SSR HTML (1 hour TTL) |
| **UI Pattern** | 3-column layout (pages list, editor, settings+preview) |
| **Template Types** | Hero, Content, Feature Grid, Related Items, CTA Banner |

---

## What's NOT Changing

✅ Existing shop/product/cart/checkout functionality  
✅ Existing SPA architecture (single page, centralized)  
✅ Existing template override logic (extended, not replaced)  
✅ Existing API patterns (new endpoints follow conventions)  
✅ Existing CSS variable system (reused for all sections)  
✅ SEO plugin compatibility (Yoast, Rank Math continue to work)  
✅ Admin menu structure (Pages added to existing Appearance menu)  
✅ Admin sidebar (enhanced with collapse functionality, not replaced)  

---

## Key Architectural Benefits

✅ **One editor, two modes** - Merchants don't learn separate systems  
✅ **Clean separation** - Static pages vs dynamic templates clear  
✅ **URL consistency** - SPA routes match WordPress permalinks  
✅ **SEO perfect** - Bots see full content, humans get SPA experience  
✅ **Scalable** - Works for current CPTs and future custom CPTs  
✅ **Flexible placeholders** - Can add any post field or custom meta  
✅ **No page builder lock-in** - Custom sections, not Gutenberg/Elementor  
✅ **Maintains design consistency** - Predefined sections, no freestyle design  

---

## Next Discussion Topics
- [ ] Section library detailed specs (Hero, Content, Features, Related, CTA)
- [ ] Placeholder source definitions and extensibility
- [ ] Section schema validation
- [ ] Caching strategy details (Redis vs file-based vs transient)
- [ ] Migration path for existing pages/posts
- [ ] Developer documentation (extending sections, custom placeholders)
- [ ] Component structure and file organization (React + PHP)
