Use Templates

Access variables and objects in Jinja2 templates

4 min read 756 words

Bengal uses Jinja2 as its template engine. This guide explains what data is available in templates and how to access site and page data.

The Template Context

Every template in Bengal receives three primary objects:

  1. page: The current page being rendered.
  2. site: Global site information and collections.
  3. config: The full configuration dictionary.

1. ThepageObject

Thepageobject represents the current markdown file being rendered. It gives you access to content and frontmatter.

Attribute Description Example
page.title The page title. {{ page.title }}
page.content The raw content (rarely used directly). {{ page.content }}
page.metadata Dictionary of all frontmatter variables. {{ page.metadata.tags }}
page.rendered_html The compiled HTML of the content. {{ page.rendered_html }}
page.toc Auto-generated Table of Contents (HTML). {{ page.toc }}
page.date Pythondatetimeobject. {{ page.date.strftime('%Y-%m-%d') }}
page.url URL with baseurl applied (for display). {{ page.url }}
page.relative_url Relative URL without baseurl (for comparisons). {{ page.relative_url }}
page.permalink Alias forurl(backward compatibility). {{ page.permalink }}

Accessing Custom Frontmatter

Any custom key you add to your YAML frontmatter is available inpage.metadata:

1
2
3
4
5
---
title: My Page
author: "Alice"
banner_image: "images/banner.jpg"
---
1
2
<div class="author">By {{ page.metadata.author }}</div>
<img src="{{ page.metadata.banner_image }}" />

2. ThesiteObject

Thesiteobject provides access to your entire website's content and structure.

Attribute Description
site.pages List of all pages (includes sections and special pages).
site.regular_pages List of standard content pages (excludes generated lists).
site.sections List of top-level sections.
site.taxonomies Dictionary of tags and categories.
site.data Data loaded from thedata/directory.
site.menu Navigation menus defined in config.

Iterating Pages

To list all blog posts:

1
2
3
4
5
6
7
<ul>
{% for p in site.regular_pages %}
    {% if p.metadata.type == "post" %}
        <li><a href="{{ p.url }}">{{ p.title }}</a></li>
    {% endif %}
{% endfor %}
</ul>

URL Pattern Best Practices

Bengal provides three URL properties with clear purposes:

page.url - Primary property for display

  • Automatically includes baseurl (e.g.,/bengal/docs/page/)
  • Use in<a href>,<link>,<img src>attributes
  • Works correctly for all deployment scenarios (GitHub Pages, Netlify, S3, file://, etc.)

page.relative_url - For comparisons and logic

  • Relative URL without baseurl (e.g.,/docs/page/)
  • Use for comparisons:{% if page.relative_url == '/docs/' %}
  • Use for menu activation, filtering, and conditional logic

page.permalink - Backward compatibility

  • Alias forurl(same value)
  • Maintained for compatibility with existing themes

Example: Usage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{# Display URL (includes baseurl) #}
<a href="{{ page.url }}">{{ page.title }}</a>

{# Comparison (without baseurl) #}
{% if page.relative_url == '/docs/' %}
  <span class="active">Current Section</span>
{% endif %}

{# Both work the same #}
<a href="{{ page.url }}">Link 1</a>
<a href="{{ page.permalink }}">Link 2</a>  {# Same as page.url #}

Why This Pattern?

  • Ergonomic: Templates use{{ page.url }}for display - it "just works"
  • Clear:relative_urlmakes comparisons explicit
  • No wrappers: Page objects handle baseurl via their_sitereference
  • Works everywhere: Supports file://, S3, GitHub Pages, Netlify, Vercel, etc.

Accessing Data Files

If you have a filedata/authors.yaml:

1
2
3
4
5
6
alice:
  name: Alice Smith
  bio: Engineer
bob:
  name: Bob Jones
  bio: Designer

You can access it viasite.data:

1
2
{% set author = site.data.authors[page.metadata.author] %}
<div class="bio">{{ author.name }}: {{ author.bio }}</div>

Template Inheritance

Bengal themes typically use Jinja2's inheritance model.

Base Template (base.html)

Defines the common structure (HTML head, nav, footer).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!-- themes/my-theme/templates/base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{{ site.title }}{% endblock %}</title>
</head>
<body>
    <nav>...</nav>

    <main>
        {% block content %}{% endblock %}
    </main>

    <footer>...</footer>
</body>
</html>

Page Template

Extends the base template and fills in the blocks.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- themes/my-theme/templates/page.html -->
{% extends "base.html" %}

{% block title %}{{ page.title }} - {{ site.title }}{% endblock %}

{% block content %}
    <h1>{{ page.title }}</h1>
    <div class="content">
        {{ page.rendered_html | safe }}
    </div>
{% endblock %}

Common Helpers

Bengal provides several Jinja2 filters and functions.

  • url_for(page): Returns the relative URL for a page object.
  • date_format(date, format): Formats a date object.
  • | safe: Marks HTML as safe to render (prevents escaping).

Debugging

If you are unsure what data is available, you can print objects to the console during build (using Python'sprintinside a template extension is not standard, but you can inspect variables).

A common trick is to dump data:

1
2
<!-- Dump variables to HTML comments for inspection -->
<!-- {{ page.metadata }} -->