This article is not maintained any longer and likely not up to date. DuckDuckGo might help you find an alternative.

How to add a carousel to your Bolt CMS homepage

In this tutorial, we will add a carousel to the homepage of our Bolt CMS using the jQuery based Slick library. We will first define what our goal is, set up the base system, create a basic HTML version of the carousel and finally incorporate it into our Bolt CMS page.

User Stories

A carousel is a collection of images that are presented on a website. There are two roles in this scenario: a website visitor and a website editor.

  1. As a visitor, I want to see some images about the service of the website I am visiting.
  2. As a visitor, I only want to see one image at a time.
  3. As a visitor, I want to be able to manually browse the images with back (<<) and forth (>>) buttons.
  4. As a visitor, I want the loading time of the website to be as little as possible.
  5. As an editor, I want to create a carousel in the backend.
  6. As an editor, I want to add/remove images to/from a carousel.
  7. As an editor, I want to change the order of the images in the carousel.

(Note: The user stories may seem a bit fine-grained, but they will help you to stay on track and can check many todos and stay motivated)

Setup

(Note: If you are familiar with setting up a development environment and Bolt CMS itself, you can skip this and the next section. Just take care of the naming conventions I introduce here.)

You need a local development environment using a command-line and running PHP 5.6/7, Composer.

I am using a Mac for my development, and I use the very handy development tool Laravel Valet. Please use whatever you and your machine works best with, be it MAMP, DesktopServer or even Docker. If you are not on a Mac and have no preferences, I highly recommend Laravel Homestead to you.

You are ready to go if php -v in terminal spits out PHP 7.1.0 or any other version number above 5.6, composer shows you a list of commands.

Installing Bolt

(Note: I always add line numbers for my edits. Those derive from vanilla settings, so if you added extra lines in your files, the numbers would not be correct. But even in these situations, they will guide you to the approximate location.)

We will use Composer to install the CMS itself. composer create-project bolt/composer-install:^3.2 carousel --prefer-dist

carousel is the name of the app – you can name it however you want, just note this name, you might need it later. Be patient, the installer downloads quite a few libraries (~ 100 MB). The installer will ask you a few questions about locations that I will just confirm with Enter. Of course, you can change the details to your liking here.

Bolt is ready for setup now. You just need to tell your local web server to serve the public folder. The easiest way is to fire up PHP's internal dev server with php -S localhost:8888 while within the public folder. I prefer using Valet which uses Nginx under the hood. The command is valet link conference while within the public folder. You can now open carousel.dev in your browser and add an admin user.

There is a note below the form which informs you that you're using SQLite. SQLite is a „database in a file“, which makes it a lot more mobile than a MySQL database. It is production-ready for sites where you have few editors (= people editing the database) and as many visitors (= requesting data from the database and cache) as you like. Our conference app may become a case where many users access and alter the database via their entries, so probably for a production site, I would go for a full-blown MySQL database. For development SQLite is fine, and you can migrate from SQLite to MySQL or MariaDB rather simply later if you want.

Setting up Bolt

Did you create your admin user already? I gave mine the username carousel-24st3 (the name is not so easy to get, which is good to prevent brute-force login attempts). Click save, and you'll be redirected to carousel.dev/bolt and see the backend.

Creating the content type

Let's start by managing the data structure first:

There may be more than one carousel on your website. It hence makes sense to create a new ContentType for it. A carousel consists of two fields: a title (mainly for reference) and an Imagelist. An Imagelist is a collection of images.

So, open your config file from carousel/app/config/contenttypes.yml and add a new ContentType:

# pages-contenttype just for orientation
pages:
    …
    recordsperpage: 100

# carousel contenttype
carousels:
    name: Carousels
    singular_name: Carousel
    fields:
        title:
            type: text
          slug:
            type: slug
            uses: title
        gallery:
            type: imagelist
    record_template: carousel.twig

What do the settings under fields mean?

  1. Every field has a name, such as title and gallery.
  2. We will access the content via these names in our template later.
  3. The type of a field is one from this list, with type: text, type: textarea and type: html being the most used ones. The last one is the equivalent of the content area that you know from Wordpress, where you can add and format freeform text.

We need a slug to get an URL for a single carousel. And gallery is just the name for the list of images. Lastly, record_template: carousel.twig will enable us to create a template part for all carousels that we can then include in any part of the website.

We head over to our backend and update the database. In the left panel, we now have a new section called "Carousels".

Note: When you visit your site at carousel.dev, you will be greeted by an error message. We did not create a page, so Bolt does not have anything to show here.

Creating our first carousel

Create a new carousel from the menu in the backend's left panel. Let's give it the title My Carousel and add a couple of images via Select from server. We can see a few example images there and luckily they all have the same size. Adding four images via Adding selected is enough to showcase the carousel. Set Status to Published.

Once we added images, we can change their order simply by click, hold and move them around. We can delete them from the carousel by clicking the x on the right.

