ZeroPress Logo ZeroPress Docs

Reference

ZeroPress Preview Data Spec v0.7

Status: Active (current preview-data contract)

This document is the long-form contract for Preview Data v0.7. Use the Preview Data Reference for quick field lookup and the Preview Data v0.7 Schema for machine-readable structural validation.

Preview Data and Theme Runtime have independent versions. A v0.7 Preview Data payload is currently consumed by themes using Theme Runtime v0.7. A theme’s theme.json therefore declares runtime 0.7; it does not declare the Preview Data version.

0. Core Philosophy

  • Preview Data is the canonical theme-facing content payload.
  • Preview Data is data-only. It does not contain a database model, CMS workflow, or render-ready application behavior.
  • Producers describe site content and policy; Build Core resolves defaults, routes, references, media, and theme context.
  • The contract must be safe to validate independently of the producer that created it.
  • Deterministic producers should use stable array ordering and canonical object-key ordering where the contract defines them.

1. Scope and Conformance

Preview Data v0.7 defines:

  • the top-level payload and site metadata
  • authors, posts, pages, categories, tags, and optional managed-media metadata
  • optional menus, widget areas, and named collections
  • search, feed, archive, permalink, front-page, post-index, discovery, and comment policies
  • optional trusted CSS and HTML customization inputs
  • contract-level URL, slug, timestamp, and path safety rules

It does not define:

  • Studio or other CMS storage and authoring APIs
  • a theme manifest or template syntax; those belong to Theme Runtime
  • a comment provider’s HTTP request and response schema
  • deployment, hosting, or database configuration

Conformance has three relevant layers:

  1. The JSON Schema describes the serializable shape and constraints that JSON Schema can express.
  2. @zeropress/preview-data-validator enforces the complete v0.7 input contract, including semantic and normalization-aware invariants.
  3. Build Core validates first, then resolves consumer defaults and derives render data and output paths.

A payload is not conforming merely because a generic JSON Schema validator accepts it. Producers and consumers must run the ZeroPress runtime validator as well.

1.1 Defaults are not input mutation

Schema default keywords are annotations. Validation returns the original object and does not add, remove, or rewrite values. Build Core may later materialize documented consumer defaults in its internal theme-facing model.

For example, omitting site.comments.provider is valid. The input remains unchanged after validation, while Build Core resolves the effective provider to "zeropress". Omitting site.search, site.feed, or site.archive likewise leaves the payload unchanged while consumers interpret the requested state as enabled.

1.2 Closed and open objects

Unless this document explicitly identifies an extension area, contract objects are closed: unknown properties are invalid. The intentionally open areas are:

  • scalar values under meta
  • structured values under Post/Page data
  • widget-type-specific keys under widget.items[].settings
  • dynamic map keys for menus, widgets, and collections

2. Minimal Valid Payload

All five top-level fields and all required site and content fields remain required even when a site has no content:

{
  "$schema": "https://schemas.zeropress.dev/preview-data/v0.7/schema.json",
  "version": "0.7",
  "generator": "example-generator",
  "generated_at": "2026-07-18T00:00:00Z",
  "site": {
    "title": "Example Site",
    "description": "",
    "url": "https://example.com",
    "media_origin": "",
    "locale": "en-US",
    "posts_per_page": 10,
    "date_style": "medium",
    "time_style": "none",
    "timezone": "UTC"
  },
  "content": {
    "authors": [],
    "posts": [],
    "pages": [],
    "categories": [],
    "tags": []
  }
}

$schema is optional. It is an editor and tooling hint; ZeroPress core does not interpret it during validation.

3. Top-Level Contract

Field Required Contract
$schema No String containing a schema URI or path hint
version Yes Literal string "0.7"
generator Yes Nonblank producer identifier
generated_at Yes Valid RFC 3339 timestamp using Z or a numeric UTC offset
site Yes Closed site configuration object
content Yes Closed content object
menus No Enabled menus keyed by menu id
widgets No Enabled widget areas keyed by widget-area id
collections No Named curated collections keyed by collection id
custom_css No Trusted site stylesheet input
custom_html No Trusted HTML injection slots

