Basker Docs

Templates

Build per-collection page templates that decide how pages, events, posts, and other records render

A template controls how a specific content type renders — how a page lays out, how an event presents its date and venue, how a post displays its author and body. Templates live in templates/ as either base templates like page.liquid or named alternates like page.landing.liquid.

For per-collection field references (the data shape of a page, event, post, etc.), see Template references.

Prerequisites

Steps

1. Create a template file

Templates use the .liquid extension and follow a strict naming convention:

templates/[collection].liquid
templates/[collection].[name].liquid

The collection is the segment before the first dot. The name is the second segment. If only one segment is provided, the name defaults to default.

FilenameCollectionName
templates/page.liquidpagedefault runtime template
templates/page.landing.liquidpagelanding alternate
templates/event.featured.liquideventfeatured alternate
templates/blog.liquidblogdefault
templates/post.archive.liquidpostarchive
templates/person.liquidpersondefault

The filename — not the schema — sets the collection and the variant name. During upload, each template's collection and name are read straight from the filename and recorded in the theme. Editors then choose between the named variants (landing, featured, archive, and so on) when assigning a template to a record. Give files clear variant names, since that name is what editors see.

2. Write the template markup

Templates are HTML mixed with Liquid output tags and control flow. The current document is exposed as the variable matching the collection name. For a page template, use page:

<article class="page">
  <header class="page__header">
    <h1>{{ page.title }}</h1>
    {% if page.description %}
      <p class="page__description">{{ page.description }}</p>
    {% endif %}
  </header>

  {% if page.image %}
    <figure class="page__hero">
      <img
        src="{{ page.image | image_url: width: 1200 }}"
        alt="{{ page.image.alt }}"
        width="{{ page.image.width }}"
        height="{{ page.image.height }}"
      >
    </figure>
  {% endif %}

  <div class="page__body">
    {% stageblocks page %}
  </div>
</article>

Use {% render 'snippet-name' %} to include partials from snippets/.

{% render 'breadcrumbs', page: page %}
{% render 'social-sharing', title: page.title, url: request().url %}

The {% include %} tag is deprecated. Use {% render %} instead.

3. Add a schema definition

Every template should include a {% schema %} tag with a JSON object. The schema defines settings (editable fields editors fill in per page) and blocks (which block types are allowed on this template).

Place the schema at the end of the file:

{% schema %}
{
  "settings": [
    {
      "type": "checkbox",
      "name": "show_breadcrumbs",
      "label": "Show breadcrumbs",
      "defaultValue": true
    },
    {
      "type": "select",
      "name": "header_style",
      "label": "Header style",
      "options": [
        { "label": "Standard", "value": "standard" },
        { "label": "Hero", "value": "hero" },
        { "label": "Minimal", "value": "minimal" }
      ],
      "defaultValue": "standard"
    }
  ],
  "blocks": [
    "text-section",
    "image-gallery",
    "call-to-action",
    "featured-events"
  ]
}
{% endschema %}

The settings array defines fields that appear in the editor. Each field requires type, name, and label; required and defaultValue are optional.

The blocks array lists allowed block types — strings matching the name property in each block's schema. Object form is also accepted:

"blocks": [
  "text-section",
  { "name": "image-gallery" },
  { "type": "call-to-action" }
]

4. Access template settings in markup

Template settings are available on the document via page.theme.settings:

{% assign show_breadcrumbs = page.theme.settings.show_breadcrumbs %}
{% if show_breadcrumbs %}
  {% render 'breadcrumbs', page: page %}
{% endif %}

{% assign header_style = page.theme.settings.header_style %}
<header class="page__header page__header--{{ header_style }}">
  <h1>{{ page.title }}</h1>
</header>

Complete example

A full event.featured.liquid template for an arts venue:

{% assign show_series = event.series != blank %}

<article class="event event--featured">
  <header class="event__header">
    {% if event.image %}
      <div class="event__hero">
        <img
          src="{{ event.image | image_url: width: 1600, height: 900, fit: 'cover' }}"
          alt="{{ event.image.alt | default: event.title }}"
          loading="eager"
        >
      </div>
    {% endif %}

    <div class="event__header-content">
      {% if show_series %}
        <a href="/series/{{ event.series.slug }}" class="event__series-link">
          {{ event.series.title }}
        </a>
      {% endif %}

      <h1 class="event__title">{{ event.title }}</h1>

      {% if event.subtitle %}
        <p class="event__subtitle">{{ event.subtitle }}</p>
      {% endif %}

      {% if event.venue %}
        <p class="event__venue">
          <a href="/venues/{{ event.venue.slug }}">{{ event.venue.title }}</a>
        </p>
      {% endif %}
    </div>
  </header>

  <div class="event__body">
    {% if event.description_html %}
      <div class="event__description rich-text">
        {{ event.description_html }}
      </div>
    {% endif %}

    {% stageblocks event %}
  </div>

  {% render 'event-sidebar', event: event %}
</article>

{% schema %}
{
  "settings": [
    {
      "type": "checkbox",
      "name": "show_related_events",
      "label": "Show related events",
      "defaultValue": true
    },
    {
      "type": "number",
      "name": "related_events_count",
      "label": "Number of related events to display",
      "defaultValue": 4
    }
  ],
  "blocks": [
    "text-section",
    "image-gallery",
    "video-embed",
    "pull-quote",
    "performer-list",
    "booking-widget"
  ]
}
{% endschema %}

This template renders when an editor assigns the featured template to an event in the admin.

Troubleshooting

"Template filename is not in the expected format" — The file must be a base template such as page.liquid or a named alternate such as page.landing.liquid. Ensure the filename has a collection segment and the .liquid extension.

"Invalid template schema JSON" — JSON syntax error inside {% schema %}. Validate it with a JSON linter. Common: trailing commas, unquoted keys, single quotes.

"Template references missing block" — A block name in the blocks array doesn't match any file in blocks/. Verify the block's name in its schema matches the string.

Rich text fields render as true instead of HTML — Rich text fields are split into two properties. Use field_name_html for the HTML; the plain field_name is a boolean.

On this page