Grav - Theme Tutorial


In this chapter, let us create a Grav theme to understand the concept.

Antimatter

When you install the Grav base package, the default Antimatter theme is installed, which uses Nucleus (a simple base set of CSS styling). Nucleus is a lightweight CSS framework that contains essential CSS styling and HTML markup which gives a unique look and feel.

Bootstrap

Let us create a theme that utilizes popular Bootstrap framework. Bootstrap is an open-source and most popular HTML, CSS, and JS framework making front-end web development faster and easier.

The following steps describe the creation of theme −

Step 1: Base Theme setup

There are some key elements to Grav theme as we studied in the Theme Basics chapter which are to be followed in order to create new theme.

Grav Theme Tutorial Grav Theme Tutorial
<?php
namespace Grav\Theme;
use Grav\Common\Theme;
class Bootstrap extends Theme {}
enable: true

Step 2: Add Bootstrap

In order to create a bootstrap theme, you must include Bootstrap in your theme. So you need to download the latest Bootstrap package by clicking this link as shown below.

Grav Theme Tutorial

Unzip the package and you will see three folders namely css, fonts and js. Now copy the contents of these 3 folders into similarly named folders in user/themes/bootstrap that were created earlier.

Step 3: Base Template

As we studied in the previous chapter, the content is stored in the default.md file which instructs the Grav to look for the rendering template called default.html.twig. This file includes everything that you need to display a page.

There is a better solution that utilizes the Twig Extends tag which allows you to define the base layout with blocks. This will allow the twig template to extend the base template and provide definitions for blocks defined in the base.

Follow these steps to create a simple Bootstrap base template −

