Sections and blocks
A section is sections/{type}.liquid: markup plus one {% schema %} naming it and declaring its settings, the blocks it accepts and the presets that put it in the section picker. A theme block is blocks/{type}.liquid, read the same way, and can be placed in any section that accepts it. A local block is declared inside a section's schema with its own settings and drawn by the section's own markup.
The shape of a section file
<div class="hero color-{{ section.settings.color_scheme }}" {{ section.settings.entrance | animation_attributes }}>
{% if section.settings.image %}{{ section.settings.image | image_tag: sizes: '100vw', loading: 'eager' }}{% endif %}
{% content_for 'blocks' %}
</div>
{% stylesheet %}
.hero { min-height: var(--min-height, 80svh); }
{% endstylesheet %}
{% schema %}
{
"name": "Hero",
"category": "Content",
"description": "A large opening image with a heading, a sentence and a call to action.",
"tag": "section",
"class": "hero-section",
"settings": [ … ],
"blocks": [ { "type": "@theme" } ],
"max_blocks": 12,
"presets": [ { "name": "Hero", "category": "Content", "blocks": [ … ] } ],
"enabled_on": { "templates": ["home", "page.*"], "groups": [] },
"thumbnail": "images/sections/hero.svg",
"hidden": false
}
{% endschema %}
Each file carries at most one {% schema %}, one {% stylesheet %} and one {% javascript %}; a second of any is an error. All three are taken out when the theme loads: the stylesheets of every section and block are bundled into one file the head links, and the scripts into one file where each runs in its own try block so two sections' top-level names never collide and one failing never stops the rest.
Schema fields
| Field | Meaning | Rule |
|---|---|---|
name |
What the owner sees in the picker | required |
category |
The picker's heading — Content, Media, Business, Leads, Layout… | recommended (an informational note without one) |
description |
A sentence under the name | — |
tag |
The element the platform wraps the section in | one of section, div, header, footer, aside, nav, article; anything else renders as section |
class |
A class on that element, beside ab-section ab-section--{type} |
— |
settings |
The section's settings | see Settings; ids unique within the file |
blocks |
What the section accepts (below) | — |
max_blocks |
The most blocks the section holds | 1–250 |
presets |
Ready-made configurations in the picker | a section without any cannot be added from the picker (a warning) unless hidden |
enabled_on / disabled_on |
Where the section may be used: templates (template keys, * for all) and groups (group names, *) |
an unknown template type or group is an error |
thumbnail |
A theme asset (an SVG or picture) for the picker | — |
hidden |
Kept out of the picker; still renders where a template names it | — |
Blocks a section accepts
"blocks" is a list of entries of three kinds:
- A local definition —
{ "type": "slide", "name": "Slide", "limit": 6, "settings": [ … ] }. It has settings and no file; the section's own markup draws it by loopingsection.blocksand readingblock.settings. Two local blocks of one type are an error; a local block needs a name. - A named theme block —
{ "type": "button" }, which refers toblocks/button.liquid. A name the theme has no file for is an error. - Any theme block —
{ "type": "@theme" }accepts every theme block except those whose file name starts with_.{ "type": "@app" }is reserved for extension blocks.
A theme block's own schema may declare blocks too — the same three kinds — so blocks nest (a buttons block holding button blocks). The stored tree nests to a depth of 6; a block placed where its parent does not accept it is refused (block.not-accepted), a block past its limit (block.limit) or its parent's max_blocks (block.max) is refused, and a block placed inside one that holds no blocks is refused (block.children).
A theme block renders its child blocks with {% content_for 'blocks' %} and writes {{ block.abizvo_attributes }} on its outermost element so the editor can select, move and hide it:
<{{ block.settings.tag | default: 'h2' }} class="{{ block.settings.scale }}" {{ block.abizvo_attributes }}>
{{- block.settings.text | editable: block, 'text' -}}
</{{ block.settings.tag | default: 'h2' }}>
{% schema %}
{
"name": "Heading",
"settings": [
{ "type": "text", "id": "text", "label": "Heading", "default": "Tell your story" },
{ "type": "select", "id": "tag", "label": "Heading level", "default": "h2", "info": "One H1 per page is best for search and screen readers.",
"options": [ { "value": "h1", "label": "H1" }, { "value": "h2", "label": "H2" }, { "value": "h3", "label": "H3" }, { "value": "p", "label": "Paragraph" } ] }
],
"presets": [ { "name": "Heading" } ]
}
{% endschema %}
A theme block's file name is its type. A block's schema also takes name, limit, tag, class, thumbnail and presets.
Static blocks
A section's markup may place a block itself: {% content_for 'block', type: 'heading', id: 'title' %}. The block is stored with static: true; the owner edits and hides it, never removes or moves it, and one the owner never edited renders with its type's defaults.
Presets
A preset is a ready-made configuration named in the picker: name (required), category, settings (values for the section's own settings) and blocks (a tree of { "type", "id", "static", "settings", "blocks" }). The check refuses a preset that sets a setting the section does not declare, sets one to an invalid value, or adds a block that cannot go there.
"presets": [
{
"name": "Split hero",
"category": "Content",
"settings": { "layout": "split", "min_height": 70 },
"blocks": [
{ "type": "heading", "settings": { "text": "Work worth talking about", "tag": "h1" } },
{ "type": "buttons", "blocks": [ { "type": "button", "settings": { "label": "Book a call", "link": "action:booking" } } ] }
]
}
]
visible_if
A setting can be shown only when another setting of the same owner has a value: "visible_if": { "setting": "layout", "equals": "overlay" }. The editor hides the control; the value is still stored and still normalized.
Dynamic sources
A textual setting — text, textarea, inline_richtext, richtext, image_picker, url — may be connected to a dynamic source instead of holding its own words, so one template serves many pages, each filling it from its own record. The stored value is { "$source": "site.name" }, and the setting may say "dynamic": false to forbid it (or true to allow it on another type). A source outside this list is refused:
| Source | Fills with |
|---|---|
site.name, site.tagline |
the site's name; the tagline is reserved and currently empty |
page.title, page.seo_title, page.seo_description, page.social_image |
the page's own title, search title, description and social picture |
business.name, business.phone, business.email, business.address, business.logo, business.hours |
the business's own facts; the address only when the owner chose to publish it. business.hours is declared and currently yields nothing |
gallery.name, gallery.description, gallery.cover, gallery.date |
the album a gallery page shows |
A picture source (page.social_image, gallery.cover, business.logo) yields { src, alt: "", focal_point: "50% 50%" }; a rich-text setting yields the words as a paragraph.
Reusable sections
A site owner can save a section's content and place it on several templates by reference. A placement with "reusable": "<id>" renders the saved section's current content and its own settings are ignored; the type must match, and a link to a saved section that is gone is dropped with a warning and the placement keeps its own content. A site keeps at most 50 reusable sections. Nothing in a theme declares this — every section can be saved.
Section groups
The header, footer, announcement, overlay and aside groups are section lists of their own, declared in sections/{group}-group.json and rendered by the layout with {% sections 'header' %}. A section may say where it belongs with enabled_on.groups / disabled_on.groups.
Limits
| Limit | Value |
|---|---|
| Sections per template | 100 |
| Blocks per template | 2,000 |
| Block depth | 6 |
Blocks per section (max_blocks) |
1–250 |
| Section, block and setting ids | letters, digits, hyphens, underscores; at most 64 characters |
| Names | at most 80 characters |