Templating

The pagelove:template attribute enables server-side Liquid rendering inside an HTML element. The template engine processes the element's subtree, replacing it with rendered output.

When to reach for it

Use templating to render dynamic content from bound data — lists, conditionals, formatted output. Templates operate over site-graph resources and the active HTTP request. They do not mutate documents or perform I/O.

Enabling templating

Attach pagelove:template to any element. The attribute value is the template engine MIME type.

<section pagelove:template="text/liquid">
    ...
</section>
Engine MIME type
Liquid text/liquid

Only the subtree rooted at the annotated element is processed. The rest of the document is unchanged.

Data sources

Templates access four categories of data:

Source Description
Resource bindings Site-wide CSS selector queries
Expression bindings Computed values using Sessel
request object The active HTTP request
Template-local variables Variables created with assign, capture, etc.

Template scope

Template execution is scoped to the annotated element, side-effect free, and deterministic.

Templates cannot:

Examples

Listing with resource binding

<ul pagelove:template="text/liquid"
    resource:users="[id][itemtype='http://example.com/TeamMember']">
    {% assign users = users | sort: 'fullname' %}
    {%- for user in users -%}
    <li>
        <a href="{{ user['@id'] }}">{{ user.fullname }}</a> ({{ user.email }})
    </li>
    {%- endfor -%}
</ul>

Processing steps:

  1. The selector evaluates across the site graph.
  2. Matching elements are materialized as resource objects.
  3. The Liquid engine renders the subtree.
  4. Rendered HTML replaces the original template subtree.

Request object

<section class="debug" pagelove:template="text/liquid">
<pre>{{ request | json: 2 }}</pre>
</section>

Includes and templates together

<pagelove:include selector="#site header"></pagelove:include>
<section pagelove:template="text/liquid">
    ...
</section>
<pagelove:include selector="#site footer"></pagelove:include>

<pagelove:include> handles structural composition (server-side DOM inclusion). pagelove:template handles data-driven rendering. They are often combined.

Worked example: listing people

Store two documents that describe people using HTML Microdata, then a listing page that uses a Liquid template with a resource binding to query all Person items:

When the listing page is requested, the template evaluates and the bound data renders:

GET /sspi-tpl-listing.html
HTTP/1.1 200

<!DOCTYPE html>
<html>
<body>
  <h1>People</h1>
  <ul>
    
    <li>Anna</li>
    
    <li>Ben</li>
    
  </ul>
</body>
</html>

The resource binding queried every Person across the site. The Liquid template rendered the list. All SSPI namespaces and binding attributes have been stripped from the output.

See also