2.1 The index page

Let's replace our generic Bootstrap home page with the real home page for our blog. Open a new terminal shell, navigate to the project directory, and start the Wagon web server with the bundle exec wagon serve command. Leave this web server running during the tutorial so that you can preview the changes we make in your browser at http://localhost:3333.

The header

Open the app/pages/views/index.liquid file and delete all of its contents. Paste in the following code.

title: Home
published: true
<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <meta name="keywords" content="{{ site.meta_keywords }} {{ page.meta_keywords }}">
    {% if page.meta_description %}
      <meta name="description" content="{{ page.meta_description }}">
    {% else %}
      <meta name="description" content="{{ site.meta_description }}">
    {% endif %}

      {{ page.title }} - {{ site.name }} |
      {% if page.seo_title %}
        {{ page.seo_title }}
      {% else %}
        {{ site.seo_title }}
      {% endif %}

    {{ 'bootstrap.min.css' | stylesheet_tag }}
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    Coming soon.

Let's go through this line by line.

The YAML header

At the very top of the file there is a YAML header is surrounded by a pair of triple dashes. All LocomotiveCMS templates start with YAML headers like this one. The header can set various properties for the page.

title: Home
published: true

This page sets two options: title and published. As you can probably guess, title sets the page's title and published is a boolean flag that determines whether this page should be publicly accessible by anyone, or if the page is still under review and should only be accessible to site editors.

Aside from the two properties above, there are around a dozen other properties that can be specified, but we'll come back to those later.

Output markup and drops

The template continues with some boilerplate HTML: a doctype and a few meta tags. The next interesting part comes in the <meta type="keywords"> tag where we can see our first piece of Liquid Markup. Liquid Markup, originally created by the good folks at Shopify, is one of Ruby's most popular templating languages.

<meta name="keywords" content="{{ site.meta_keywords }} {{ page.meta_keywords }}">

In Liquid, pairs of double curly brackets indicate output markup. Output markup outputs whatever is between the curly brackets.

Here, we output site.meta_keywords. Do you remember the config/site.yml file from Chapter 1.2? Wagon loads all of the properties set in config/site.yml into a drop called site that we can access in our templates. drops are collections of variables. You can access a drop's variables by putting a period after the drop name, followed by the variable's name.

After outputting site.meta_keywords, there's a space, and we then use Liquid to output page.meta_keywords. Similar to the site drop, Wagon loads all the properties set in a page's YAML header and puts them into the page drop.

Let's see what this looks like. Open your browser to http://localhost:33333, where you will be greeted by the world's most boring web page. View the source.

Our simple home page's source code

Hey, looky there. The keywords we assigned to meta_keywords in config/site.yml are in the meta tag! At the end, there's a space, but nothing afterwards. That's because we didn't assign the property meta_keywords in the page header. When a variable is empty or unassigned, Liquid outputs nothing.

Just to test this, replace the page header with the code below.

title: Home
published: true
meta_keywords: panda biscuits

Refresh the page and view the source again in your browser.

Our source code after adding panda biscuits

Behold! The page's keywords were now added in addition to the site-wide keywords. That was just to make a point, so go ahead and delete the meta_keywords property from the page header.

This is all great, but some may be wondering: why reference page.meta_keywords if it's empty? Further, why are we using variables at all? Why not just put the text directly into the HTML like so:

<meta name="keywords" content="travel backpacking budget adventure">

Good question! The first reason is because all of these variables are editable in the LocomotiveCMS back-office. LocomotiveCMS comes with a back-office where site editors can login and edit the site's content using an easy graphical user interface. Page header variables can be easily chagned by site editors. However, if we just put the text directly in the page, editors won't be able to change the SEO keywords.

The second reason is that index.liquid is not just a page. Thanks to LocomotiveCMS's page inheritance system, it also serves as a template for child pages. As such, we want the value of page.meta_keywords to change, depending on which page we are looking at. We'll come back to page inheritance later.

Liquid tags

Let's get back to our index.liquid template. Right after the keywords meta tag, we encounter another piece of Liquid markup.

{% if page.meta_description %}
  <meta name="description" content="{{ page.meta_description }}">
{% else %}
  <meta name="description" content="{{ site.meta_description }}">
{% endif %}

Here we are introduced to a second type of Liquid markup: tag markup. Liquid tags are indicated with paired curly brackets and percentage signs.

Liquid tags can perform all kinds of functions, but here we have a simple if statement: if page.meta_description exists, make a meta tag with the value of page.meta_description. Otherwise, make a meta tag with the value of site.meta_description. So if a page has a page specific meta description defined, we'll use that. Otherwise, we'll just use the global, site meta description.

Take another look at the source.

The source of the meta description

As you can see, we didn't define meta_description in the index.liquid page header, so the site meta description is used.

Next up is the page's <title> tag, which uses some of the Liquid output markup and tag markup that you've just learned. Take a look at the code and see if you can figure out what it does. You can always check your understanding by looking at the page source in your web browser.

Liquid filters

In the next line of index.liquid we encounter this interesting line:

{{ 'bootstrap.min.css' | stylesheet_tag }}

Liquid filters can be used inside output markup. Filters in some way modify whatever comes before the pipe character.

