PHP
Article

Using BoltCMS to Build a Small Business Website

By Nick Salloum

As the web continues to mature and the demand for the efficiency of content delivery increases, more and more slim and trim CMSs are coming into the fray. Developers (front-end and back-end) are branching away from the heavy-hitters like WordPress and Drupal, and into the likes of more streamlined, tailor-made solutions. Bolt CMS is one of these CMSs, and prides itself on being a dream for designers, developers, and content editors alike.

Bolt CMS Logo

On the front-end side of things, Bolt uses the increasingly popular Twig templating language, allowing front-end devs to quickly and neatly generate templates the way they want, and how they want. On the back-end side of things, custom types and fields give us the freedom to organise things the way we want. Bolt is also built upon Silex with Symfony components, making it stable, powerful, open source, and free. Twig, Silex, and Symfony are all under the Sensio Labs umbrella, so you’re guaranteed one will never leave the other in the dust. It’s a great combination!

Bolt has a really nicely laid out documentation on their site, as well as a Stack Overflow tag with an increasing number of posts. Other ways to raise points or get support include the GitHub issue tracker. Read up on the community page for more info.

Building With Bolt

In this article, we’re going to take a look at the following key points which should set us up nicely for building our first project with Bolt:

  1. Requirements, setup and installation
  2. Main configuration and theme set up
  3. Splitting up files into templates
  4. Introducing and creating content types
  5. Retrieving content from database records

From now on, I recommend you keep the docs open in your browser, because we’ll reference it a lot. Alright, let’s dig in!

Requirements, Setup & Installation

Bolt requires the following in order to run:

  • PHP 5.3.3 or higher
  • Access to SQLite, MySQL, or PostgreSQL
  • Apache with mod_rewrite or Nginx

The PHP installation also has a few more requirements, but you can read up on those here. For the admin panel to run efficiently and optimally, modern browsers are recommended. Of course, this is just for the admin side of things. The front-end will be served on the various browsers according to the way you build it.

There are three ways to install Bolt. I’m going to use option 1, the command line way. Let’s open up terminal and from there on, run the following commands:

curl -O http://bolt.cm/distribution/bolt-latest.tar.gz
tar -xzf bolt-latest.tar.gz --strip-components=1

From here on, make sure the correct files and directories have the correct permissions. Do this by running the following:

chmod -R 777 files/ app/database/ app/cache/ app/config/ theme/ extensions/

A Quick Note About 777 Permissions

777 is the number of the beast, and we should all be aware of this. You should be aware of why Bolt requires 777 on certain directories:

  1. It’s required on the /files/ directory, because Bolt needs to write to this directory when uploading media through the admin.
  2. It’s required by the app/cache/ directory, because Bolt automatically caches and retrieves cached material from this directory.
  3. The app/database/ permissions are totally optional, and completely unnecessary unless using SQLite. If you are using SQLite, Bolt will need to write to this directory to update the sqlite file.
  4. The app/config/ and theme/ permissions are also optional, and only required if users would like to edit the theme and configuration files through the bolt admin.
  5. The extensions/ directory is also optional, and only required if you’ll be uploading extensions via the Bolt admin.

You should be totally aware of the implications of using 777 permissions, and try to configure your server to avoid having to do so. Moving on.

Continuing With Setup

Out of the box, Bolt works just fine with SQLite (a file-based database). We’re going to configure it to work with MySQL though, which is probably a more likely scenario in a production website. Let’s set that up quickly. Since we’re in the terminal already, let’s cd into the app/config directory. Bolt gives us the default config.yml.dist file to start with, which is ready to roll with SQLite. Let’s copy that and rename it to config.yml so we can use MySQL, and open that up in an editor.

We edit the database section in accordance with the Bolt docs, but make sure to put your own values in:

database:
  driver: mysql
  username: root
  password: password
  databasename: bolt
  host: localhost
  port: 3306

Point your virtual host to the root directory of the project (for the easiest way to do this, see Homestead Improved) and visit the desired URL in the browser. You should now be presented with the Bolt start up page, prompting you to create the first user. Go ahead and do that. Now, you can log into the admin panel and also view the front end! Awesome, let’s move onto content types – the heart of Bolt.

Main Configuration and Theme Setup

