Layout, sections and blocks
The layout around every page, the sections merchants arrange, and the blocks inside them.
The layout
Section titled “The layout”layout/theme.liqx is the HTML around every page. Four calls put the page together:
<template><!doctype html><html lang={shop.locale} dir={shop.direction}> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{product ? `${product.title} — ${shop.name}` : shop.name}</title> {'base.css' | asset_url | stylesheet_tag} </head> <body class={`template-${template}`}> {sections('header-group')} {section('header')}
<main id="main"> {content_for_layout} </main>
{section('footer')} {appEmbeds()} </body></html></template>| Call | Prints |
|---|---|
{content_for_layout} |
The page’s template: its sections, in order |
{section('header')} |
One section, placed by the layout itself. The merchant edits its settings but can’t move or remove it |
{sections('header-group')} |
A section group from sections/header-group.json: sections the merchant can add, reorder and remove in that area |
{appEmbeds()} |
Snippets from installed apps that the merchant switched on, such as a custom code embed. Put it just before </body> |
A section group file:
{ "name": "Above the header", "sections": { "announcement": { "type": "announcement-bar", "settings": { "content": "Cash on delivery everywhere" } } }, "order": ["announcement"]}Sections
Section titled “Sections”A section is a file in sections/: a template plus a <schema> that declares its settings.
---const { settings } = section;---<template><section class="featured"> <If condition={settings.heading !== ''}> <h2>{settings.heading}</h2> </If> <div class="grid"> {products.slice(0, settings.limit).map(item => <ProductCard product={item} />)} </div></section></template><schema>{ "name": "Products", "tag": "div", "enabled_on": ["index"], "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Our products" }, { "type": "range", "id": "limit", "label": "Products", "min": 4, "max": 20, "step": 1, "default": 8 } ], "presets": [ { "name": "Products" } ]}</schema>Inside a section, section.settings holds its values, section.id its id and section.blocks its blocks.
Schema keys
Section titled “Schema keys”| Key | Means |
|---|---|
name |
The name merchants see in the editor |
settings |
The section’s settings. See Settings |
blocks |
Which blocks it accepts (see below) |
max_blocks |
The most blocks a merchant can add |
presets |
Ready-made versions offered in “Add section”, each with a name, and optional settings and blocks |
enabled_on |
The templates it may be added to, e.g. ["index", "product"] |
enabled_in_groups |
The section groups it may be added to |
tag |
The element Sworen wraps the section in (section by default). "none" means no wrapper. It must be an element name: null or "" is refused |
class |
An extra class on that wrapper |
Sworen adds the attributes the theme editor needs to the wrapper itself, so a merchant can click any section in the preview.
Blocks
Section titled “Blocks”Blocks are the pieces a merchant adds inside a section: a question in a FAQ, a heading, an image. There are two kinds.
Blocks declared in the section
Section titled “Blocks declared in the section”Declare them in the section’s own schema and loop over section.blocks. Put {block.lithos_attributes} on each block’s root element so the editor can select it:
<div class="faq"> {section.blocks.map(block => ( <details {block.lithos_attributes}> <summary>{block.settings.question}</summary> <div>{block.settings.answer}</div> </details> ))}</div>"blocks": [ { "type": "question", "name": "Question", "settings": [ { "type": "text", "id": "question", "label": "Question" }, { "type": "richtext", "id": "answer", "label": "Answer" } ] }]Theme blocks
Section titled “Theme blocks”A file in blocks/ is a block any section can accept. It has its own template and schema, and reads block.settings:
---const level = block.settings.level || 'h2';---<template><Switch value={level}> <Match when="h1"><h1>{block.settings.text}</h1></Match> <Default><h2>{block.settings.text}</h2></Default></Switch></template><schema>{ "name": "Heading", "settings": [ { "type": "text", "id": "text", "label": "Text", "default": "Heading" }, { "type": "select", "id": "level", "label": "Level", "default": "h2", "options": [ { "value": "h1", "label": "H1" }, { "value": "h2", "label": "H2" } ] } ]}</schema>A section (or a block) accepts theme blocks with { "type": "@theme" } for all of them, or by naming them, and prints them with {contentFor('blocks')}:
"blocks": [ { "type": "@theme" }, { "type": "_divider" } ]<div class="page-content">{contentFor('blocks')}</div>- A block file whose name starts with
_(blocks/_divider.liqx) is private:@themedoesn’t include it, so a section has to name it. - Blocks can contain blocks: a block’s schema can accept blocks too, and prints them with
contentFor('blocks'). - Sworen wraps each block in a
div(change it withtag). With"tag": "none", there is no wrapper and the editor attributes go on the block’s first element, which must then contain the whole block."tag": nullis refused.