generated_at is the payload generation time, not a content publication time. Runtime validation checks actual calendar dates rather than accepting a date-shaped string only.

RFC 3339 permits a leap-second value with seconds 60, and the v0.7 validator accepts it. Current Build Core date rendering relies on ECMAScript Date, which cannot consume leap-second Post/Page timestamps. Producers targeting the current builder should therefore emit seconds from 00 through 59. This is a current consumer limitation, not a change to the v0.7 timestamp contract.

4. Site Contract

4.1 Required site fields

Field Contract
title Nonblank string
description String; may be empty
url Empty string or credential-free absolute HTTP(S) origin; canonical producers emit URL.origin
media_origin Empty string or absolute HTTP(S) origin
locale Canonical BCP 47 locale
posts_per_page Integer greater than or equal to 1
date_style none, short, medium, long, or full
time_style none, short, medium, long, or full
timezone UTC, a canonical IANA id, or a canonical fixed offset within -14:00 through +14:00

Build Core formats site-local fallback text from locale, timezone, date_style, and time_style. Canonical *_at_iso values remain the machine-readable instants. Themes may progressively enhance explicitly marked <time datetime="..."> elements for a visitor’s locale and timezone, but should preserve build-generated text when client-side formatting is unavailable.

none omits that date or time portion. When both styles are none, formatted display strings are empty while canonical timestamps remain available. Fixed offsets use the canonical +09:00 shape, cannot exceed the real-world ±14:00 range, and must not express zero as +00:00 or -00:00; use UTC instead.

4.2 Site defaults resolved by consumers

The following fields are optional. Their effective Build Core behavior when omitted is:

Field Effective default
media_delivery_mode none
expose_generator true
search { "enabled": true }, subject to theme search capability
feed { "enabled": true }, subject to canonical URL and build settings
archive { "enabled": true }, subject to archive.html availability
robots { "allow_indexing": true }
permalinks.output_style directory
permalinks.posts /posts/:slug/
permalinks.pages /:slug/
permalinks.categories /categories/:slug/
permalinks.tags /tags/:slug/
front_page { "type": "theme_index" }
post_index { "enabled": true, "path": "/", "paginate": true }
footer.attribution true

Only some of these values appear as JSON Schema default annotations. The table describes Build Core behavior, not validation-time mutation.

search, feed, and archive are optional closed objects. Whenever one exists, enabled is required; {}, booleans, null, and unknown fields are invalid. Omission means requested enabled true.

These objects express requested state, not guaranteed output. Search is effective only when the active theme declares features.search: true. Feed is effective only when site.url is a canonical absolute URL and the build wrapper has not applied its generateFeed: false hard override. Archive is effective only when the active theme contains archive.html. Build Core exposes the resulting effective objects to themes.

When search or archive is ineffective, Build Core removes only corresponding search or archive widget items. It retains the widget area and all other items. Menus are authored data and are never rewritten or filtered based on these feature states.

robots is an optional closed object. When present, allow_indexing is required; {}, a boolean, null, or the removed site.indexing field is invalid. { "allow_indexing": false } controls the fallback robots.txt policy and remains distinct from per-document discoverability.

expose_generator: false suppresses ZeroPress generator metadata. It is distinct from visible footer attribution.

4.3 URL classes

The contract uses different URL classes deliberately:

  • site.url: empty or a credential-free HTTP(S) origin only. A trailing root slash is accepted; canonical producers emit URL.origin without it.
  • site.media_origin: empty or an HTTP(S) origin only. Credentials, a non-root path, query, and fragment are forbidden. A trailing root slash is accepted; canonical producers should omit it.
  • navigation fields such as menu and newsletter URLs: a credential-free absolute HTTP(S) URL or a safe single-slash root-relative URL. / is allowed.
  • media fields such as favicons, logos, avatars, featured images, and managed-media sources: the same absolute/root-relative policy, but a real non-root path is required, so / alone is invalid.
  • comments API base: an absolute HTTP(S) URL or a single-slash root-relative path, without credentials, query, or fragment.