By default, Bolt will load with the base-2014 theme. This is great for snooping around and getting started, but it’s very likely that you’ll want to create your own theme, and build from scratch. First of all, open up the project in your editor of choice. Navigate to the theme directory, and create a new directory called my-theme (you can call it whatever you want, really). Now, we want to change that theme on our back end.

Remember that configuration file we edited before we first loaded our project? Well, it’s now accessible through the admin. Go to Configuration > Main configuration, and it’ll load up the file. There’s a whole host of configuration options here, but we’ll stick to just three for now:

  1. Edit the sitename to your site name.
  2. Edit the payoff to your site’s tagline
  3. Edit the theme to the newly created theme (my-theme in my case)

After that, save the configuration file. Now go ahead and create an index.twig file inside your theme, and just input some boilerplate code like this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>My Website</title>
  <link rel="stylesheet" href="http://bootswatch.com/superhero/bootstrap.min.css">
</head>
<body>
  
<nav class="navbar navbar-default">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Site Title</a>
    </div>
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li><a href="#">Lorem</a></li>
        <li><a href="#">Ipsum</a></li>
        <li><a href="#">Dolor</a></li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container -->
</nav>

<main>
  <div class="container">
    <div class="jumbotron">
      <h1>Hello, world!</h1>
      <p>Welcome to my first bolt site.</p>
    </div>
  </div>
</main>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>

</body>
</html>

Notice that I’ve included a bootstrap template so that we have some aesthetics going on. You’ll probably want to link to your own CSS files, and don’t worry, I’ll show you how to do that soon. Hit refresh on the front-end window, and voila, your brand new site is waiting to be filled with delicious templates and content! But with many pages in the mix, it’s a hugely unsustainable and terrible practice to copy and paste entire chunks of reusable template code into new files, over and over again. Let’s get into templating a little bit.

Splitting Up Files Into Templates

As with any modern day website, particularly CMSs, we want to call upon different template files as needed. If you head on over to the “building templates” section of the docs, you’ll get some valuable information to help you out. Based on Bolt’s recommended file structure, and our current template, we can easily extract two main parts from our existing index.twig file:

  • _header.twig
  • _footer.twig

Now, our main index file should look like this:

{% include '_header.twig' %}

<main>
  <div class="container">
    <div class="jumbotron">
      <h1>Hello, world!</h1>
      <p>Welcome to my first bolt site.</p>
    </div>
  </div>
</main>

{% include '_footer.twig' %}

The relevant parts have been extracted into their respective files, but I won’t include them here to overstate the obvious. Now that we’ve touched on the basics of templating, let’s move on to content types and records, i.e. content creation, storage, and retrieval.

Introducing and Creating Content Types

We’re talking about a CMS here, so naturally, we’re going to be pulling some kind of content and records from a database. Let’s assume that we’re building a little business website, and we want to have three static pages and one testimonials page with multiple testimonial entires. So we’re looking at this sort of navigation:

- home
- about
- testimonials
    - single testimonial
    - ...
- contact

Let’s roll with this idea for the remainder of this article, so that we have something to build on. This brings us to the next main feature, and perhaps the main feature, of Bolt CMS – Content types and records. They concatenate the two words in the docs, because that’s how we reference them in the code, so from now on we’ll be calling them “contenttypes”.

So what exactly is a contenttype? Here’s a little excerpt from the Bolt docs:

All content in Bolt is stored in the database in a logical and flexible fashion. In general…you have an idea what kind of content you’re going to be managing. All of these different types of content are called Contenttypes in Bolt, and you can add as many different contenttypes as you need.

Apart from a couple required “Fields” that are used internally, we’re pretty much free to define how the Contenttype is structured. In the case of our static pages, we might want to include title, teaser, image, and body fields. In the case of our testimonials, we’ll probably want something like name, position, body, and date. Let’s examine this a bit more.

If we head over to our admin dashboard, you’ll notice that under the Content section, there are three different types of content that we can enter:

  • Pages
  • Entries
  • Showcases

These are actually contenttypes, and are all defined inside our contenttypes.yml file. Bolt makes it easy for us, and we can access this file directly through the admin (Configuration > Contenttypes). After studying the current contents of this file, let’s go ahead and delete everything except the pagescontent type. Our file should now look like this:

