Templates and sections
Templates
Each kind of page has a template. A JSON template lists the sections the page is made of, in order. The firm can add, remove, reorder and configure them in the theme editor.
| Template | Page | Page objects |
|---|---|---|
index |
The homepage's starting layout | page |
page |
A site page's starting layout | page |
page.{name} |
Alternative page layouts, e.g. page.contact, page.about |
page |
practice_areas |
The list of practice areas, at /practice-areas |
|
practice_area |
One practice area's page, at /practice-areas/{handle} |
practice_area |
blog |
The blog, at /blog, and its category and tag archives at /blog/category/{handle} and /blog/tag/{handle} |
blog |
article |
One article's page, at /blog/{handle} |
article |
intake |
The firm's intake form, at /intake, while the firm has it on |
|
404 |
Page not found | |
customers/login |
Sign in | |
customers/forgot_password |
Forgot password | |
customers/reset_password |
Reset password | reset_password |
customers/verify_email |
Verify email | |
customers/activate_account |
Accepting a client portal invitation: the client chooses a password | invitation |
Site pages
The firm creates its own pages under Pages (any number, each at its own address, /{slug}) and marks one as the homepage. Pages don't nest: dropdowns and grouping come from the menus the firm builds in Navigation. Each page picks one of your page templates: page, or any page.{name} your theme ships (the editor lists page.about as "About"). A missing page.{name} falls back to page.
Firms manage pages in the theme editor: they pick a page, switch its layout between your page templates, and change its sections. Once they change a page's sections, that page keeps its own layout (stored as pages/{id} on the theme, never in your package); switching layout again replaces it with the chosen template's sections.
The page's text is stored on the page, not in a layout, so it survives layout and theme changes. Show it with {{ page.content }} in a section whose schema has "page_content": true (Counsel's is main-page): selecting that section in the editor shows the text editor for the page. Put such a section in every page template.
{% schema %}
{ "name": "Page content", "page_content": true, "settings": [] }
{% endschema %}
{
"layout": "theme",
"sections": {
"hero": {
"type": "hero",
"settings": { "heading": "Clear advice when it matters most" },
"blocks": {
"cta": { "type": "button", "settings": { "label": "Book a consultation" } }
},
"block_order": ["cta"]
},
"faq": { "type": "faq", "settings": {}, "disabled": false }
},
"order": ["hero", "faq"]
}
layoutpickslayout/<name>.liquid(defaulttheme), orfalsefor no layout.typeis a file insections/. Section and block ids are yours: letters, digits,-and_, up to 64 characters.disabled: truekeeps a section configured but hidden.- A template can also be a
.liquidfile, which then isn't editable in the theme editor.
Practice areas
Firms publish their practice areas under Firm settings → Practice areas, and the platform serves /practice-areas with your practice_areas template and each area's page with practice_area. If you don't ship them, Counsel's are used. A site page the firm publishes at the same path takes its place. The practice_areas and team objects are available on every page, so any section can list them.
Blog
Firms on a plan with the blog write articles under Website → Blog. The platform serves /blog and the category and tag archives with your blog template (check blog.category and blog.tag to title an archive) and each article with article. Archives show 12 articles a page: link blog.pagination.previous_url and next_url. If you don't ship the templates, Counsel's are used. A site page the firm publishes at /blog takes the blog's first page's place; articles and archives always come from the blog. The blog object is available on every page, so a home page section can show blog.latest_articles or blog.featured_articles.
The client portal's account pages are rendered by the platform. They're shown inside layout/member.liquid (or theme.liquid if you don't ship one), with your header and footer around them.
There is no public sign-up: clients join by invitation, on your customers/activate_account page. Any customers/* template you don't ship falls back to Counsel's.
Give a signed-in customer a way to sign out from your header (see the customer example). Don't hide it behind a setting: the bundled themes always show it, and their "Show sign in link" setting only controls the link guests see.
Section groups
sections/header-group.json and sections/footer-group.json are the header and footer, shared by every page. Render them in your layout:
{% sections 'header-group' %}
<main id="main-content">{{ content_for_layout }}</main>
{% sections 'footer-group' %}
They use the same format as templates, plus "type": "header" or "type": "footer" and a name.
Sections
A section is a Liquid file in sections/ with a {% schema %}:
<div class="page-width section-y">
<h2 class="h2">{{ section.settings.heading | escape }}</h2>
<div class="grid gap-6 md:grid-cols-3">
{%- for block in section.blocks -%}
<div {{ block.theme_attributes }}>
<h3>{{ block.settings.title | escape }}</h3>
<div class="rte">{{ block.settings.text }}</div>
</div>
{%- endfor -%}
</div>
</div>
{% schema %}
{
"name": "Features",
"tag": "section",
"class": "section",
"settings": [
{ "type": "text", "id": "heading", "label": "Heading", "default": "Why learn with us" }
],
"blocks": [
{
"type": "feature",
"name": "Feature",
"settings": [
{ "type": "text", "id": "title", "label": "Title", "default": "Live classes" },
{ "type": "richtext", "id": "text", "label": "Text" }
]
}
],
"max_blocks": 6,
"presets": [
{ "name": "Features", "blocks": [{ "type": "feature" }, { "type": "feature" }, { "type": "feature" }] }
],
"enabled_on": { "templates": ["index", "page.contact"] }
}
{% endschema %}
| Schema key | Meaning |
|---|---|
name |
Shown in the theme editor. |
tag |
The wrapper element: section, div (default), header, footer, aside, nav, main or article. |
class |
Classes on the wrapper. The wrapper also gets id="theme-section-…", data-section-type and, when the firm animates the section, data-animate or data-animate-stagger. |
settings |
The section's settings (see Settings). |
blocks |
Block types: type, name, settings, and optionally limit (how many of that type). |
max_blocks |
How many blocks in total (up to 50). |
presets |
Makes the section available under Add section, with starting settings and blocks. Without a preset, a section can only be placed by a template file. |
enabled_on / disabled_on |
Limit where the section can be added: { "templates": [...], "groups": ["header", "footer"] }. |
animations |
false to leave out the platform's animation settings for this section and its blocks (see Platform settings). A block's schema can also say "animations": false. Defaults to true. |
Output {{ block.theme_attributes }} on each block's outermost element. The theme editor uses it to highlight and select blocks, and it carries the block's animation (data-animate="…"), so a block without it can't animate.
For repeated items that aren't blocks, such as the cards of a list, put data-animate-item on each item's outer element. When the firm turns on Stagger blocks, those items are revealed one after another too. See Motion and animations.
{% section 'name' %} renders a section with its schema defaults, outside any template. It isn't editable.
Snippets
{% render 'card', title: block.settings.title, compact: true %} renders snippets/card.liquid. A snippet only sees the variables you pass it, plus the global objects.
Still need help?
Send a request to the Mattersimple team and we'll reply by email.