Using Template Tags¶
Template tags are one of the most flexible extension points in SmallBlock CMS. They allow you to embed dynamic data directly into your templates, enabling you to mix Python logic with presentation without modifying the CMS core.
In this tutorial, you’ll learn how to define custom template tags, pass parameters, return complex data structures, and optionally render partial templates.
—
Before You Begin¶
Make sure you have:
A working SmallBlock CMS site from Build Your First Site.
Completed the Create a Plugin tutorial.
Basic familiarity with Python functions and modules.
Access to your project’s plugin directory.
—
How Template Tags Work¶
Template tags are Python functions decorated with @app.template_tag(name).
They are loaded at application startup and made globally available inside your
template engine.
A template tag can:
return a string
return a list, dict, or other iterable
render a partial template using
app.render_template()
The following diagram shows the rendering flow:
![digraph G {
rankdir=LR;
node [shape=box, style="rounded,filled", fillcolor="#eef3f8"];
A [label="Template Tag Function\n(plugin.py)"];
B [label="@app.template_tag(name)"];
C [label="Template Engine"];
D [label="Rendered Output"];
A -> B -> C -> D;
}](../_images/graphviz-15c042b9cb124b2ddfc3016a2f9e6cb746dba38f.png)
—
Step 1 — Create a New Plugin (If Needed)¶
If you don’t already have a plugin for experimenting with tags, create one:
cd mysite/plugins
mkdir -p current_time
cd current_time
touch __init__.py plugin.py
Your folder now contains:
current_time/
├── __init__.py
└── plugin.py
—
Step 2 — Create a Basic Template Tag¶
Open plugin.py and add:
from datetime import datetime
def register(app):
@app.template_tag("current_time")
def current_time(format="%Y-%m-%d %H:%M:%S"):
"""Return the current server time, formatted."""
return datetime.now().strftime(format)
app.logger.info("Template tag 'current_time' registered.")
This creates a tag named current_time that accepts an optional
format string, defaulting to ISO-like output.
Verify
Run:
python3 -c "from plugins.current_time.plugin import current_time; print(current_time())"
—
Step 3 — Use the Tag in a Template¶
Open any template (for example, templates/base.html) and insert:
<footer>
<p>Server time: {% current_time "%H:%M:%S" %}</p>
</footer>
Reload your site — the current time should appear on every page render.
—
Step 4 — Build a Tag That Returns a List¶
Template tags can return lists that templates iterate over.
Extend plugin.py with:
def register(app):
@app.template_tag("recent_pages")
def recent_pages(limit=5):
"""Return the N most recently published pages."""
pages = (
app.models.Page.query
.order_by(app.models.Page.published_at.desc())
.limit(int(limit))
.all()
)
return pages
Then add to a template:
<aside>
<h3>Recent Pages</h3>
<ul>
{% for page in recent_pages 5 %}
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
</aside>
The sidebar will update automatically as new content is published.
—
Step 5 — Create a Tag That Renders a Partial Template¶
For more complex markup, tags can render subtemplates.
Add to plugin.py:
def register(app):
@app.template_tag("site_header")
def site_header():
"""Render a custom header partial."""
return app.render_template("partials/site_header.html")
Create templates/partials/site_header.html:
<header class="site-header">
<h1>{{ site_name }}</h1>
<nav>
<a href="/">Home</a>
<a href="/about/">About</a>
</nav>
</header>
Include the tag anywhere in your layout:
{% site_header %}
—
Step 6 — Style the Output¶
For example, in static/css/custom.css:
.site-header {
background-color: #0f1c2c;
color: #e6edf3;
padding: 1em;
border-bottom: 2px solid #23445a;
}
.site-header a {
color: #9baec8;
text-decoration: none;
margin-right: 1em;
}
.site-header a:hover {
color: #e6edf3;
}
—
Troubleshooting¶
Tag doesn’t appear or raises an error
Ensure the tag name matches the decorator exactly.
Restart the development server — tags load at startup.
Confirm the plugin is enabled in your configuration:
[plugins] enabled = current_time
Check logs:
smallblock logs
Partial template not rendering
Ensure the path (e.g.,
partials/site_header.html) exists.Confirm
render_template()is being passed correct parameters.
—
Next Steps¶
Continue extending your templates and site design with:
Extend the Toolbar — build interactive editor tools.
Building a Custom Theme — style your entire project.
Building a Multilingual Page — localize your template output.