feat: Page Editor v1.0 - canonical schema, SSR parity, and migration

Major improvements to WooNooW Page Editor system:

Schema & Architecture:
- Canonical section schema with unified sectionSchema.ts
- Normalized feature-grid to use items (not features)
- Standardized default values across all section types
- Schema versioning with automatic migration on read

Backend (PHP):
- Enhanced PlaceholderRenderer with typed output contracts
- Added fallback behavior for empty/invalid dynamic sources
- Added caching support for post data resolution
- New SchemaMigration class for backward compatibility
- New Features class for feature flags
- Enhanced PageSSR with full style support
- Removed controller-level special-casing for related_posts

Frontend (Admin SPA):
- Updated CanvasRenderer with schema-aware transformation
- Enhanced InspectorPanel with canonical schema metadata
- Added new section renderers

Frontend (Customer SPA):
- New section components: BentoCategoryGrid, MarqueeBanner, ProductCarousel, ShoppableImage
- Updated FeatureGridSection for items prop contract

Testing:
- Add PHP tests: SchemaMigrationTest, PlaceholderRendererTest, PageSSRTest
- Add TypeScript tests: schema-integration, feature-grid-regression
- Add parity tests for React vs SSR content matching
- Add CI script: check-schema-drift.mjs
- Add VERIFICATION_CHECKLIST.md

Documentation:
- RELEASE_NOTES-v1.0.md with full release notes
- docs/PAGE_EDITOR_SECTION_SCHEMA_V1.md
- docs/PAGE_EDITOR_SSR_COVERAGE_AUDIT.md
This commit is contained in:
Dwindi Ramadhana
2026-05-30 13:02:08 +07:00
parent e70aa1f554
commit 396ca25be4
118 changed files with 10162 additions and 3726 deletions

View File

@@ -0,0 +1,42 @@
# Page Editor Section Schema v1
## Purpose
The Page Editor uses one canonical section contract for editor defaults, inspector fields, canvas rendering, storefront rendering, and PHP SSR expectations.
The TypeScript source of truth is:
```text
admin-spa/src/routes/Appearance/Pages/schema/sectionSchema.ts
```
## Canonical Rules
- Section type names use kebab-case in saved JSON, for example `feature-grid`.
- Section props are stored as `SectionProp` objects: `{ "type": "static", "value": ... }` or `{ "type": "dynamic", "source": ... }`.
- Runtime renderers receive flattened prop values after adapter transformation or backend resolution.
- Repeater props must use arrays as their static value.
- `feature-grid.items` is the canonical feature/post-card list prop.
- `feature-grid.features` is supported only as a legacy read fallback.
## Current Section Types
| Type | Canonical repeater props | Notes |
|---|---|---|
| `hero` | none | Dynamic title/subtitle/image supported by inspector metadata |
| `content` | none | Rich text content may be dynamic |
| `image-text` | none | Dynamic title/text/image supported |
| `feature-grid` | `items` | Legacy `features` is read as fallback |
| `cta-banner` | none | Static CTA content |
| `contact-form` | none | Webhook/redirect URLs are static settings |
| `bento-category-grid` | `items` | Array of category/grid item objects |
| `product-carousel` | none | Product source/limit are scalar props |
| `shoppable-image` | `hotspots` | Array of product hotspot objects |
| `marquee-banner` | none | Scalar text/separator/speed props |
## Migration Notes
- Existing saved `feature-grid.features` values should be read as `items` at render time.
- New editor writes should persist `feature-grid.items`.
- A future payload-level `schemaVersion` should make legacy migration explicit.
## Preview Resolution Contract
- Template preview samples are fetched from `GET /woonoow/v1/preview/samples/{cpt}`.
- Dynamic template preview sections are resolved through `POST /woonoow/v1/preview/resolve/{cpt}`.
- The editor must render resolved preview sections separately from the saved source sections so dynamic values do not overwrite `{ type: "dynamic", source: "..." }` metadata.

View File

@@ -0,0 +1,26 @@
# Page Editor SSR Coverage Audit
## Scope
This audit compares section types available in the admin canvas and customer DynamicPage renderer against explicit PHP SSR renderers in `includes/Frontend/PageSSR.php`.
## Coverage Matrix
| Section type | Admin canvas | Customer SPA | PHP SSR | Status |
|---|---:|---:|---:|---|
| `hero` | yes | yes | `render_hero` | covered |
| `content` | yes | yes | `render_content` | covered |
| `image-text` | yes | yes | `render_image_text` | covered |
| `feature-grid` | yes | yes | `render_feature_grid` | covered, now reads `items` with `features` fallback |
| `cta-banner` | yes | yes | `render_cta_banner` | covered |
| `contact-form` | yes | yes | `render_contact_form` | covered for SEO structure only |
| `bento-category-grid` | yes | yes | `render_bento_category_grid` | covered |
| `product-carousel` | yes | yes | `render_product_carousel` | covered for configured/static product data |
| `shoppable-image` | yes | yes | `render_shoppable_image` | covered |
| `marquee-banner` | yes | yes | `render_marquee_banner` | covered |
## Immediate Finding
The SSR path now has explicit renderers for all section types exposed by the editor canvas. The next gap is deeper content parity for sections that rely on runtime API data, especially product carousel data loading.
## Next Implementation Targets
1. Add product data resolution for `product-carousel` when SSR runs without pre-resolved products.
2. Add parity fixtures covering one scalar-heavy section and one repeater-heavy section.
3. Add snapshot tests comparing React content output vs SSR content output.