# 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.