# Pages - used for the static pages like about, contact, etc.

pages:
    name: Pages
    singular_name: Page
    fields:
        title:
            type: text
            class: large
            group: content
        slug:
            type: slug
            uses: title
        image:
            type: image
        teaser:
            type: html
            height: 150px
        body:
            type: html
            height: 300px
        template:
            type: templateselect
            filter: '*.twig'
    taxonomy: [ chapters ]
    recordsperpage: 100

When you save that, you should notice that you no longer have access to the entries and showcases contenttypes. Let’s try to create our own for testimonials before we add any content. Head over to the “defining contenttypes” section in the docs, and let’s read through a bit. We’ll definitely want a name and singular_name, and our fields will be as we mentioned above. Let’s add our testimonial contenttype:

# Testimonials

testimonials:
    name: Testimonials
    singular_name: Testimonial
    fields:
        name:
            type: text
            class: large
        position:
            type: text
        body:
            type: textarea
            height: 150px

Save, and now you might get an alert to go and update your database. Follow the instructions, refresh, and now we can add a testimonial. Let’s quickly create a new testimonial, add some dummy data to it, and save it. We’ve just created our first contenttype, added a new entry, and stored it in the database. We’re not quite there yet, though. You’re probably wondering how to access and display these records. Well, let’s look at that in the next section.

Retrieving Content From Database Records

We’re going to backtrack just a little bit here, because we ignored a couple of important features. By default, Bolt looks for a record.twig template file to output the “record”, or the contenttype entry. If we preview that testimonial we just created, we’ll get an error thrown at us telling us that Bolt tried to use record.twig, and it doesn’t exist. Let’s create that and throw in some dummy content:

{% include '_header.twig' %}

<main>
  <div class="container">
    <div class="page-header">
      <h1>Record!</h1>
      <p>This is a generic record.</p>
    </div>
    <div class="page-content">
      <h2>Record Stuff Here</h2>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint eum tempore optio corporis aspernatur tempora temporibus vero maxime consectetur dolorum dolore vel numquam aut iure, esse, repudiandae nemo animi, vitae.</p>
    </div>
  </div>
</main>

{% include '_footer.twig' %}

Now if we hit refresh on our preview, we’ll see that we’ve generated the generic record page with dummy data. This brings us to point number two, though. It’s highly unlikely that the template for a testimonial will be the same as the template for a static page, so let’s fix that. Back in the defining contenttypes docs, we’ll see a few other things of interest:

  • record_template – the template to display a single record of a contenttype
  • listing_template – the template to display the collection of records of a contenttype

As we already know, by default, record_template will use the record.twig template file by default. For listing_template, it’ll search for the listing.twig file by default. We can, however, override these in our configuration of our contenttype. Let’s update it like this:

# Testimonials

testimonials:
    name: Testimonials
    singular_name: Testimonial
    fields:
        name:
            type: text
            class: large
        position:
            type: text
        body:
            type: textarea
            height: 150px
    listing_template: testimonials.twig
    record_template: testimonial.twig

Now, let’s create the respective testimonials.twig and testimonial.twig files. Here are the two files I created:

testimonials.twig

{% include '_header.twig' %}

<main>
  <div class="container">
    <div class="page-header">
      <h1>Testimonials!</h1>
      <p>All the testimonials be here.</p>
    </div>
    <div class="page-content">
      <p>All testimonials...</p>
    </div>
  </div>
</main>

{% include '_footer.twig' %}

testimonial.twig

{% include '_header.twig' %}

<main>
  <div class="container">
    <div class="page-header">
      <h1>Testimonial!</h1>
      <p>This is a testimonial.</p>
    </div>
    <div class="page-content">
      <p>Testimonial content...</p>
    </div>
  </div>
</main>

{% include '_footer.twig' %}

Now, we can access the overview page in the browser like via /testimonials, and our first record via /testimonial/1 (which is the default slug structure for records). Let’s focus on the single testimonial for now, and retrieve the data. Inside a single record page, we have access to the record values. To increase code readability, we can access it by the record name, in our case testimonial. If we go ahead and enter {{ dump(testimonial) }} in our record template, we’ll see the entire record dumped on our screen.