<!DOCTYPE html>
<html lang = "en">
   <head>
      {% block head %}
      <meta charset = "utf-8">
      <meta http-equiv = "X-UA-Compatible" content = "IE = edge">
      <meta name = "viewport" content = "width = device-width, initial-scale = 1">
      {% if header.description %}
      <meta name = "description" content = "{{ header.description }}">
      {% else %}
      <meta name = "description" content = "{{ site.description }}">
      {% endif %}
      {% if header.robots %}
      <meta name = "robots" content = "{{ header.robots }}">
      {% endif %}
      <link rel = "icon" type = "image/png" href="{{ theme_url }}/images/favicon.png">

      <title>{% if header.title %}{{ header.title }} | {% endif %}{{ site.title }}</title>

      {% block stylesheets %}
         {# Bootstrap core CSS #}
         {% do assets.add('theme://css/bootstrap.min.css',101) %}

      {# Custom styles for this theme #}
         {% do assets.add('theme://css/bootstrap-custom.css',100) %}

         {{ assets.css() }}
      {% endblock %}

      {% block javascripts %}
         {% do assets.add('https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js', 101) %}
         {% do assets.add('theme://js/bootstrap.min.js') %}

         {% if browser.getBrowser == 'msie' and browser.getVersion >= 8 and browser.getVersion <= 9 %}
            {% do assets.add('https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js') %}
            {% do assets.add('https://oss.maxcdn.com/respond/1.4.2/respond.min.js') %}
         {% endif %}

         {{ assets.js() }}
      {% endblock %}

      {% endblock head %}
   </head>
      <body>
         {# include the header + navigation #}
         {% include 'partials/header.html.twig' %}

         <div class = "container">
            {% block content %}{% endblock %}
         </div>

         <div class = "footer">
            <div class = "container">
               <p class = "text-muted">Bootstrap Theme for <a href = "http://getgrav.org">Grav</a></p>
            </div>
         </div>
      </body>
   {% block bottom %}{% endblock %}
</html>

Step 4: Breaking it Down

Let's see how the code works in base.html.twig file as shown below.

{% do assets.addCss('http://fonts.googleapis.com/css?family = Open + Sans') %}

or,

{% do assets.addJs(' https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js') %}

Step 5: Header Template

When {% include 'partials/header.html.twig' %} is executed, the Twig rendering engine searches for the Twig template. So create the header.html.twig template file inside user/themes/bootstrap/templates/partials folder with the following content.

<nav class = "navbar navbar-default navbar-inverse navbar-static-top" role = "navigation">
   <div class = "container">
      <div class = "navbar-header">
         <button type = "button" class = "navbar-toggle"
            data-toggle = "collapse" data-target = ".navbar-collapse">
               <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 = "#">Grav</a>
      </div>
      
      <div class = "navbar-collapse collapse">
         <ul class = "nav navbar-nav navbar-right">
            {% for page in pages.children %}
            {% if page.visible %}
            {% set current_page = (page.active or page.activeChild) ? 'active' : '' %}
            <li class = "{{ current_page }}"><a href = "{{ page.url }}">{{ page.menu }}</a></li>
            {% endif %}
            {% endfor %}
         </ul>
      </div>
      
   </div>
</nav>

The above code creates a navbar and displays all menu items automatically whenever a new page is created in the user/pages folder.

Step 6 − Default Template

Each item of the content has a particular file name such as default.md which instructs Grav to search for a template file called default.html.twig. Let us now create the default.html.twig file in your user/themes/bootstrap/templates/ folder with the following content.

{% extends 'partials/base.html.twig' %}
{% block content %}
   {{ page.content }}
{% endblock %}

The above default.html.twig file extends the partials/base.html.twig and tells the base template to use {{ page.content }} for the content block.

Step 7: Theme CSS

In partials/base.html.twig file we referenced to a custom theme css using assets.add('theme://css/bootstrap-custom.css',100), which stores any custom CSS used in your site.

Let us now create a bootstrap-custom.css file in user/themes/bootstrap/css folder with the following content −

/* Restrict the width */
.container {
   width: auto;
   max-width: 960px;
   padding: 0 12px;
}

/* Place footer text center */
.container .text-muted {
   margin: 18px 0;
   text-align: center;
}

/* Sticky footer styles
-------------------------------------------------- */
html {
   position: relative;
   min-height: 80%;
}

body {
   /* Margin bottom by footer height */
   margin-bottom: 60px;
}

.footer {
   position: absolute;
   bottom: 0;
   width: 100%;
   /* Set the fixed height of the footer here */
   height: 50px;
   background-color: #dcdcdc;
}

/* Typography */
/* Tables */
table {
   width: 100%;
   border: 1px solid #f0f0f0;
   margin: 30px 0;
}

th {
   font-weight: bold;
   background: #f9f9f9;
   padding: 5px;
}

td {
   padding: 5px;
   border: 1px solid #f0f0f0;
}

/* Notice Styles */
blockquote {
   padding: 0 0 0 20px !important;
   font-size: 16px;
   color: #666;
}

blockquote > blockquote > blockquote {
   margin: 0;
}

blockquote > blockquote > blockquote p {
   padding: 15px;
   display: block;
   margin-top: 0rem;
   margin-bottom: 0rem;
   border: 1px solid #f0f0f0;
}

blockquote > blockquote > blockquote > p {
   /* Yellow */
   margin-left: -75px;
   color: #8a6d3b;
   background-color: #fcf8e3;
   border-color: #faebcc;
}

blockquote > blockquote > blockquote > blockquote > p {
   /* Red */
   margin-left: -100px;
   color: #a94442;
   background-color: #f2dede;
   border-color: #ebccd1;
}

blockquote > blockquote > blockquote > blockquote > blockquote > p {
   /* Blue */
   margin-left: -125px;
   color: #31708f;
   background-color: #d9edf7;
   border-color: #bce8f1;
}

blockquote > blockquote > blockquote > blockquote > blockquote > blockquote > p {
   /* Green */
   margin-left: -150px;
   color: #3c763d;
   background-color: #dff0d8;
   border-color: #d6e9c6;
}

Step 8: Testing

Change your default theme with the new bootstrap theme. Open the user/config/system.yaml file and edit the line which contains −

pages:
   themes: antimatter

and change the above code to −

pages:
   theme: bootstrap

Now reload your Grav site and you will see the newly installed theme as shown below.

Grav Theme Tutorials