Resource Binding
A resource binding declares a site-wide CSS selector query and exposes the matching elements as a named variable for use by templates, constraints, triggers, and other server-side processors.
When to reach for it
Use resource bindings to pull data from across the site graph into a single document. Templates render the bound elements, constraints validate invariants against them, and triggers access context through them.
Namespace declaration
Declare the Pagelove Resource namespace on any element:
<html xmlns:r="https://pagelove.org/Binding/CSS">
The prefix can be any valid XML prefix (r, resource, etc.). Server-side processing must also be enabled by declaring the https://pagelove.org/1.0 namespace:
<html xmlns:p="https://pagelove.org/1.0"
xmlns:r="https://pagelove.org/Binding/CSS">
Attribute form
Add a namespaced attribute to any element. The attribute name is the variable name. The attribute value is a CSS selector evaluated across the entire site graph.
r:<name>="<css-selector>"
The result is a collection of matching elements.
Semantics
| Property | Behaviour |
|---|---|
| Scope | Site-wide — selectors operate across all documents |
| Result type | HTML elements, not deserialized records |
| Evaluation | At processing time, not cached |
| Mutability | Read-only — mutation is performed via HTTP methods |
Binding placement
Bindings may appear on any element. The declaring element determines scope:
- For templates, the template processor defines which bindings are visible.
- For constraints, bindings on the constraint element or its ancestors are available.
- For triggers, bindings on the trigger element or its ancestors are available.
Multiple bindings may appear on the same element.
Examples
Template rendering
The following document binds all schema.org/Person items to a variable named contacts and renders them with a Liquid template:
<!doctype html>
<html lang="en"
xmlns:r="https://pagelove.org/Binding/CSS"
xmlns:p="https://pagelove.org/1.0">
<head>
<title>Contacts List</title>
</head>
<body r:contacts="[itemtype='http://schema.org/Person']"
p:template="text/liquid">
<ul>
{% for contact in contacts %}
<li>{{ contact.name }}</li>
{% endfor %}
</ul>
</body>
</html>
The selector [itemtype='http://schema.org/Person'] evaluates across all documents. Matching elements bind to contacts. The template iterates over contacts to render the list.
Graph constraint
Resource bindings supply the variables that constraint expressions operate on:
<body xmlns:r="https://pagelove.org/Binding/CSS"
r:users="[itemtype*=User]"
r:admins="[itemtype*=User]:has([itemprop=role]:value-equals('admin'))">
<div itemscope itemtype="https://pagelove.org/Constraint">
<code itemprop="constraint">size(admins) >= 1</code>
<span itemprop="message">At least one admin user must exist</span>
</div>
</body>
Trigger context
Triggers use resource bindings to access data for transformations:
<div xmlns:r="https://pagelove.org/Binding/CSS"
r:auth="[itemtype*=Request] [itemprop=auth]"
r:apiKey="[itemprop=webhook-api-key]"
itemscope
itemtype="https://pagelove.org/Trigger">
<meta itemprop="selector" content="[itemtype*=Order]">
<meta itemprop="method" content="PUT">
<code itemprop="transformation">
{
headers: {
'Authorization': 'Bearer ' + apiKey
},
body: {
purchaser: auth.claims.email
}
}
</code>
<div itemprop="action" itemscope itemtype="https://pagelove.org/HTTPRequest">
<meta itemprop="url" content="https://api.example.com/orders">
</div>
</div>
The transformation expression accesses auth and apiKey bindings directly by name.
Note — binding the Request Document.
r:auth="[itemtype*=Request] …"sources data from the Request Document, a transient, selector-addressable document representing the current request. The binding resolves during page composition, and any page that reads a request-document fragment is servedCache-Control: private. If you only need a field (not a selector-addressable fragment), the request object is also available directly in expression bindings and Liquid templates —request.auth.claims.*/request.auth.username(see Sessel syntax → Authenticated identity in composition).
Security
Resource bindings are evaluated server-side during composition and query the entire site graph without per-request authorization. A binding reads matching elements from every document on the host, regardless of whether the current request would be authorized to fetch those documents directly. Authorization rules govern which requests may reach which paths — they do not restrict what a resource binding may read.
The trust boundary is therefore who may author a composed page: because a page's bindings can surface any content stored on the host, treat authorship of a composed page as equivalent to read access over the whole host. Do not use a resource binding to pull data onto a page whose authors should not be able to see that data.
Error cases
| Condition | Result |
|---|---|
| Invalid CSS selector | Request fails during document processing |
| Selector matches no elements | Empty collection (not an error) |
| Selector matches elements in other documents | All matching elements are returned — bindings are not filtered by per-request authorization (see Security) |
See also
- Expression Binding — computed values using Sessel or JavaScript expressions
- Templating — render bound data in Liquid templates
- Selector Extensions — extended pseudo-classes available in binding selectors
- Method Elements — the general attribute-form dispatch mechanism
r:attributes use under the hood