Navigation and media URLs reject bare or dot-relative paths, protocol-relative URLs, path dot segments, whitespace, backslashes, control characters, malformed percent encoding, credentials, and unsafe schemes. Query strings and fragments are allowed for navigation and media URLs. Comments API URLs continue to reject query strings and fragments. Runtime validation uses WHATWG URL parsing to check hostname, port, IP address, and URL syntax; JSON Schema format is descriptive annotation rather than a substitute for the ZeroPress runtime validator.

4.4 Media origin and delivery

site.media_origin replaces the pre-v0.7 media-base URL model. A non-empty value identifies only an origin:

{
  "media_origin": "https://media.example.com",
  "media_delivery_mode": "media_domain"
}

Build Core resolves accepted root-relative media values such as /images/cover.jpg against this origin. Absolute external URLs remain external. When media_origin is empty, root-relative values remain same-host paths. Bare and dot-relative media values are not valid v0.7 input.

This normalization applies to:

  • author avatars
  • Post and Page featured images
  • content.media[].src
  • favicon and logo values
  • profile-widget avatars

media_delivery_mode supports:

Value Meaning
none Preserve normalized media URLs without deriving responsive variant URLs
media_domain Allow responsive variants for matching managed raster media at media_origin

Omitting media_delivery_mode means none. Selecting media_domain with an empty media_origin is a hard validation error.

media_domain does not make every image managed. Build Core derives srcset only when the normalized image exactly matches a content.media entry, is served from the configured origin, and has a supported raster extension.

site.favicon is optional and must contain at least one URL when present:

{
  "favicon": {
    "icon": "/favicon.ico",
    "icon_dark": "/favicon.dark.ico",
    "svg": "/favicon.svg",
    "png": "/favicon.png",
    "apple_touch_icon": "/apple-touch-icon.png"
  }
}

icon_dark is the color-scheme-specific dark icon. Build wrappers may auto-discover conventional public favicon files when the first-class field is omitted; that wrapper behavior does not change the Preview Data input contract.

site.logo is optional theme-facing identity data:

{
  "logo": {
    "src": "/logo.svg",
    "alt": "Example Site"
  }
}

src is required when the object exists. alt is optional and may be empty; a theme may fall back to site.title when it is omitted.

4.6 Newsletter

site.newsletter is optional theme-facing CTA or island data:

{
  "newsletter": {
    "enabled": true,
    "title": "Subscribe",
    "description": "Get new posts by email.",
    "button_label": "Subscribe",
    "signup_url": "https://example.com/newsletter",
    "embed_url": "/newsletter/embed"
  }
}

enabled is required. When it is true, signup_url, embed_url, or both are required. Display strings are optional and themes own fallback copy. The contract does not define provider submission behavior or provider-specific JavaScript.

4.7 Comments

site.comments is optional provider configuration and requested state. Omitting it means no provider is configured and comment runtime is unavailable. If present, both enabled and api_base_url are required:

{
  "comments": {
    "enabled": true,
    "api_base_url": "https://comments.example.com/api",
    "provider": "zeropress",
    "per_page": 50,
    "order": "desc",
    "threading": {
      "enabled": true,
      "max_depth": 2
    }
  }
}

Consumer defaults are:

Field Default Range or values
enabled No default; required Boolean
provider zeropress zeropress, wordpress
per_page 50 Integer 1–100
order desc asc, desc
threading.enabled true Boolean
threading.max_depth 2 Integer 2–10

Build Core removes trailing slashes from api_base_url, except for the root-relative value /.

Validation requires an item request token when all of these data-only conditions hold, regardless of the theme selected later:

  • site.comments exists
  • site.comments.enabled is true
  • the effective provider is zeropress
  • the item has allow_comments: true

That item must contain:

{
  "comments": {
    "request_token": "opaque-public-token"
  }
}

