Creating a Bolt theme from a template

A friend recently asked me if I could make a simple website for the new radiostation he was joining as a DJ. My usual job is big applications and web projects, so (while this may sound weird) a simple website is actually something I'm not that efficient in, but since finding Bolt I actually do that every once in a while. Setting up and configuring Bolt is such a simple task that I've been happily creating some simple websites for friends or contributing to website projects every once in a while.

My main weak point is frontend and design. This is something I have been painfully aware of for ages already. Luckily there are sites like TemplateMonster and Open Source Web Design that offer templates that can be used for websites where there is no dedicated designer/frontender, nor budget for one. After a quick talk with my friend there was some budget to get a paid template from TemplateMonster, but now this template needed to be applied to the Bolt installation I had set up and configured with the required contenttypes.

The thing with Bolt is: It's actually quite easy to create themes. One of the reasons is the fact that they use Twig as a template engine, but on top of that they've added some pretty nice and useful extensions. So, let me walk you through the steps I took to create the theme for this specific site, which is my usual workflow for creating a Bolt theme.

The directory structure

Bolt's themes can be found in the /theme folder, which is quite obvious. By default, Bolt comes with two standard themes: default and base-2014. These are very helpful, because they give you a good idea of the structure and approach you can take in creating the templates. But since it's Twig anyway, if you want to use another approach, that's not that hard.

To create a new theme, you create a new directory in the theme directory with a name that represents your theme. In my case, I created the directory /theme/atlantis.


Next up: Assets. Any stylesheets, javascripts and images can be put into the newly created directory. You could put them somewhere else, but it's obviously easier to keep it all in the same directory, especially since Bolt has some additional variables available in the templates such as paths.theme, which you can use in your templates to refer to the base theme directory (we'll talk about that later). I took the js, css and images directories from the design I purchased and put them in /theme/atlantis directory.

Switching the active theme

Another thing I need to do is to switch the active theme before I can actually test my work. For this, I need to open the app/config/config.yml file and update the theme value:

    theme: atlantis

Now Bolt will look for the template files in my theme/atlantis directory.

Breaking up the design

In most websites, every page consists of several parts. Some parts are very specific to the page you're viewing, others are shared throughout the site. For instance, the header and footer, sometimes also the sidebar. In this case, the header and footer are used throughout the site (except for the homepage), and only the middle part is different for different pages. So the first thing I needed to do was identify which parts of the HTML could be shared and put them into different template files. Luckily, the template I purchased was well documented and easily marked the "cut lines" for the header and footer. Pretty quickly, I had a _header.twig file and a _footer.twig file.

As usual, the header contains a lot of links to css files and javascript files. As I mentioned before, Bolt adds some useful variables to your templates that can be used to make sure the URLs you use are always correct. Imagine your template being renamed, or put into a subdirectory when you go live, if you use hardcoded URLs such as /theme/atlantis/js/jquery.js, this won't work anymore when the site is being deployed on production into /radio. Bolt's paths variable comes to the rescue.

So I went through the header to create relative paths for this. Just to give you an idea, this is part of the header now:

    <link rel="icon" href="{{ paths.theme }}/images/favicon.ico" type="image/x-icon">
    <link rel="stylesheet" href="{{ paths.theme }}/css/grid.css">
    <link rel="stylesheet" href="{{ paths.theme }}/css/owl.carousel.css"/>
    <link rel="stylesheet" href="{{ paths.theme }}/css/style.css">
    <script src="{{ paths.theme }}/js/jquery.js"></script>
    <script src="{{ paths.theme }}/js/jquery-migrate-1.2.1.js"></script>

For any images that are part of the theme, I did the same thing. I did this for the header and the footer (though the latter contained only two paths that I needed to update, so that was quite simple).

The main pages

