Page Rendering with Templates

Describes how .twig template files are used with .json files to render page content.

The rendered content of a page is produced by combining requested site data with .twig page template files. A page can be made up of a page template (which optionally extends a layout template), include-based partial templates (for code reuse), and enriched reusable section templates: pages, layouts, partials, and sections.

Page templates and section templates are core elements of the page rendering flow. In addition to template markup, they include a custom schema tag that exactly describes the expected payload for the page. For example, the following template is used for a page that expects an item named some_item and a category named large_category to be provided:

{% schema %}
{
    "some_item": {
       "type": "item"
    },
    "large_category": {
       "type": "category"
    }
}
{% endschema %}

Sections and section containers

Sections are enriched partial templates that are isolated from the pages that they’re rendered on. This isolation enables developers to create reusable modules of content that are stored outside of a page template’s code. Sections encapsulate their data by defining their own schemas.

In addition to sections, Square Online pages support section containers. A section container allows developers to dedicate an area of a given page in which a seller can add, remove, and reorder any number of sections. This enables developers to build generic pages that stylistically match the rest of a site while allowing sellers to entirely customize the content in the Square Online dashboard. An example page with a section container might look like this:

{% extends "layouts/theme" %}

{% block main_content %}
<div class="flex flex-col">
        {{ section_container(main, 'main') }}
</div>
{% endblock %}

{% schema %}
{
       "main": {
              "type": "section-list"
       }
}
{% endschema %}

In this example, the schema informs the rendering engine that a section-list is required and provides the list to the section_container function call. When this page is edited, the contents of the page JSON is stored and would look something like this:

{
    "main": [
        {
            "template": "featured-items",
            "props": {
                "items": {
                    "filters": {
                        "ids": ["18", "8", "11", "12", "13", "14"]
                    }
                }
            }
        },
        {
            "template": "text-and-image",
            "props": {
                "layout": "row",
                "image": {
                    "src": "https://some-image.source"
                },
                "imageSize": "large",
                "headline": "Gear for any way <br>you get the job done.",
                "subheading": "9 to whenever. At home or wherever.",
            }
        }
    ]
}

The rendering engine processes each section in the main array by looking up the provided section (identified by the template key) and passing the stored props into their section and rendering. The template path is relative to theme/components/sections, for example "template": "text-and-image" will reference theme/components/sections/text-and-image.html.twig.

Global sections and containers

Sections and containers can also be global elements whose state is saved at the site level instead of the page level. Any section or container can be defined and used as global, and then its state is automatically loaded anywhere that global section or container is referenced in a template. This allows for shared sections and containers across a site that don’t require duplication of data.

An example of a global section is a site header. A site header that appears the same across all pages would use a global section, and if an edit is made to the header’s data on any page, the change is reflected on all pages. The state of global sections or containers can be edited using a .json file interface in the site/global directory.

A theme defines its global sections and containers in its global config file, where it specifies the name and the template that is used. The example below illustrates that, unlike when pages use sections or containers and require them to be defined in the page template, a global section can be used only by calling the global section function with the section name.

Global section example

site/global/sections/header.json
{
    "props": {
        "title": "Example Header"
    }
}
theme/config/global.json
{
    "sections": {
        "header": {
            "template": "header"
        }
    }
}
theme/components/sections/header.html.twig
<h1> {{ title }} </h1>

{% schema %}
{
    "title": {
        "type": "string"
    }
}
{% endschema %}
theme/templates/pages/first-page.html.twig
{{ global_section('header') }}
<p> This is the first page template. </p>
theme/templates/pages/second-page.html.twig
{{ global_section('header') }}
<p> This is a second page template. </p>

Global container example

site/global/section_containers/footer.json
[
    {
        "props": {
            "social": {
                "type": "external",
                "href": "https://www.example.com/mysocial"
            }
        },
        "template": "socials"
    },
    {
        "props": {
            "year": "2023"
        },
        "template": "copyright"
    }
]
theme/config/global.json
{
    "section_containers": {
        "footer": {}
    }
}
theme/components/sections/socials.html.twig
<p><a href="{{ link(social) }}">Check us out</a></p>

{% schema %}
{
    "social": {
        "type": "link"
    }
}
{% endschema %}
theme/components/sections/copyright.html.twig
<p>Copyright {{ year }}</p>

{% schema %}
{
    "year": {
        "type": "string"
    }
}
{% endschema %}
theme/templates/pages/first-page.html.twig
<p> This is a first page template. </p>

<footer>
    {{ global_section_container('footer') }}
</footer>
theme/templates/pages/second-page.html.twig
<p> This is a second page template. </p>

<footer>
    {{ global_section_container('footer') }}
</footer>

Custom page routing and rendering

There are two ways a defined template can be rendered on a Square Online site. The first way is through explicitly defined custom pages. A custom page can be customized and edited in the Square Online code editor and is represented by a .json file in the sites/pages directory.

site/pages/home.json

{
    "template": "templates/pages/lightning-item",
    "route": "/lightning-item/:item_id",
    "props": {
        "item": {
            "filter": {
                "id": "request_data(path.item_id)"
            }
        },
        "title": "An Item Page"
    }
}

theme/pages/lightning-item.html.twig

<h1> {{ title }} </h1>

<p> {{item.name}} </p>
<p> {{item.price.amount}} </p>
{% schema %}
{
    "item": {
        "type": "item"
    },
    "title": {
        "type": "string"
    }
}
{% endschema %}

To see a resource in JSON format, append .json to the URL.

System Page routing and rendering

The other way a template can be rendered on a Square Online site is with System Pages. A System Page represents a type of page that all Square Online sites can support and are typically served from the same URI path on every Square Online site, some examples include a product display page, category page, shop all page, and stories page. These pages are served from a predefined route and have a predetermined schema of data that is available to the template. For example, the product display page will have a route of /product/{product-name}/{product-id} and the template will receive the item that corresponds to the identifiers in the route.

See System Pages for more details.

Render Mode Flag

Overview

A render_mode flag to the template parameters to signify the rendering context of the page. This flag can have one of the following values:

  • editor: When the site is being rendered in the Square Online design editor.
  • preview: When the site is rendered in Square Online code editor preview.
  • dashboard: When the site is rendered in Square dashboard
  • published: When the site is on the published site.

The render_mode flag enhances the flexibility of our template rendering process by providing clear context about the rendering environment. This allows developers to create more dynamic and responsive templates that adapt to different usage scenarios.

We strongly advise hiding popup UI such as alerts or modals when the render_mode is editor and dashboard to enhance seller experience while previewing your theme in various use-cases.

Example Usage

Here is a basic example of how the render_mode flag can be used in a template:

theme/templates/pages/home.html.twig
<div class="home-page">
    {% if square.render_mode == 'editor' %}
        <p>This content is visible only in the Square Online editor.</p>
    {% elseif square.render_mode == 'preview' %}
        <p>This content is visible only in a site preview.</p>
    {% elseif square.render_mode == 'dashboard' %}
        <p>This content is visible on the Square Dashboard.</p>
    {% endif %}
    {% elseif square.render_mode == 'published' %}
        <p>This content is visible on the published site.</p>
    {% endif %}
</div>