The token must be nonblank and at most 512 Unicode code points. Its provider-specific internal format is intentionally outside this contract.

Build Core exposes an enabled comment context for an individual Post or Page only when all of these runtime conditions hold:

  • the theme declares features.comments: true
  • site.comments exists
  • site.comments.enabled is true
  • the item has allow_comments: true
  • the item has a positive public_id
  • for the ZeroPress provider, the item has a valid comments.request_token

For the WordPress provider or an otherwise inactive comment state, item-level comments metadata is optional rather than forbidden. If present, it must still have the valid closed-object shape. Build Core drops ignored request metadata and never exposes a request token in the WordPress or inactive theme context.

site.footer is optional:

{
  "footer": {
    "copyright_text": "Example Site",
    "attribution": false
  }
}

copyright_text, when present, is nonblank. Missing or true attribution allows a supporting theme to show ZeroPress attribution; false asks it to hide that UI.

site.meta is an optional generator-defined scalar extension object. Values may be strings, finite numbers, booleans, or null. ZeroPress core does not interpret its keys.

5. Content Contract

content is closed and requires all of these arrays:

  • authors
  • posts
  • pages
  • categories
  • tags

media is optional.

5.1 Authors

{
  "id": "editor",
  "display_name": "Example Editor",
  "avatar": "/avatars/editor.jpg"
}

id and display_name are required and nonblank. avatar is optional and follows the general media URL policy. Author ids must be unique, and every Post author_id must resolve to one exported author.

5.2 Posts

Every Post requires:

Field Contract
public_id Positive integer, unique within Posts
title Nonblank string
slug Safe slug segment
content String; may be empty
document_type plaintext, markdown, or html
excerpt String; may be empty
published_at_iso Valid RFC 3339 timestamp
updated_at_iso Valid RFC 3339 timestamp
author_id Nonblank reference to an exported author
status published or draft
allow_comments Boolean
category_slugs Array of safe slug references
tag_slugs Ordered array of safe slug references

Optional fields are featured_image, meta, data, discoverability, and conditional comments.

tag_slugs order is the theme-facing display order. Values must be unique after NFC normalization. The first tag is display-first only; it does not implicitly become a primary or SEO tag.

The global content.tags array has no semantic display order. Deterministic producers should sort global definitions by name and then slug. This does not alter each Post’s tag_slugs order.

Post public_id is public identity, not a Studio or database-internal id. There is no Post id field in v0.7.

5.3 Pages

Every Page requires:

  • title
  • slug
  • content
  • document_type
  • status

Optional fields are:

  • public_id
  • path
  • excerpt
  • featured_image
  • updated_at_iso
  • meta
  • data
  • discoverability
  • allow_comments
  • comments

Missing Page allow_comments means false. Setting it to true requires a positive public_id. Page ids must be unique within Pages. A Post and a Page may use the same numeric public id because they are different target types.

path is a relative route override without leading or trailing slashes, for example company/about. Each component follows the slug policy. When omitted, Build Core derives the effective path from site.permalinks.pages and the Page slug. A producer that knows a Page hierarchy materializes it in path. Page leaf slugs are not identities: two Pages may both use about when their NFC-normalized effective paths differ. Effective Page paths must be unique after NFC normalization.

5.4 Categories and tags

Categories and tags require name and slug; description is optional. Names are nonblank, descriptions may be empty, and slugs follow the common slug contract.

Post category and tag arrays are slug references. Build Core derives matching taxonomy objects and routes from the global definitions.

5.5 Managed media metadata

content.media is optional:

{
  "src": "/images/cover.jpg",
  "width": 1600,
  "height": 900,
  "alt": "Cover image"
}

src, width, and height are required. Dimensions are positive integers; alt is optional and may be empty. Media src values must be unique.

This array describes media already referenced by fields such as featured_image or avatar; it does not replace those fields. Build Core matches the normalized URL to attach dimensions and optionally derive responsive variants.

5.6 Document discovery

