News Learn Download
Overview News Manual

Pongo2 Tutorial

Note: in Sprouts, Pongo2 is being deprecated in favor of Scriggo!

Files ending in .tmpl or .pgo2 are interpreted as Pongo2 templates.

The basic idea is very similar to Django or Jinja templates, but not all Jinja's features are supported.

I'm not aware of a complete reference documentation for Pongo2, but if you are familiar with Django/Jinja templates, you can pick it up quite easily.

I will try to give a basic rundown of the most common/useful features.

To start, you can treat template files as regular html files with some special additional syntax.

Expressions are enclosed by {{ ... }} double curlies, while special constructs are indicated with {% ... %}

Let's go over some useful constructs one by one.

Includes

The include directive will include the content of one file into another file

{% include "snippet.html" %}

The path specified is relative to the current template file being executed.

Filters

Like Django and Jinja, you can pass strings to filter functions with the pipe operator:

{{ "hello world"|title }}

Will produce:

Hello World

You can also use the filter tag:

{% filter title %}hello world{% endfilter %}

The following is a list of builtin filter names that ship with Pongo2:

escape
e       // alias of `escape`
safe
escapejs

add
addslashes
capfirst
center
cut
date
default
default_if_none
divisibleby
first
floatformat
get_digit
iriencode
join
last
length
length_is
linebreaks
linebreaksbr
linenumbers
ljust
lower
make_list
phone2numeric
pluralize
random
removetags
rjust
slice
split
stringformat
striptags
time        // time uses filterDate (same golang-format)
title
truncatechars
truncatechars_html
truncatewords
truncatewords_html
upper
urlencode
urlize
urlizetrunc
wordcount
wordwrap
yesno

float       // pongo-specific
integer     // pongo-specific

You can use Django's filter documentation for reference on what these filters do.

Markup languages

Sprouts adds a few more filters that can be used with the filter tag to write blocks of text in a markup language.

Text in these blocks can be indented and the indentation will be stripped before processing the text.

{% filter markdown %}
    # Introduction

    This is an example markdown block. Text here will be processed as markdown.

    ```go
    func Hello() {
        // this is a code block
    }
    ```
{% endfilter %}

You can mix and match blocks by using multiple filters in sequence

{% filter markdown %}
    Some markdown text
{% endfilter %}

{% filter d2 %}
    a -> b
{% endfilter %}

Macros

When you have a repeated html pattern, you can capture it in a macro.

Let's say that you want to list out your most important essays:

<div class="essay card">
    <a href="/essays/scrum">
        <h2>📊 Why Scrum doesn't work, and what to do instead</h2>
    </a>
    <a href="/essays/scrum">
        <h3>How to manage software projects</h3>
    </a>
</div>

<div class="essay card">
    <a href="/essays/manifesto">
        <h2>📜 The Straight Forward Programming Manifesto</h2>
    </a>
    <a href="/essays/manifesto">
        <h3>It&#39;s all about the data!</h3>
    </a>
</div>


<div class="essay card">
    <a href="/essays/fake-problems">
        <h2>🚀 The Tyranny of the Fake Problems Equation</h2>
    </a>
    <a href="/essays/fake-problems">
        <h3>The more solutions you have, the more solutions you need!</h3>
    </a>
</div>

All essay elements have the same basic structure, so we can define a macro like this:

{% macro essay_card(url, title, subtitle) %}
<div class="essay card">
    <a href="{{ url }}">
        <h2>{{ title }}</h2>
    </a>
    <a href="{{ url }}">
        <h3>{{ subtitle }}</h3>
    </a>
</div>
{% endmacro %}

And use it by invoking it like this:

{{ essay_card("/essays/scrum", "📊 Why Scrum doesn't work, and what to do instead", "How to manage software projects") }}
{{ essay_card("/essays/manifesto", "📜 The Straight Forward Programming Manifesto", "It's all about the data!") }}
{{ essay_card("/essays/fake-problems", "🚀 The Tyranny of the Fake Problems Equation", "The more solutions you have, the more solutions you need!") }}

The basic structure to define a macro is:

{% macro macro_name(params) %}
    body
{% endmacro %}

Inside the macro body, you can refernce passed parameters using the double curly braces.

To use a macro, you "call" it inside an expressed surrounded with curly braces:

{{ macro_name(params) }}

One limitation of the macro system in Pongo is the lack of caller() expression found in Jinja, meaning you cannot define a macro to wrap a "body" of text; only parameters are supported.

Shared layouts with extends and block

A template file can be used as a "skeleton" with "holes" to be filled in by other templates that "extend" it.

In the base (layout) template, you declare named blocks with some default content.

To create a template using the base template, you extend it and fill in the blocks with custom content.

Very basic example of a _base.tmpl file:

<html>
    <head>
        <title>{% block title %}Default Title{% endblock %}</title>
    </head>
    <body>
        {% block content %}
        {% endblock %}
    </body>
</html>

In the same directory you can create, for example, 'about.tmpl':

{% extends "_base.tmpl" %}
{% block title %}About Us{% endblock %}
{% macro Content %}
    <insert content here>
{% endblock %}

Note: by starting the filename with an underscore, it becomes "private": sprouts will not serve it if someone requests the url to it.