The header and footer parts of the template are the same for each of the different templates that the purchased design defined, with the exception of the homepage (we'll get back to the homepage later). However, the content parts were different. That makes sense, because a DJ listing simply looks different from a news section. So from the HTML files I got with the purchased template, I took everything between the header and footer markers and pasted that into a new file. For instance for the DJ section, I created a new file called djs.twig for the listing and dj.twig for the detail page. Now, however, I'm not done yet, because I don't have the header and footer yet. Luckily, we can use Twig's include functionality for that. So at the top, I added:

    {% include "_header.twig" %}

And at the bottom, the predictable:

    {% include "_footer.twig" %}

In the contenttype configuration in app/config/contenttypes.yml, I can now point Bolt to these new templates and make Bolt use those for the dj contenttype, by specifying the templates:

    record_template: dj.twig
    listing_template: djs.twig

Now when I load up the djs page on http://localhost:8080/radio/djs (I use the built-in webserver of PHP to run this website locally using the following command: php -S localhost:8080 -t .), I get the page I just created. However, there is no dynamic content yet in my listing page, because I haven't actually created the dynamic content. It's the just default listing that the HTML file contained. Let's work on that next.

Dynamic content

In the static HTML of the djs.twig, I identified the snippet of HTML that I needed to repeat for each of the DJ's. It was a pretty simple piece of HTML. I quickly filled it with the placeholders for the content that should go in there, which resulted in the following snippet:

    <div class="grid_3">
            <div class="event">
                <img src="{{ thumbnail(dj.image, 270, 170) }}" alt="{{ }}"/>
                <h6 class="color_2">
                    <a href="{{ }}">{{ }}</a>
                <p>{{ dj.teaser }}</p>

In a Bolt listing page, the records in the database for the specified content type are always available in a variable called records. So surrounding the above snippet is a simple for-loop:

    {% for dj in records %}
        // snippet
    {% endfor %}

Now it actually works, and I get content from the database instead of the static HTML that I had. Yay!

For the record-page which shows the individual DJ (when they click on the name in the listing), I now have to do a similar thing. This page contains a record variable instead of a records variable, which is just a single record, so I don't need a for loop, but the process of making it dynamic is similar as above.

More dynamic content

When you look at the bottom of the DJ listing you'll notice two blocks of text. I could add those statically to the website, but if I were to do that, for every change to that text the radiostation would have to either edit the template themselves or content me. Instead, I wanted to make these blocks of text editable through the Bolt CMS interface. Bolt has a great system of fetching content when you need it. I've put that system to good use for the blocks on the DJ-listing as well as various other dynamic blocks throughout the site.

I've created a new contenttype called blocks for this reason. By creating this contenttype, the CMS backend contains a management interface allowing the radiostation to update the text without having to edit any files. But now I still have to display it in the site. This is where Bolt's fetching content feature comes in.

There are two blocks at the bottom of the page, so I'll fetch those blocks seperately in the location where I want them. This results in the following template code:

    {% setcontent block = 'blocks' where { identifier_string: 'djs_wie_zijn_wij' } returnsingle %}
    <h4 class="color_2">{{ block.title }}</h4>
        <div class="box3">
            {{ block.body }}

The first line actually does all the magic. It sets the value of the block variable to the result of a query where I look for a record with the string 'djs_wie_zijn_wij' in the field 'identifier_string'. Because I added the returnsingle parameter it will return a single record. If I didn't do that, it would be an array containing a single record, which is kind of useless. Now, after setting the value, I can simply echo the title and body of the block in the template. I do the same for the second block, just fetching the content by a different identifier_string.


Now that I've done the first section (DJs) the same thing can be repeated for the other sections as well. Since all sections except for the homepage use the same header and footer code I can easily re-use those by using the same include systements that I've used in the DJ section. Once I've done that, all I'm missing is the homepage!

The homepage

The process of getting the homepage up and running is actually very similar to what I've described above. I set it up slightly differently though. Because I don't have to reuse the header and the footer of the homepage (the homepage is the only page with this style) I don't have to create seperate header and footer templates, I can simply put it all into one file. I've called that file homepage.twig.

In the app/config/config.yml file I can define what the homepage should contain and which template it should use. This basically defines what information will be available in your template. I've configured the homepage to be:

    homepage: over/homepage
    homepage_template: homepage.twig

This means it's going to use the record from the 'over' contenttype with slug 'homepage'. My 'over' contenttype is used for a section of pages with information about the radiostation (the Dutch word 'over' translates to 'about' in English). The page with the slug 'homepage' clearly contains the information I want to display on the homepage.

Aside from the basic information for the homepage, I also want to display the most recent 5 newsitems, so I manually fetch that content and loop over it.

    {% setcontent latestnews = 'nieuwsberichten/latest/5' %}
    {% for news in latestnews %}
        // the content to display the newsitem here
    {% endfor %}

Now when I load my homepage, it also works!

Getting rid of more duplicated code

Actually, there is still more duplicated code in my templates. Using more include statements, I can easily get rid of that. But since the process of doing that is the same as what I've done with the header and footer, I won't describe it in more detail. Be pragmatic about extracting duplicated content though: Extracting every single detail into a seperate template file and including it wherever it is used can be a pain in the ass once your website enters maintenance, because you'll be searching for ages to get to that specific element that is causing problems in your site. Use your common sense to determine whether you want to extract something into a seperate template, and do it mostly for very common elements such as header, footer, sidebar and navigation.