Post and Page discoverability is optional. Missing is equivalent to default; canonical producers should omit the explicit default value.

Value Behavior
default Normal automatic discovery
noindex Render the route and add HTML robots noindex
delist Render the route, add noindex, and omit it from automatic discovery outputs

Automatic discovery includes generated listings, sitemap, and native search where applicable. Explicit menus, named collections, and manual links are not access control and may still expose a delisted document.

5.7 meta and data

Post and Page meta is for scalar metadata. Each value must be a string, finite number, boolean, or null.

Post and Page data is for structured theme-facing data such as facts, galleries, timelines, or swatches. It must be an object and follows these limits:

  • keys match ^[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*$
  • every object has at most 64 keys
  • every array has at most 256 items
  • nested container depth is at most 4 below the root data object
  • values are JSON-safe strings, finite numbers, booleans, null, arrays, or objects

Use meta for simple flags and labels. Use data when the theme needs repeated or nested structures.

6. Menus, Widgets, and Collections

6.1 Menus

menus is an optional map of enabled menus. Menu ids match ^[a-z][a-z0-9_-]{0,63}$.

{
  "menus": {
    "primary": {
      "name": "Primary Menu",
      "items": [
        {
          "title": "Home",
          "url": "/",
          "target": "_self",
          "children": []
        }
      ]
    }
  }
}

A menu requires a nonblank name and an items array. Every item requires:

  • nonblank title
  • URL-like url
  • target of _self or _blank
  • recursive children array

Optional item meta is scalar extension data. menuItem.type is not part of v0.7; URLs are already resolved and themes should not infer behavior from a producer-specific type marker.

6.2 Widgets

widgets is an optional map of enabled widget areas. Widget-area ids use the same 1–64 character identifier shape as menu ids.

{
  "widgets": {
    "sidebar": {
      "name": "Sidebar",
      "items": [
        {
          "type": "search",
          "title": "",
          "settings": {
            "placeholder": "Search..."
          }
        }
      ]
    }
  }
}

A widget area requires a nonblank name and items. A widget item requires nonblank type and a string title. An empty or whitespace-only title is valid and means no displayed widget title after Build Core trims it. settings is an optional open object whose policy belongs to the widget type and Theme Runtime.

Omitting widgets and providing {} both mean there are no enabled widget areas in Preview Data. Importers may have their own explicit fallback-generation policy before producing the final payload; that policy is not part of this contract.

6.3 Collections

collections is an optional map of curated content lists. Collection ids match ^[a-z][a-z0-9_-]{0,63}$.

{
  "collections": {
    "featured": {
      "title": "Featured",
      "description": "Selected reading",
      "items": [
        { "type": "post", "slug": "hello" },
        { "type": "page", "path": "docs/about" }
      ]
    }
  }
}

items is required. title is optional and nonblank when present; description is optional and may be empty. Each item is a closed discriminated reference. Posts use { "type": "post", "slug": "hello" }; Pages use { "type": "page", "path": "docs/about" }, where path is the Page’s NFC-normalized effective route path. Providing both slug and path, or the field for the other type, is invalid. Duplicate normalized identities in one collection are invalid. Build Core requires every reference to resolve and fails the build when referenced content is missing.

7. Site Customization Inputs

7.1 Custom CSS

custom_css is an optional closed object:

{
  "custom_css": {
    "content": ".site-title { letter-spacing: 0.02em; }"
  }
}

content is required and nonblank. Build tooling consumes it as trusted raw CSS and emits the corresponding site stylesheet asset.

7.2 Custom HTML

custom_html is an optional trusted build directive outside site and theme runtime data:

{
  "custom_html": {
    "head_end": "<meta name=\"site-verification\" content=\"example\">",
    "body_end": "<script defer src=\"/vendor/app.js\"></script>"
  }
}

At least one slot is required. Each supplied slot must be nonblank and no longer than 65,536 Unicode code points. Values are direct raw strings; the earlier { "content": "..." } slot shape is not part of v0.7.

ZeroPress does not sanitize, escape, deduplicate, or rewrite URLs inside these strings. Build Core inserts head_end before </head> and body_end before </body> on theme-rendered HTML routes. A configured slot whose closing target is absent fails the build instead of silently discarding content.

A front_page.type: "standalone_html" document remains independent and does not receive favicon, generator, custom CSS, or custom HTML injection.

8. Slug and Path Safety

8.1 Slug segment policy

The shared segment policy applies to Post, Page, category, tag, Post collection references, effective Page paths, post-index paths, and literal permalink segments.

A valid segment:

  • contains at least one Unicode letter or decimal digit
  • may contain Unicode letters, combining marks, decimal digits, _, -, and isolated internal . characters
  • does not begin or end with .
  • does not contain consecutive periods
  • is not . or ..
  • contains no slash, backslash, whitespace, control character, or percent encoding
  • contains at most 200 Unicode code points after NFC normalization

Examples:

Value Result Reason
theme-runtime-v0.6 Valid Isolated internal period has meaning
café Valid Decomposed input is accepted and evaluated after NFC normalization
.draft Invalid Leading period
release..notes Invalid Consecutive periods
. Invalid Reserved dot segment
hello/world Invalid Path separator inside one segment

The public Schema records the normalization-aware limit using a ZeroPress extension annotation because ordinary JSON Schema length is not NFC-aware.

8.2 Route path rules

Permalink patterns and post_index.path are absolute paths beginning with /. Page path is relative and has no leading or trailing slash. These route values reject:

  • empty path components
  • backslashes, query strings, fragments, whitespace, controls, and percent encoding
  • a literal lowercase .html suffix in any route segment

The literal .html restriction prevents a path policy from colliding with html-extension output handling. It does not ban meaningful internal periods from ordinary slug segments.

Build tooling must independently verify every computed output path remains within the output root. Input validation never replaces final filesystem safety checks.

site.permalinks is optional and closed:

{
  "permalinks": {
    "output_style": "directory",
    "posts": "/posts/:slug/",
    "pages": "/:slug/",
    "categories": "/categories/:slug/",
    "tags": "/tags/:slug/"
  }
}

All members are optional independently; Build Core fills an omitted member from the defaults in section 4.2.

output_style values are:

Value Public URL and output shape for the route /about/
directory Public /about/, output about/index.html
html-extension Public /about, output about.html

html-extension describes the generated filename; ZeroPress uses its extensionless clean URL in theme links, canonical metadata, sitemap, feed, and search data. For Pages only, a terminal index path keeps directory-index behavior: path: "guides/index" produces output guides/index.html and public URL /guides/.

Tokens occupy a complete path segment.

Field Allowed tokens Required token
posts :slug, :public_id, :year, :month, :day :slug or :public_id
pages :slug :slug
categories :slug :slug
tags :slug :slug

Date tokens use the Post publication instant interpreted in site.timezone, not necessarily its UTC calendar date.

10. Front Page and Post Index

10.1 Front page

site.front_page supports:

type Additional requirement Meaning
theme_index None Theme index owns /
page page_path The Page with that effective relative route path owns /
standalone_html html Trusted complete HTML owns /

The three shapes are closed and discriminated: fields from another branch are invalid. page_path is NFC-normalized and has no leading or trailing slash. Build Core requires it to resolve to an exported Page’s effective path. standalone_html content is a complete document and bypasses theme rendering and site customization injection.

10.2 Post index

site.post_index has optional enabled, path, and paginate fields. Missing values resolve to true, /, and true respectively.

When a Page or standalone HTML owns /, an enabled Post index cannot also use /; Build Core fails the conflicting configuration. Choose a non-root index path such as /blog/ or disable the Post index. A theme may also disable post-index capability.

11. Runtime-Only Semantic Invariants

The following requirements are normative even though the public JSON Schema cannot express all of them completely:

  • author ids are unique
  • Post public_id values are unique within Posts
  • provided Page public_id values are unique within Pages
  • Post slugs are unique after NFC normalization
  • effective Page paths are unique after NFC normalization; duplicate Page leaf slugs are allowed when paths differ
  • equal numeric ids across one Post and one Page are allowed
  • every Post author_id resolves to an exported author
  • managed-media src values are unique
  • Post tag_slugs values are unique after NFC normalization
  • collection Post references resolve by normalized slug, Page references resolve by normalized effective path, and references are not duplicated
  • RFC 3339 values represent real calendar dates and valid clock/offset components
  • slug and literal route-segment lengths are measured after NFC normalization
  • URLs pass WHATWG parsing in addition to the Schema’s structural patterns
  • computed output paths remain safe after token substitution and output-style conversion

The validator reports errors and currently produces no warning-only results. Producers should treat any error as a rejected payload rather than attempting to guess a repaired contract value.

12. Deterministic Serialization

JSON object order has no semantic meaning, but stable serialization helps review, caching, and reproducible output. The validator package exports canonicalizePreviewDataKeyOrder() for presentation canonicalization.

That helper:

  • clones rather than mutates the payload
  • orders known closed-object keys according to the v0.7 Schema
  • sorts dynamic map keys and open-object keys lexically
  • preserves array order
  • does not validate, add defaults, normalize values, or remove unknown fields

Semantic array rules still apply. In particular, Post tag_slugs order is meaningful and must be preserved, while global tag definition order is nonsemantic and should be emitted deterministically by producers.

13. Compatibility Notes

Preview Data v0.7 accepts only version: "0.7". It does not include compatibility aliases for removed v0.6 fields or shapes.

Important v0.7 differences include:

  • site.media_origin replaces site.media_base_url
  • site.indexing is removed in favor of the closed site.robots: { "allow_indexing": boolean } object
  • Page front-page and collection references use effective route paths (page_path and path) instead of Page leaf slugs
  • site.datetime_display is removed
  • Post internal id is removed
  • menuItem.type is removed
  • custom_html.head_end and body_end are direct strings
  • favicon supports icon_dark
  • comments are first-class site and Post/Page data
  • site.disallow_comments is removed; site.comments.enabled is the positive site-level request flag
  • site.search is a closed { "enabled": boolean } object rather than a boolean
  • site.feed and site.archive add independent closed generation requests with the same shape
  • Pages may have public comment identity and comment policy
  • widget item title remains required but may be empty to suppress its heading
  • Page leaf slugs may repeat when effective paths differ; Post slugs and effective Page paths remain unique identities
  • duplicate normalized content references within one collection are invalid
  • slug/path handling permits meaningful isolated periods while enforcing dot-segment safety
  • Post tag reference order is explicitly theme-facing and NFC-unique

Producers migrating from v0.6 must account for these changes directly. Historical v0.6 documents and schemas describe v0.6 only and must not be treated as alternate valid shapes for a v0.7 payload.

14. Normative Summary

Area Classification Summary
version, generator, generated_at, site, content Required Core payload identity and data
menus, widgets, collections Optional Missing values resolve to empty theme-facing maps
custom_css, custom_html Optional, trusted Build inputs rather than ordinary theme data
site.search, site.feed, site.archive Optional Closed { "enabled": boolean } requests; omission means requested enabled
site.comments Optional Requires enabled and api_base_url; provider and display defaults are consumer-resolved
site.robots Optional Closed global indexing policy; omission means { "allow_indexing": true }
Post/Page comments Conditional/optional Required by the enabled ZeroPress/item data policy; otherwise allowed but ignored by Build Core
Post public_id and allow_comments Required Public identity and per-item behavior
Page public_id and allow_comments Optional Missing comments policy means false; true requires public id
meta Optional open scalar map Generator/theme convention data
data Optional bounded structured object Repeated or nested theme-facing content
site.permalinks, front_page, post_index Optional Build Core resolves documented route defaults
slug and route safety Required Enforced by runtime validation and again at output planning
schema defaults Informative annotations Do not mutate validated input
Build Core normalization Consumer behavior Produces effective theme and route context after validation