Skip to content

Manifest schema

Every artifact ships a manifest.json validated against a JSON Schema at publish time. Required fields: name, version, format, supports.

Field Type Description
name string The template’s identity, lowercase, hyphenated, stable across versions.
version string Semver. Stable versions are immutable once submitted. Owner-only development versions use x.y.z-dev.N, remain non-promotable, and may be replaced before creating a stable release.
format port60-liquid@2 The dialect/contract major this template is written against.
label string Human-readable name shown in pickers.
description string
requiresCapabilities array Platform capabilities this design needs in order to work as intended. This is a catalogue matching signal, never an entitlement grant. The validator checks that each declared capability has a corresponding section, page template, island or context surface.
suitsProfiles array Organisation profiles this design was composed for. An empty list means the template is general purpose. Profiles improve catalogue recommendations but do not hide or unlock features.
changelog string One human line describing what THIS version changed, shown on the Appearance update nudge.
supports object
supports.pages array Section based page bodies this template renders from sections/{type}.liquid. Contract v1 supports home and about. This is independent of layout chrome and route-specific pageTemplates.
supports.sections array Section types this template ships renderers for (sections/{type}.liquid). Unsupported types are omitted at render, never an error.
supports.islands array Islands this template places. Every {% island %} name must be listed here AND exist in the platform island registry.
supports.layout boolean True when the template ships layout.liquid and owns the page chrome (header/nav/footer). The platform still owns , consent, and identity, see the layouts guide.
supports.pageTemplates array Route-specific data views rendered from pages/{page}.liquid with documented context. Events and articles own listings; course and article own detail presentation. Event transactions, course enrolment, article engagement, comments, identity and consent stay platform-owned islands. Requires supports.layout; without an entry the platform body renders inside the template chrome.
supports.worship boolean True when the layout renders the worship context (the prayer/service-times rail). Declared honesty: the choosers badge worship-enabled tenants toward looks that show their times, and warn on looks that don’t. Requires supports.layout; the layout must actually branch on worship.
supports.navigationModes object Explicit header presentation choices for this exact layout: simple (inline dropdown), cascading (side-opening descendants), mega (wide panel per header item), panel (one Menu button). Declare only the 2 to 4 implemented modes, with a default from that subset. Preserve navigation nodes, order, destinations and saved metadata in every mode. Requires supports.layout. The host resolves an accepted saved menus.headerMode or this default into site.nav.headerMode. Mark the navigation root data-p60-navigation-mode with that resolved mode. Missing support leaves saved preferences unused, never inferred from navigationHighlights.
supports.navigationModes.options array
supports.navigationModes.default simple | cascading | mega | panel
supports.sectionCollectionLinkVisibility array Supported collection section types whose existing onward link may be hidden. Every entry must also be in supports.sections and render its supplied collection destination on a permanent data-p60-collection-link anchor. Only section.showCollectionLink == false adds hidden; absent or true retains the template default link. Keep its shared label and destination unchanged, and never hide the heading, records, cards or individual record links. No new URLs, text override or positioning control.
supports.navigationHighlights boolean True when the layout displays the optional single site.nav.items[].megaMenu.promo card inside each expanded top-level menu. Requires supports.layout. The validator proves title, text, image and linked label render together; image-free and absent highlights must remain safe. The platform resolves linked courses, events and campaigns into the same promo fields as custom highlights. This flag does not enable a general mega menu or control column counts. Missing or false disables highlight editing for this exact template version.
supports.fieldMarkers boolean True when the sections mark which node shows which field with data-p60-field, so the editor can put the caret on the page instead of in a side panel. The address is inside that section’s own content: data-p60-field=“title”, or data-p60-field=“items.{{ forloop.index0 }}.label” for an entry in a list. Purely additive: the attribute is markup, the contract is untouched, and a template that marks nothing keeps the section-level editor. The validator reads the marks from the source and warns on any that does not name a field of that section. Missing or false leaves this exact template version editing in the panel.
supports.sectionFields object Per-section opt-in to optional authored fields in this exact template version. The initial capability is the About introduction photograph: hero must also occur in supports.sections, and imageUrl/imageAlt are declared together. Optional photoFraming adds fill/whole on that photo; absent/reset inherits the author’s composition while explicit whole shows the uncropped natural ratio. A fixed-layout photograph can be supported without sectionLayout. Missing support keeps saved photo fields but omits them from rendering and offers no new image picker. Validation proves supplied source/alt, no-photo omission, bounded framing and section ownership.
supports.sectionFields.hero array
supports.sectionPresentation object Exact-version opt-in to independent platform-owned section presentation controls. Every key must be in supports.sections and declare at least one known control. Each control’s default must occur in its options and describe inherited responsive styling. Saved explicit choices are projected into section.presentation; absence inherits without writing defaults. headingScale requires a permanent data-p60-heading-scale hook on the actual heading and authored font-size CSS. sectionSpacing requires a permanent data-p60-section-spacing hook on the natural outer section root and authored block-axis padding CSS, even without a heading; never alter horizontal gutters, card gaps, heights or island internals. Missing declarations are unsupported. No arbitrary values, conditions or CSS selectors are accepted.
supports.sectionHeadingAlignment object Explicit opt-in per supported section type to desktop heading alignment choices. Missing entries disable the editor control. The host projects section.headingAlignment only for declared options. Mark heading/eyebrow elements using data-p60-heading-align with that value. The shared base applies text-align at widths of at least 1024 CSS pixels; absent/empty hooks retain the template default at every width. The validator proves each declared option renders on real headings and cannot change unrelated content. No layout positioning is implied.
supports.heroImagery boolean True when the homeHero renderer displays the tenant’s hero photographs (homeHero.images, legacy imageUrl), always under a TREATMENT built from the template’s own palette variables (scrim/tint/blend), never raw. Declared honesty, proven behaviourally at validation: the choosers badge photo-led tenants toward templates that show their images and warn on ones that won’t. Requires the homeHero section among supports.sections.
supports.heroImageLimit integer Maximum homeHero photographs this exact template version can present. Requires supports.heroImagery: true. Missing means one; no hero imagery means zero. Values above one require rendering every image in a fixture of the declared size or placing the hero_carousel island. Generic carousel behavior or island declarations alone do not opt in. This gates editor additions, never truncates saved photographs or changes an older artifact’s rendering.
supports.behaviors array Engine-attached behaviours this template’s markup opts into via data-p60-* attributes (see the behaviour catalogue). Templates never ship JavaScript; declaring here is what makes the engine wire the markup, and the validator proves declaration and usage agree in both directions.
supports.focus array The site-focus kinds this template can LEAD with (docs/volunteering.md). Declaring ‘volunteer’ means the home hero places the primary_action_widget island (the widget that becomes the donation widget or the volunteer sign-up as the charity chooses) or branches on section.primary.kind, so the volunteer sign-up can take the widget slot; the picker marks templates that cannot lead with volunteering. Templates that predate the setting keep rendering the donation widget, since donate is the default.
imagery object The template’s OWN image advice, surfaced beside uploads in the charity’s editor, a design statement (what shape suits THIS composition), advisory only, never enforced. Entity images (events, courses, articles) are platform-scoped instead: see the contract’s imagery.json envelopes.
imagery.hero object
imagery.hero.idealAspect string The aspect this hero composes best with, e.g. “16:9”.
imagery.hero.minWidth integer Below this pixel width the photo may look soft full-bleed.
imagery.hero.note string One human line of advice, e.g. how panoramas or portraits behave in this hero.
fonts array Webfont stylesheet URLs the platform loads in (with preconnects, never a CSS @import). Google Fonts css2 URLs only.
looks array One-click LOOKS: author-named bundles of knob values (scheme + fonts + width…) applied together. Everything remains individually adjustable afterwards.
looks[].name string The look’s evocative, author-chosen name, shown as a one-click chip in Appearance.
looks[].values object Knob key → value. Every key must be a declared settings knob; select values must be listed options; font values must be catalogue families.
compositions object The template’s preferred composition per supported page (site editor stage 4): the ordered section types it designs the page around, each with a role. core sections carry the design (removing one warns, never locks), recommended ones are on by default, optional ones are offered. A page a tenant never edited renders this composition; the Pages editor offers it as the order to reset to.
settings object
settings.schema array The template’s own theming knobs (colour schemes etc.), rendered as an editor in Appearance/get-started; values land in site-config config.theme.
settings.schema[].key string
settings.schema[].kind color | select | toggle | font
settings.schema[].label string
settings.schema[].default
settings.schema[].options array
settings.schema[].group typography | looks | header | footer Where the admin surfaces this knob: typography, looks, or the shared header/footer inspector. Header and footer groups explicitly declare template-authored global chrome settings, not a new content source. Every option must have template-owned CSS or markup; omitted groups never imply support. Other ungrouped knobs render under Template options.
settings.schema[].weights array FONT knobs only: the weights this template’s typographic system uses for the slot. The host requests these for the tenant’s chosen family (clamped to the family’s real weights). The tenant picks the FAMILY; weights, sizes and tracking stay template-owned.