So how do we access parts of it? With Twig templating, we can access the various values by simple dot-notation. In other words, if we wanted the “name” of the person who wrote the testimonial (as defined in our contenttype configuration), we’d access it like this:

{{ testimonial.name }}

With that in mind, let’s configure our template to pull in the content:

{% include '_header.twig' %}

<main>
  <div class="container">
    <div class="page-header">
      <h1>{{ testimonial.name }} | <small>{{ testimonial.position }}</small></h1>
      <time>{{ testimonial.datecreated|date("jS F, Y") }}</time>
    </div>
    <div class="page-content">
      {{ testimonial.body }}
    </div>

  </div>
</main>

{% include '_footer.twig' %}

Now, creating more testimonials and viewing them should be a breeze. Let’s now head to our testimonials.twig template, and try to retrieve all testimonials. Just as we were able to before, we can access the “records” by name. We can call upon records, or in this case, testimonials. Go ahead and dump that out onto your page, and you’ll see them all.

Twig templating offer neat ways to iterate over arrays, along with some filters. I won’t get into too much detail here, but you’ve seen the first filter in action above when we formatted the date. I’ll use another filter to truncate the testimonial body to 100 characters. Our testimonials template should now look like this:

{% include '_header.twig' %}

<main>
  <div class="container">
    <div class="page-header">
      <h1>Testimonials</h1>
      <p>All the testimonials for this great company be here.</p>
    </div>
    <div class="page-content">
      {% for testimonial in testimonials %}
        <div class="testimonial">
          <h3>{{ testimonial.name }} | <small>{{ testimonial.position }}</small></h3>
          <p>{{ testimonial.body|excerpt(100) }}</p>
        </div>
      {% endfor %}
    </div>
  </div>
</main>

{% include '_footer.twig' %}

And there you go! Navigate over to /testimonials, and you’ll see the looped, formatted output. Go ahead now and populate your about page and contact page, and try to output the records in the generic record.twig template file. If you feel like you want a specific template for pages, create a page.twig file and go from there the same way as above. You’re now properly on your way to building up your site just the way you want.

A Note On Images & Media

One thing we haven’t touched on at all here is how Bolt handles media uploads. If you’re coming from a WordPress background, you’re most likely interested in the way WordPress handles media, with its robust, and (personally speaking) easy to use media library. Bolt is a constant work in progress, and there’s no doubt that there’s some room for improvement here. But once you get accustomed to the file management system, it becomes a bit easier.

In Bolt terminology, images are kept “on the stack”. This just means that there’s a stack of images that you manually uploaded. If you take a look at the directory structure, you’ll see the files directory. Here is where uploads are stored. When you upload a file in the admin, it’ll store it in a sub-directory referencing the year and month of the upload. Now, if you have a regular HTML field in your contenttype, and you’re trying to get an image in there, you might be a bit confused at this point. There’s no actual button to upload the image! Why is this?

By default, Bolt disables the image button from the WYSIWYG editor. Lucky for us, that’s easily accessible from the main configuration file. Inside the admin, head to settings -> configuration -> main configuration, and scroll down to the WYSIWYG section. There, you can change the images setting to true. Back in your record editor, you can now insert images the way you’d expect.

Where To Go From Here

There’s a whole lot more to Bolt than what we’ve seen, and that’s what makes it beautiful to work with. It’s feature rich, but only when you want it to be. It remains lightweight and fast throughout development and production, and just feels natural and easy to use. From here on, I recommend reading through the documentation. It’s really well written and easy to follow, and it answers a lot of your questions. My two top choice sections in the docs to boost your knowledge and workflow would be content fetching and template tags. After that, you’re looking at pagination, search, extending Bolt, and the works.

Thanks for reading, and I hope this article gave you some great insight into building with Bolt CMS. If you’re a WordPress or Drupal developer, I highly encourage you to open your mind to new platforms like Bolt. You will not be disappointed at all!


Free Guide:

7 Habits of Successful CTOs

"What makes a great CTO?" Engineering skills? Business savvy? An innate tendency to channel a mythical creature (ahem, unicorn)? All of the above? Discover the top traits of the most successful CTOs in this free guide.

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in PHP, once a week, for free.