Liquid
Variables, filters, if, and for.
Templates use Liquid to fill in per-message values. This page covers the tags and filters you need most, and what Liquid will not do in PostShiba.
Where Liquid runs
Liquid works in the subject, HTML, text, and CSS of a template. From and Reply-To are plain text.
Values come from template.variables on the send. In the dashboard, the Variables tab uses the same JSON shape for the preview and test sends.
Variables
greeting.html
1<p>Hi {{ name }},</p>
2<p>{{ body | default: "Thanks for signing up." }}</p>
variables.json
1{
2 "name": "Ada",
3 "body": "Your account is ready."
4}
nested.html
1<p>{{ user.name }}</p>
nested.json
1{
2 "user": {"name": "Ada"}
3}
Escaping
Liquid does not escape HTML for you. {{ name }} is inserted exactly as sent. Escape untrusted values in your app, or use | escape. Pass a value that is already HTML when you want markup in the body.
Filters
Common Liquid filters.
| Filter | Example |
|---|---|
default |
{{ name | default: "there" }} |
upcase, downcase, capitalize |
{{ name | upcase }} |
escape |
{{ name | escape }} |
date |
{{ created_at | date: "%b %-d, %Y" }} |
truncate |
{{ body | truncate: 80 }} |
join |
{{ tags | join: ", " }} |
An unknown filter is an error, not a silent no-op.
Conditions
conditions.html
1{% if action_url %}
2 <p><a href="{{ action_url }}">Continue</a></p>
3{% endif %}
4
5{% unless items %}
6 <p>No items.</p>
7{% endunless %}
list.html
1{% for item in items %}
2 <p>{{ item.name }}, {{ item.price }}</p>
3{% endfor %}
items.json
1{
2 "items": [
3 {"name": "Vintage Macintosh", "price": "499"},
4 {"name": "Keyboard", "price": "79"}
5 ]
6}
comments.html
1{% comment %}Not sent.{% endcomment %}
2{% raw %}{{ this stays literal }}{% endraw %}