User Docs Developer Docs | |

Syntax Overview

The Pubvana template engine defines four distinct syntax forms, each with its own delimiters and evaluation rules.

1. Escaped Output — {{ }}

{{ variable }}
{{ variable | filter }}
{{ variable | date "M d, Y" }}
{{ post.author.name }}

Evaluates the expression, applies any filters, then HTML-escapes the result before inserting into the output stream. Safe for all user-supplied content.

Dot notation resolves nested properties: post.author.name accesses $data['post']['author']['name'] (or the equivalent object chain).

2. Raw Output — {! !}

{! variable !}
{! tag_function "argument" !}
{! render_content post !}
{! csrf_field !}

Evaluates the expression or calls the tag function and inserts the result without HTML escaping. Use for:

  • Tag function calls that return URLs or HTML (post_url, widget_area, render_content, csrf_field)
  • Content that has already been sanitised (e.g. rendered post body HTML)
  • Variables you have explicitly marked safe with |raw in a prior step

Never use {! !} for unvalidated user input.

3. Control Tags — {% %}

{% extends "layout.tpl" %}
{% block content %}...{% endblock %}
{% include "partials/nav.tpl" %}
{% for post in posts %}...{% endfor %}
{% if condition %}...{% elif other %}...{% else %}...{% endif %}

Control tags do not produce output directly. They control template structure (inheritance, includes) and flow (loops, conditionals). Tag arguments are not quoted unless they are string literals.

4. Comments — {# #}

{# This is a comment and will not appear in rendered output #}

Comments are stripped at lex time. They are never emitted to the HTML output. Useful for annotating complex template logic.

Whitespace

The engine does not strip surrounding whitespace from tag lines. A {% for %} tag on its own line produces a blank line in the output. This is generally not visible in rendered HTML but matters for <pre> blocks.

Nesting Rules

  • {% for %} and {% if %} can be nested to any depth
  • {% block %} tags can only appear inside a template that uses {% extends %}, or in the layout file itself
  • {% extends %} must be the first tag in the file if used; mixing extends with inline content outside blocks is not supported
  • {% include %} resolves relative to the active theme's view directory, not the including template's directory

Literal Strings in Tags

Tag arguments that are string literals must be double-quoted:

{% extends "layout.tpl" %}
{% include "partials/footer.tpl" %}
{! site_url "blog/archive" !}
{! lang "Common.read_more" !}

Variable references in tags are unquoted:

{% for item in items %}
{! post_url post.slug !}
{! render_content post !}