Templating / Building templates
Note: You are currently reading the documentation for Bolt 4.0. Looking for the documentation for Bolt 5.2 instead?
To render HTML pages with dynamic content, Bolt uses the Twig templating language. This means that everybody who is familiar with Twig can easily get started with building templates in Bolt.
In short, Twig can be described as a 'flexible, fast, and secure template engine for PHP'. Primarily, it separates the markup of your templates from the PHP code in the CMS. It does this elegantly and quickly, which means that writing your HTML templates in Twig will give you clean and legible templates.
That means you don't have to use PHP-like statements in your markup, so there's less code like this:
<?php if ( the_something('3') ) { ?>
<h1>Title is: <?php echo the_title() ?>.</h1>
<?php } ?>
Instead, more like this:
{% if something('3') %}
<h1>Title is: {{ title }}.</h1>
{% endif %}
A template in Bolt can use all standard Twig tags, functions, filters and tests, with a few additions that are specific to working with Bolt. If you're not familiar with Twig yet, you should read "Twig for Template Designers", on the official Twig website.
Twig syntax basics¶
There are basically three different types of Twig delimiters that you can use in your templates:
{% %}
— Control structures, or "do something" actions{{ }}
— Output structures, or "output something" action{# #}
— Comments that are not meant for outputting to the rendered page
Inside control & output structures you can use expressions, statements, variables, functions and filters.
A simple example of these together might look like this:
{# Render the content in template.twig here #}
{% include 'template.twig' %}
{# Create a varable called "vars" containing an array #}
{% set vars = {'foo': 'bar'} %}
{# Check if the "vars" variable can be looped over #}
{% if vars is iterable %}
{# Loop over our variable #}
{% for key, value in vars %}
<p>{{ key }} has the {{ value }}</p>
{% endfor %}
{% else %}
<p>Well this is strange!</p>
{% endif %}
For in-depth coverage you should read the Twig manual.
Control structures¶
Simply, control structures are sections of logic in your template file that "does something".
They are defined using by pairing a curly brace and a percentage sign —
{% %}
— that contains a "tag".
The most common tags used in a Twig template are typically:
for
that is used to iterate over an arrayif
statements allow you to conditionally perform actionsset
is used to "set" a variable's valueinclude
statements return the rendered content of another templateblock
tags are used to break out inheritable sections of templates for re-use or overriding in child templates
For example, {% if foo == "bar" %}
is a statement that tests if the variable
foo
is equal to the value "bar". If so, the part that's between the opening
statement and the corresponding {% endif %}
will be rendered.
Output structures¶
As the name suggests, output structures are used to display the output of variables, or Twig functions & filters.
They are defined using by pairing two curly braces — {{ }}
— that contain
the instructions to give to Twig in order to output the desired text.
For example:
{{ foo }}
outputs the contents of the variablefoo
{{ bar(foo) }}
outputs the results of the functionbar()
. In this case, 'foo' is used as an argument in the function, so the output is most likely dependent on the contents offoo
.{{ foo|bar }}
Outputs the variablefoo
, but withbar
as a filter. Iffoo
is "hello",{{ foo|upper }}
would output "HELLO".
Comments¶
Comments are just that, to add comments to your templates, that don't do anything, but leave yourself useful information relevant to that part of the template.
They are comparable to the HTML comments like <!-- foo -->
, except for the
fact that Twig comments don't get sent to the browser,so you can't see them
using 'view source'.
They are defined using by pairing a curly brace with a # sign — {# #}
—
that contain the comment's text.
For example, the following lines of a Twig template would render an empty HTML
<div>
, but leaves yourself a reminder to why.
<div>
{# TODO: Add something here #}
</div>
Filesystem Layout¶
A Bolt website theme consists of a set of Twig templates, that are located in
the theme
folder in the public directory of your site.
You can always add more templates, if you want to. By default, the index.twig
template is the homepage, but you can override it using the configuration settings.
The current default theme contains the following files and folders:
File | Description |
---|---|
index.twig |
Front page of the web site |
page.twig |
For a single pages ContentType record |
listing.twig |
Displaying listings, like 'latest pages', but also taxonomy overview pages |
record.twig |
A 'generic record' page, used if the ContentType has no template specified |
search.twig |
Displaying search results. |
partials/_master.twig |
Base layout template, that other templates extend to inherit the properties of |
partials/_aside.twig |
Helper template that gets included as the sidebar |
partials/_header.twig |
Helper template that gets included as the header. |
partials/_footer.twig |
Helper template that gets included as the footer. |
partials/_recordfooter.twig |
Footer specifically for ContentType records |
theme.yaml |
A file with configuration related to the theme and how it works with bolt. Can also contain configuration for template specific fields and values for the theme to use in its templates. |
js/ |
Compiled JavaScript files |
css/ |
Compiled CSS files |
The file names of the 'helper' templates all start with an underscore. This is just a convention, to make it easier to recognize which template does what. If one of your ContentTypes have a 'template select' field, Bolt will skip these helper templates by default, when providing you with a list to select your template.
Tip: the default template set uses the
include
tag to insert the header, footer and such, but you're free to use
Template Inheritance if you prefer.
By default, Bolt creates links to single pages based on the ContentTypes, and it uses a template based on its name.
For instance, if your site has a ContentType foos
, a single record in that
ContentType will be available under domain.com/foo/slug-of-record, where
slug-of-record
is the "slugified" version of the title. Bolt will try to use
foo.twig
as the template to render the page.
You can change this by either defining another template in contenttypes.yaml
,
or using a 'template select' field in the ContentType. More information about
this can be found in the section on working with ContentTypes.
Using your themes theme.yaml
you can provide overrides for certain settings
of the main config.yaml
. These are useful when building themes and you want to
provide your own templates.
These are (provided with examples):
homepage_template: index.twig
record_template: record.twig
listing_template: listing.twig
search_results_template: listing.twig
maintenance_template: maintenance.twig
listing_template
is used for both ContentType listings and taxonomy listings.
By using the template_directory
setting in your themes theme.yaml
you can
choose the location of the templates within your theme structure.
For example to place all your templates in a directory called twig
you would
add the following to your theme's theme.yaml:
template_directory: twig
Template structure¶
A simple page.twig
template could look something like the example you see
below.
Using this example we'll go over some of the details of the Twig Template language. As mentioned before: Much, much more detailed info can be found at Twig for Template Designers on the official Twig site.
{% extends 'partials/_master.twig' %}
{% block main %}
<article>
<h1><a href="{{ record.link }}">{{ record.title }}</a></h1>
{# Only display the image, if there's an actual image to display #}
{% if record.image != "" %}
<div class='image'>
<img src="{{ record.image|thumbnail(320, 240) }}">
</div>
{% endif %}
{{ record.body }}
<p class="meta">
Posted by {{ record.user.displayname }} on
{{ record.datecreated|date("M d, ’y")}}
</p>
</article>
{% endblock main %}
What happens in this example is the following:
{% extends 'partials/_master.twig' %}
, line 1: Theextends
tag tells Twig that this is a child template, that inherits the content and functionality from_master.twig
{% block main %}
, line 3: Theblock
tag, and its matchingendblock
on line 23, tells Twig to override the contents of the block called "main" in_master.twig
{{ record.title }}
, line 6: Since this is a generic template,record
contains the record of the current requested page. For example, if the current page is domain.com/news/the-website-is-live,record
would contain the record from thenews
ContentType that has 'the-website-is-live' as a slug. Therecord
variable acts like an array, so to output thetitle
field, we use dot-notation (.
){{ record.link }}
, line 6: Here we use the link property to get the URL that links to the content{# Only display .. #}
, line 8: This is a simple comment. It will be removed when the template is rendered to the browser, so it will not show up in 'view source'{% if content.image != "" %} … {% endif %}
, lines 9 - 13: Theif
statement only parses the part between the start and end tag, if the given condition is true. So, in this case, the image is only rendered to the browser, ifcontent.image
does not equal an empty string (""
), i.e. if it is not empty{{ record.image|thumbnail(320, 240) }}
, line 11: By using thethumbnail
filter, we can create thumbnail images on the fly. In this case, the image source attribute in the HTML will be something like '/thumbs/300x240/imagename.jpg'. Bolt has a built-in image resizer that will create the image with the exact dimensions, and caches it for further use.{{ record.body }}
, line 15: This renders thebody
field of the ContentType record{{ record.datecreated|date("M d, ’y")}}
, line 19:datecreated
is one of the elements that is always present in all ContentTypes, and it contains the date the record was created. It's stored in a machine-readable format, so to display it the way we want, we use thedate()
filter. In this case, it will output something like 'August 26, ’12'.
Couldn't find what you were looking for? We are happy to help you in the forum, on Slack or on Github.