Worked example, the starter template’s manifest

Section titled “Worked example, the starter template’s manifest”
{
"name": "starter",
"version": "2.0.0",
"format": "port60-liquid@2",
"label": "Starter",
"description": "The reference template for the Port60 dialect, the developer docs' worked example and the base to copy when building your own. 1.1.0 adds the layout slot: the template owns the header, navigation and footer chrome.",
"supports": {
"navigationHighlights": false,
"fieldMarkers": true,
"sectionFields": {
"hero": [
"imageUrl",
"imageAlt",
"photoFraming"
]
},
"sectionPresentation": {
"homeHero": {
"headingScale": {
"options": [
"compact",
"standard",
"large"
],
"default": "standard"
},
"sectionSpacing": {
"options": [
"compact",
"standard",
"spacious"
],
"default": "standard"
}
},
"hero": {
"sectionLayout": {
"options": [
"image-start",
"image-end",
"stacked"
],
"default": "stacked"
},
"headingScale": {
"options": [
"compact",
"standard",
"large"
],
"default": "standard"
},
"sectionSpacing": {
"options": [
"compact",
"standard",
"spacious"
],
"default": "standard"
}
},
"values": {
"headingScale": {
"options": [
"compact",
"standard",
"large"
],
"default": "standard"
},
"sectionSpacing": {
"options": [
"compact",
"standard",
"spacious"
],
"default": "standard"
}
},
"cta": {
"headingScale": {
"options": [
"compact",
"standard",
"large"
],
"default": "standard"
},
"sectionSpacing": {
"options": [
"compact",
"standard",
"spacious"
],
"default": "standard"
}
}
},
"pages": [
"home",
"about"
],
"sections": [
"homeHero",
"hero",
"values",
"cta",
"people",
"campaigns",
"impactMap",
"form"
],
"islands": [
"donation_widget",
"member_menu",
"hero_carousel",
"map",
"form",
"primary_action_widget",
"search"
],
"layout": true,
"heroImagery": true,
"heroImageLimit": 6,
"behaviors": [
"reveal",
"carousel",
"nav"
],
"focus": [
"donate",
"volunteer"
]
},
"compositions": {
"home": [
{
"type": "homeHero",
"role": "core"
},
{
"type": "campaigns",
"role": "recommended"
},
{
"type": "impactMap",
"role": "optional"
},
{
"type": "cta",
"role": "recommended"
}
],
"about": [
{
"type": "hero",
"role": "core"
},
{
"type": "values",
"role": "recommended"
},
{
"type": "people",
"role": "optional"
},
{
"type": "cta",
"role": "recommended"
}
]
},
"settings": {
"schema": [
{
"key": "siteFont",
"kind": "font",
"label": "Site font",
"default": "Inter",
"weights": [
400,
500,
600,
700,
800
]
}
]
},
"changelog": "Uses the v2 site object, resolved header actions and collection envelopes while preserving authored field markers.",
"imagery": {
"hero": {
"idealAspect": "16:9",
"minWidth": 1600,
"note": "Landscape around 16:9 fills the hero cleanly; panoramas suit the whole-photo framing."
}
}
}