Preparing the template

We defined carousel.twig as the template file for carousels. It does not exist yet, so we will just copy index.twig from the folder public/theme/base-2016/ . We need to change a few things here:

  1. Remove {{ record.teaser }}, {{ record.body }} as we do not have these fields
  2. Loop over the images we have with
{% for images in record.gallery %}
    {{ image|showimage() }}
{% endfor %}

Save and we can now view the preview. The preview URL that we can directly visit is carousel.dev/preview/carousel. We see four images, each on a single line.

Ok, what do we need to get a moving carousel?

  1. The carousel Javascript and CSS assets
  2. A Javascript script that initiates the carousel

Loading the JS and CSS assets

We could hardwire the assets in the base template ( public/theme/base-2016/partials/_master.twig, but let's think twice.

We only need the carousel assets in pages that contain carousels. Adding the sources to _master.twig would load them on every page. We do not want this. What can we do instead?

Let's open _master.twig. In line 19 and 20 there is a tag {% block headincludes %}{% endblock headincludes. This is a Twig block. It enables us to extend the master template with every template that uses it with % extends ‚partials/_master.twig‘ %} – just as our carousel.twig. This way we can include custom headers just for this page.

Here is how it should like for carousel.twig:

{% block headincludes %}
    <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css" />
    <!-- Add the slick-theme.css if you want default styling -->
    <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick-theme.css" />
    <style>
.slick-prev:before, .slick-next:before { 
    color:red !important;
}
</style>
{% endblock headincludes %}

Note: We have to define blocks one after another, so make sure you add the headinclude outside of the main block. The order of blocks is not crucial, following a logical order makes it easier to read the code, though.

This will load Slicks CSS files from a remote CDN server, so we do not have to install extra software.

What about the Javascript assets? It is considered best practice to include them at the end of your page, just before the closing </html>. And Bolt's base-2016 template has a block for this as well bottomincludes. This is how it is supposed to look like for loading the assets for us (again in carousel.twig:

<script type=" text/javascript " src="//code.jquery.com/jquery-1.11.0.min.js "></script>
<script type="text/javascript " src="//code.jquery.com/jquery-migrate-1.2.1.min.js "></script>
<script type="text/javascript " src="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js "></script>

Save carousel.twig and reload the preview in Chrome. And? Nothing. Click right in the window and view the source. Here you can see that indeed the CSS and JS were loaded. But what is missing?

The Javascript script that initiates the carousel

Of course, we need to initiate slick and tell it which elements to include in the carousel. We have to wrap the loop in a div and give it a unique ID so we can access it:

    <div id="my-carousel">
        {% for image in record.gallery %}
            {{ image|showimage() }}
        {% endfor %}
    </div>

As documented on slick's website, we can now initiate (or define) the carousel such as this within the bottomincludes block:

    <script type="text/javascript ">
        $(document).ready(function(){
          $('#my-carousel').slick({
            slidesToShow: 1,            
            lazyLoad: 'ondemand',
            autoplay: true,
            accessibility: true
          });
        });
    </script>

We address the div with #my-carousel and defined a few settings. We get lazy loading out of the box which basically means that not all images will be loaded at page load but rather when they are being viewed. This speeds up the initial load, especially on mobile connections.

Save and load the carousel again. Yeah, that looks like a carousel now. But wait: Where are the buttons to switch between the images?

Fiddling through the page source will reveal that there are buttons for back and forth – but they are white. There is an easy fix: Just add this to your headincludes block:

    <style>
        .slick-prev:before, .slick-next:before { 
            color:red !important;
        }
    </style>

Save, refresh and see the buttons.

We now have a fully functional carousel. We can visit and enjoy it

Including the carousel in the header area

Right now we have to visit a special URL to view the carousel. Sometimes, however, we want to include the carousel on every page. For example: In Bolt's base-2016 theme we might want to put the carousel where we see a city panorama now.

What should we do?

  1. Move the assets to the global _master.twig file (we need them on any page now) (put the CSS in the header and the JS before the </html> as described above
  2. In base-2016/partials/_header.twig define the content of the carousel and load a new partial, because the generic record variable gets always filled with the current page's values. We need the values from one page, however, so we use setcontent to get our carousel's content.
{% setcontent mix = '/carousel/my-carousel' %}
{{ include('partials/_carousel.twig') }}
  1. Create new partial _carousel.twig in base-2016/partials and just paste the loop in it:
<div class="large-12 columns headerphoto" id="my-carousel">
    {% for image in mix.gallery %}
        {{ image|showimage() }}
    {% endfor %}
 </div>

Save everything and create some pages in the backend (I created an about and contact page and filled them with some dummy content.

When we load about and contact now, we see the carousel. We did not fine tune the dimensions and the headings and body text may be covered by the carousel, but you can check the page source to see that they are actually there.

Great job!

Did this help you?