The stylesheets_tag filter takes the name of file in the public/stylesheets directory and creates an HTML ` tag referencing it. If you preview this page using Wagon's web server and view the source, you'll see the above Liquid becomes:

<link href="/stylesheets/bootstrap.min.css" media="screen" rel="stylesheet" type="text/css" />

This isn't just a time-saving shortcut. It's actually necessary due to the way LocomotiveCMS handles assets. If you were to deploy this site to an Engine and view the source, the same line would look something like this:

<link href="/sites/52759abbb5f1c932fe000002/theme/stylesheets/bootstrap.min.css" media="screen" rel="stylesheet" type="text/css">

For this reason, when linking to assets in your templates, use Liquid filters to generate the tag. What if we want to change the value of the media attribute? The stylesheet_tag filter actually takes a media argument, as shown in the example below.

{{ 'bootstrap.css' | stylesheet_tag: "screen, print" }}

Another solution might be to use a completely different filter, stylesheet_url, like this:

<link href="{{ 'bootstrap.css' | stylesheet_url }}" media="screen, print" rel="stylesheet" type="text/css">

Liquid filters can do way more than just modify URLs. Let's explore some other filters. You can try these experiments in index.liquid below the "Coming soon" text and check the results with the Wagon web server.

Filters can modify strings.

{{ 'test' | capitalize }}
<!-- Outputs: Test -->

Filters can also modify variables.

{{ page.title | upcase }}
<!-- Outputs: HOME -->

Filters can accept an argument.

{{ site.name | truncate: 10 }}
<!-- Outputs: Wisdom ... -->

Filters can accept multiple arguments.

{{ site.name | truncate: 8, "!!!" }}
<!-- Outputs: Wisdo!!! -->

Filters can modify numbers.

{{ 8 | plus: 10 }}
<!-- Outputs: 18 -->

Filters can be strung together.

{{ "MY NAME IS TOM" | dasherize | downcase }}
<!-- Outputs: my-name-is-tom -->

Pretty neat, huh? Liquid comes with a good set of filters and LocomotiveCMS has added more on top of that. You can see a list of all the filters and what they do using Liquid's Documentation and LocomotiveCMS's Template Reference.

The body

Onto the <body> of the page! Paste the following code into the body.

<div class="container">
  <!-- Site Title -->
  <div class="row">
    <div class="col-md-10 col-md-offset-1 col-sm-12">
      <h1>{{ site.name }}</h1>

  <!-- Site Navigation -->
  <div class="row">
    <div class="col-md-10 col-md-offset-1 col-sm-12">
      <nav class="navbar navbar-default" role="navigation">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main-nav">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="main-nav">
          <ul class="nav navbar-nav">
            <li {% if page.slug == "index" %}class="active"{% endif %}>
              <a href="/">Home</a>

  <!-- Page Content -->
  <div class="row">
    <div class="col-md-10 col-md-offset-1 col-sm-12">
      <h2>{{ page.title }}</h2>
      Coming Soon.

<!-- Javascripts -->
<script type='text/javascript' src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
{{ 'bootstrap.min.js' | javascript_tag }}

You've probably noticed that the page now has quite a few div and span tags making use of Bootstrap classes. These are there to make this page responsive, so that it can be viewed on phones, tablets, and desktops. They also create the navigation bar under the title.

Go ahead and take a look in the browser.

Our new home page

What exactly these Bootstrap classes do is a bit outside the scope of this tutorial, but I'd encourage anyone interested to checkout Bootstrap's excellent documentation site.

Page slugs and operators

Let's study this bit of Liquid from the navigation bar in the body:

<li{% if page.slug == "index" %}class="active"{% endif %}>
  <a href="/">Home</a>

page.slug is a variable representing the page's slug. In LocomotiveCMS, page slugs configure the URL of a page. If a page's slug is foo-bar-baz, then the page can be accessed at the URL /foo-bar-baz. Page slugs should be all lowercase, hyphenized, and unique among pages in the same directory.

Like page.title or page.meta_description, page.slug can be set in the YAML header using the slug option. By default, all pages are assigned a slug based on their file name, so we usually omit this option from the header.

This file is index.liquid, so the slug is index by default. If we created a file app/views/pages/things_to_pack.liquid, the slug would be things-to-pack. Note that the underscores became hyphens. This situation probably won't come up, but if you wanted the slug of things_to_pack.liquid to be packing, you could do so by adding the following line to the YAML header in things_to_pack.liquid.

slug: packing

As you might have noticed, the slug index is a special slug that allows us to access the page at the root URL. Since index.liquid's slug is index, the page is accessible at /.

Back to the Liquid code above, the next new bit is ==. As in many programming languages, Liquid uses == as a comparison operator. So, {% if page.slug == "index" %} could be translated as "if the value of page.slug equals index". Liquid features the usual suspects in terms of comparison operators. They are shown in the table below.

== equals Ex) {% if (2 + 1) == 3 %}
!= does not equal Ex) {% if 'a' != 'b' %}
> greater than Ex) {% if 10 > 5 %}
< less than Ex) {% if 0 < 1 %}
>= greater than or equal to Ex) {% if 10 >= 9 %}
<= less than or equal to Ex) {% if 7 <= 7 %}
contains Ex) {% if 'foobar' contains 'foo' %}

Let's take a look at that Liquid markup again:

<li {% if page.slug == "index" %}class="active"{% endif %}>
  <a href="/">Home</a>

If we put everything together, this Liquid markup means: if the slug of the current page is "index", then add class="active" to this <li> tag. For those interested, active is a Bootstrap class used for marking the current location in navigation.

Finishing up

There's are a few more pieces of Liquid markup on the page, but I'll let you find those on your own. If you're not sure what they do, you can always consult LocomotiveCMS's Template Reference.

Let's commit our pages to the git repository before moving on.

$ git add app/views/pages/index.liquid
$ git commit -m "Customized the home page."

The home page is complete for now. We still have a long way to go on our blog, but the pace will really pick up from here.

Next: adding pages
© 2023 LocomotiveCMS Terms of use Privacy Policy
Back to top