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:
- Mutate documents
- Create resources
- Perform I/O
- Issue HTTP requests
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:
- The selector evaluates across the site graph.
- Matching elements are materialized as resource objects.
- The Liquid engine renders the subtree.
- 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
- Template Filters — hashing, random generation, date arithmetic, and data conversion filters
- Resource Binding — bind site-wide CSS selector queries to variables
- Expression Binding — computed values using Sessel expressions