Template Reference
Tuesday, 08 July 2025 - ⧖ 16 min🗒️
- Template System Overview
- Template Variables
- Global Variables (Available in all templates)
- Content-Specific Variables (content.html)
- List-Specific Variables (list.html)
- Group-Specific Variables (group.html)
- Template Functions
- Template Filters
- Template Inheritance
- Template Includes
- Custom Template Creation
- Advanced Template Features
- Template Debugging
- Best Practices
Marmite uses the Tera templating engine, which provides a powerful and flexible way to customize your site's appearance. This reference covers all template variables, functions, and customization options available in Marmite.
Template System Overview
Template Engine
- Tera: Jinja2-inspired templating language
- Inheritance: Templates can extend and override parent templates
- Includes: Templates can include other templates
- Filters: Built-in and custom filters for data transformation
- Functions: Custom functions for complex operations
Core Templates
Marmite provides four core templates that can be customized:
templates/
├── base.html # Base template for all pages
├── content.html # Individual content pages
├── list.html # Content listing pages
└── group.html # Grouped content pages (tags, authors, etc.)
Template Variables
Global Variables (Available in all templates)
Site Configuration
{{ site.name }} <!-- Site name -->
{{ site.tagline }} <!-- Site tagline -->
{{ site.url }} <!-- Site URL -->
{{ site.language }} <!-- Site language -->
{{ site.footer }} <!-- Site footer HTML -->
{{ site.pagination }} <!-- Posts per page -->
{{ site.default_date_format }} <!-- Default date format -->
{{ site.enable_search }} <!-- Search enabled boolean -->
{{ site.enable_related_content }} <!-- Related content enabled -->
{{ site.toc }} <!-- Table of contents enabled -->
{{ site.json_feed }} <!-- JSON feed enabled -->
{{ site.publish_md }} <!-- Markdown publishing enabled -->
{{ site.source_repository }} <!-- Source repository URL -->
Site Data
{{ site_data.posts }} <!-- All posts -->
{{ site_data.pages }} <!-- All pages -->
{{ site_data.tag.map }} <!-- Posts grouped by tag -->
{{ site_data.archive.map }} <!-- Posts grouped by year -->
{{ site_data.author.map }} <!-- Posts grouped by author -->
{{ site_data.stream.map }} <!-- Posts grouped by stream -->
{{ site_data.series.map }} <!-- Posts grouped by series -->
Navigation
{{ menu }} <!-- Navigation menu items -->
{{ language }} <!-- Site language -->
Fragment Content
{{ announce }} <!-- Content from _announce.md -->
{{ header }} <!-- Content from _header.md -->
{{ hero }} <!-- Content from _hero.md -->
{{ sidebar }} <!-- Content from _sidebar.md -->
{{ footer }} <!-- Content from _footer.md -->
{{ comments }} <!-- Content from _comments.md -->
{{ htmlhead }} <!-- Content from _htmlhead.md -->
{{ htmltail }} <!-- Content from _htmltail.md -->
Content-Specific Variables (content.html)
Content Object
{{ content.title }} <!-- Content title -->
{{ content.description }} <!-- Content description -->
{{ content.slug }} <!-- URL slug -->
{{ content.html }} <!-- Rendered HTML content -->
{{ content.date }} <!-- Publication date -->
{{ content.authors }} <!-- Author names array -->
{{ content.tags }} <!-- Tags array -->
{{ content.stream }} <!-- Stream name -->
{{ content.series }} <!-- Series name -->
{{ content.pinned }} <!-- Pinned status boolean -->
{{ content.toc }} <!-- Table of contents HTML -->
{{ content.card_image }} <!-- Social media card image -->
{{ content.banner_image }} <!-- Banner image -->
{{ content.comments }} <!-- Comments enabled boolean -->
{{ content.source_path }} <!-- Source file path -->
{{ content.modified_time }} <!-- Last modification time -->
Navigation
{{ content.next }} <!-- Next post in stream/series -->
{{ content.previous }} <!-- Previous post in stream/series -->
{{ content.back_links }} <!-- Content linking to this post -->
Note: When both series
and stream
are set on content, series navigation takes precedence for next/previous links.
Extra Fields
{{ content.extra.math }} <!-- Enable MathJax -->
{{ content.extra.mermaid }} <!-- Enable Mermaid diagrams -->
{{ content.extra.mermaid_theme }} <!-- Mermaid theme -->
{{ content.extra.custom_field }} <!-- Any custom frontmatter field -->
List-Specific Variables (list.html)
Pagination
{{ content_list }} <!-- Array of content for current page -->
{{ current_page }} <!-- Current page filename -->
{{ current_page_number }} <!-- Current page number -->
{{ total_pages }} <!-- Total number of pages -->
{{ total_content }} <!-- Total content count -->
{{ per_page }} <!-- Items per page -->
{{ previous_page }} <!-- Previous page filename -->
{{ next_page }} <!-- Next page filename -->
Group-Specific Variables (group.html)
Grouping
{{ kind }} <!-- Group type: "tag", "author", "archive", "stream", "series" -->
{{ title }} <!-- Group page title -->
Template Functions
url_for()
Generate URLs with proper base URL handling:
<!-- Basic usage -->
<a href="{{ url_for(path='about.html') }}">About</a>
<!-- Absolute URL -->
<a href="{{ url_for(path='about.html', abs=true) }}">About</a>
<!-- External links (passed through unchanged) -->
<a href="{{ url_for(path='https://example.com') }}">External</a>
group()
Access grouped content:
<!-- Get all tags -->
{% for tag_name, tag_posts in group(kind="tag") %}
<h3>{{ tag_name }}</h3>
<ul>
{% for post in tag_posts %}
<li><a href="{{ post.slug }}.html">{{ post.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}
<!-- Get all authors -->
{% for author_name, author_posts in group(kind="author") %}
<h3>{{ author_name }}</h3>
<p>{{ author_posts | length }} posts</p>
{% endfor %}
<!-- Get all streams -->
{% for stream_name, stream_posts in group(kind="stream") %}
<h3>{{ stream_display_name(stream=stream_name) }}</h3>
<ul>
{% for post in stream_posts %}
<li><a href="{{ post.slug }}.html">{{ post.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}
<!-- Get archive years -->
{% for year, year_posts in group(kind="archive") %}
<h3>{{ year }}</h3>
<p>{{ year_posts | length }} posts</p>
{% endfor %}
<!-- Get all series -->
{% for series_name, series_posts in group(kind="series") %}
<h3>{{ series_display_name(series=series_name) }}</h3>
<ul>
{% for post in series_posts %}
<li><a href="{{ post.slug }}.html">{{ post.title }}</a></li>
{% endfor %}
</ul>
{% endfor %}
stream_display_name()
Get friendly display names for streams:
<!-- Show display name for current content's stream -->
{% if content.stream %}
<span class="stream-name">{{ stream_display_name(stream=content.stream) }}</span>
{% endif %}
<!-- Use in stream listing -->
{% for stream_name, stream_posts in group(kind="stream") %}
<h3>{{ stream_display_name(stream=stream_name) }}</h3>
<p>{{ stream_posts | length }} posts in {{ stream_display_name(stream=stream_name) }}</p>
{% endfor %}
<!-- Link to stream page with friendly name -->
<a href="{{ content.stream }}.html">
View all {{ stream_display_name(stream=content.stream) }} posts
</a>
Configuration:
streams:
tutorial:
display_name: "Python Tutorials"
news:
display_name: "Latest News"
guide:
display_name: "User Guides"
If no display name is configured, returns the stream name itself.
series_display_name()
Get friendly display names for series:
<!-- Show display name for current content's series -->
{% if content.series %}
<span class="series-name">{{ series_display_name(series=content.series) }}</span>
{% endif %}
<!-- Use in series listing -->
{% for series_name, series_posts in group(kind="series") %}
<h3>{{ series_display_name(series=series_name) }}</h3>
<p>{{ series_posts | length }} posts in {{ series_display_name(series=series_name) }}</p>
{% endfor %}
<!-- Link to series page with friendly name -->
<a href="serie-{{ content.series }}.html">
View all {{ series_display_name(series=content.series) }} posts
</a>
Configuration:
series:
python-tutorial:
display_name: "Python Tutorial"
web-dev-basics:
display_name: "Web Development Basics"
If no display name is configured, returns the series name itself.
source_link()
Generate source file links:
<!-- Generate source link for current content -->
{% set source_url = source_link(content=content) %}
{% if source_url %}
<a href="{{ source_url }}" rel="nofollow">📄 View source</a>
{% endif %}
Template Filters
default_date_format
Format dates using the site's default format:
{{ content.date | default_date_format }}
remove_draft
Filter out draft content from arrays:
<!-- Remove draft posts from a list -->
{% for post in site_data.posts | remove_draft %}
<li>{{ post.title }}</li>
{% endfor %}
<!-- Get count of non-draft items -->
{{ items | remove_draft | length }}
<!-- Use with group function results -->
{% for name, items in group(kind="tag") %}
<h3>{{ name }} ({{ items | remove_draft | length }} posts)</h3>
{% for post in items | remove_draft %}
<li>{{ post.title }}</li>
{% endfor %}
{% endfor %}
Built-in Tera Filters
Marmite includes all standard Tera filters:
<!-- String filters -->
{{ content.title | upper }}
{{ content.description | truncate(length=100) }}
{{ content.slug | replace(from="-", to="_") }}
<!-- Array filters -->
{{ content.tags | join(sep=", ") }}
{{ content_list | slice(end=5) }}
{{ content_list | length }}
<!-- Date filters -->
{{ content.date | date(format="%Y-%m-%d") }}
<!-- URL filters -->
{{ content.slug | urlencode }}
<!-- Utility filters -->
{{ content.html | striptags }}
{{ content.title | slugify }}
Template Inheritance
Base Template Pattern
<!-- base.html -->
<!DOCTYPE html>
<html lang="{{ language }}">
<head>
<title>{% block title %}{{ site.name }}{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
<header>
{% block header %}
<h1>{{ site.name }}</h1>
{% endblock %}
</header>
<main>
{% block main %}{% endblock %}
</main>
<footer>
{% block footer %}
{{ site.footer }}
{% endblock %}
</footer>
{% block tail %}{% endblock %}
</body>
</html>
Extending Templates
<!-- content.html -->
{% extends "base.html" %}
{% block title %}{{ content.title }} | {{ site.name }}{% endblock %}
{% block main %}
<article>
<h1>{{ content.title }}</h1>
{{ content.html }}
</article>
{% endblock %}
Template Includes
Including Other Templates
<!-- Include fragments -->
{% include "content_title.html" %}
{% include "content_date.html" %}
{% include "pagination.html" %}
<!-- Conditional includes -->
{% include "comments.html" ignore missing %}
{% include "custom_sidebar.html" ignore missing %}
Custom Template Creation
Content-Specific Templates
Create templates for specific content types:
<!-- templates/custom_tutorials.html -->
{% extends "base.html" %}
{% block main %}
<article class="tutorial">
<div class="tutorial-header">
<h1>{{ content.title }}</h1>
<div class="tutorial-meta">
<span>Difficulty: {{ content.extra.difficulty }}</span>
<span>Duration: {{ content.extra.duration }}</span>
</div>
</div>
{% if content.toc %}
<div class="tutorial-toc">
<h2>Table of Contents</h2>
{{ content.toc }}
</div>
{% endif %}
<div class="tutorial-content">
{{ content.html }}
</div>
</article>
{% endblock %}
Stream-Specific Templates
Templates for specific streams:
<!-- templates/custom_news.html -->
{% extends "list.html" %}
{% block main %}
<div class="news-header">
<h1>Latest News</h1>
<p>Stay updated with our latest announcements</p>
</div>
<div class="news-grid">
{% for post in content_list %}
<article class="news-item">
<h2><a href="{{ post.slug }}.html">{{ post.title }}</a></h2>
<time>{{ post.date | default_date_format }}</time>
<p>{{ post.description }}</p>
</article>
{% endfor %}
</div>
{% endblock %}
Series-Specific Templates
Templates for specific series with chronological navigation:
<!-- templates/custom_series.html -->
{% extends "base.html" %}
{% block main %}
<div class="series-header">
<h1>{{ series_display_name(series=content.series) }}</h1>
<p>Part {{ content.series_position }} of {{ content.series_total }}</p>
</div>
<article class="series-content">
<h2>{{ content.title }}</h2>
{{ content.html }}
</article>
<nav class="series-navigation">
{% if content.previous %}
<a href="{{ content.previous.slug }}.html" class="prev-post">
← Previous: {{ content.previous.title }}
</a>
{% endif %}
{% if content.next %}
<a href="{{ content.next.slug }}.html" class="next-post">
Next: {{ content.next.title }} →
</a>
{% endif %}
</nav>
<div class="series-toc">
<h3>All Parts in This Series</h3>
<ul>
{% for post in site_data.series.map[content.series] %}
<li {% if post.slug == content.slug %}class="current"{% endif %}>
<a href="{{ post.slug }}.html">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}
Advanced Template Features
Conditional Content
<!-- Show content based on conditions -->
{% if content.stream == "tutorials" %}
<div class="tutorial-notice">
This is a tutorial post. Follow along step by step!
</div>
{% endif %}
<!-- Show series navigation -->
{% if content.series %}
<div class="series-notice">
Part of the <a href="serie-{{ content.series }}.html">{{ series_display_name(series=content.series) }}</a> series
</div>
{% endif %}
<!-- Show content based on site configuration -->
{% if site.enable_search %}
<div class="search-box">
<input type="search" placeholder="Search...">
</div>
{% endif %}
Loops and Iteration
<!-- Loop through tags -->
{% for tag in content.tags %}
<span class="tag">{{ tag }}</span>
{% endfor %}
<!-- Loop through authors -->
{% for author in content.authors %}
<span class="author">{{ author }}</span>
{% endfor %}
<!-- Loop with conditions -->
{% for post in content_list %}
{% if post.pinned %}
<article class="pinned-post">
{% else %}
<article class="regular-post">
{% endif %}
<h2>{{ post.title }}</h2>
</article>
{% endfor %}
Template Comments
{# This is a template comment - won't appear in output #}
{#
Multi-line comments
are also supported
#}
Template Debugging
Debug Variables
<!-- Debug site data -->
<pre>{{ site | json_encode(pretty=true) }}</pre>
<!-- Debug content -->
<pre>{{ content | json_encode(pretty=true) }}</pre>
<!-- Debug specific values -->
<p>Debug: {{ content.stream | default(value="no stream") }}</p>
Template Errors
Common template errors and solutions:
- Variable not found: Use
{{ var | default(value="fallback") }}
- Filter not found: Check filter name spelling
- Template not found: Verify template file exists
- Syntax error: Check bracket matching and syntax
Best Practices
- Use template inheritance: Extend base templates for consistency
- Keep templates DRY: Use includes for repeated content
- Handle missing data: Use default filters for optional fields
- Comment your templates: Document complex logic
- Test thoroughly: Verify templates work with different content types
- Use semantic HTML: Structure content meaningfully
- Optimize for performance: Minimize template complexity
This comprehensive reference covers all aspects of Marmite's template system. Use these features to create beautiful, functional, and maintainable themes for your site.
Please consider giving a ☆ on Marmite Github repository, that helps a lot!