Grav: Building Fast and Flexible Websites

By  on  

I've been friends with Djamil Legato for almost a decade. We were on the MooTools team in its early days, trying to forge a more useful way of working with JavaScript. Fast forward to today, Djamil is working on an awesome flat-file CMS called Grav. Have a look at what he and his team have created!

Grav is an open source flat-file CMS, that requires no database and that is built to be modular, easy to use, and incredibly fast. Its database-free structure offers users the advantage of simple setup, straightforward customization, and rapid deployment to any server running php 5.4 or higher, including the all new php 7.

The Grav project started about a year ago, and has recently gone into a release candidate stage. It has been largely created by a very small team of talented developers with experience working with larger content management systems, including Joomla and WordPress.

Why Grav?

The inspiration behind Grav's development was to create a CMS that fills a gap between simple, static sites and complex multiuser blogs. When the project's founder, Andy Miller, took a look at the flat-file solutions already out there, he found current options were either commercial, underpowered, or both.

This isn't for lack of technology. Twig tempting, YAML configuration, markdown content support, and other exceptionally user-friendly features were out there, but they hadn't been assembled into a single CMS available for free.

We felt it was important to make Grav not only free, but open source. This enables its community of developers to contribute code, have a definite say in the project's development, and to easily create plugins and themes that take full advantage of Grav's capabilities.

Flat-file Structure

One of Grav's biggest features is its flat-file structure. This enables it to not only break free of the need of a database, but for its content to be simply created, swapped, and edited.

Installing Grav on a server is as simple as downloading the Grav core, or a skeleton which includes demo content to get you started, and unpacking it on your server.

There is no database to set up or installation wizard to work through.

User Folder

Grav has an intuitive organizational structure, as well. For example, just about everything that isn't core to Grav is stored in a user folder. This includes any custom configuration and settings, user accounts, themes, site-specific assets, plugins, and content.

At its basic level, backing up a Grav site is as simple as making a copy of the user folder.

The site's content is stored in the user/pages directory. Here, pages are organized using a directory structure. Each blog post, for example, would have its own folder containing a markdown file and any images used in the post. Images can be stored in many different ways, but this is one popular example.

User Folder

You can separate categories, or types of pages by directory as well. For example, if your site has a dedicated Authors area where profiles of authors are maintained, putting this content in its own folder is an easy way to set it apart in Grav's menu system.

A theme can have several page templates that enable you to create unique styling and layouts for different areas of the site. Page templates are loaded depending on the name of the markdown file. For example, if a blog post's markdown file is named item.md, this tells Grav to use the item.html.twig template when rendering the page.

In the example seen in the image a couple paragraphs above, you we used blog.md to reference a parent blog page template included with the Antimatter theme.

Powerful Command Line

Grav is designed to fit the needs of its user. This includes giving users the ability to decide if they want to control Grav almost entirely using the command line, or through its simple, yet powerful, admin plugin.

Once you have Grav's core on your server, installing just about any theme or plugin is a breeze. We have detailed documentation of Grav's GPM (Grav Package Manager) and CLI commands, but we'll give a basic example of how you can hit the ground running here.

Let's say you just installed the Grav core, and want to add the TwentyFifteen theme. All you have to do is type bin/gpm install twentyfifteen.

Want to back up your site's content? Simply type bin/grav backup from within the site's directory to generate a zip file, pre-labeled with the date and time the backup was performed.
Plugins
The very flexible and modular architecture of Grav, allows for anything to be just written as a Plugin. Grav Core can work alone, all you will need is a theme and nothing else, but to enrich your experience or compliment requirements for a site, it all comes down to plugins.

Plugins can attach to an extensive number of Events that Grav Core triggers while performing its tasks. Every event and task is greatly optimized to maintain the #1 priority of Grav, which is speed.

Grav is so flexible that we were able to create the whole Admin manager in a single plugin.

Grav's Admin plugin gives users an intuitive, easy-to-follow interface for managing Grav's configuration and content. The goal behind the plugin was to make Grav accessible to anyone, regardless of their level of technical know-how.

Its dynamic structure is made possible by Grav's YAML configuration system, pulling in options and settings from plugins and themes and presenting them in a way that is intuitive and natural to the user.

Grav's current free plugin library features over 70 plugins, with more being produced all the time.

Even if there isn't a plugin already available that meets your needs, creating one for Grav is as simple as it gets, thanks in large part to its YAML + Twig code base.

Community-driven Development

Perhaps the most important element in Grav's DNA is its community. From day one, development has occurred in public on GitHub, with participation encouraged in a variety of ways.

From GitHub issues to the Gitter chat room, users are able to interact directly with the Grav development team to offer feedback, ask questions, and raise any issues that they find. There is even a forum, powered by Muut, where users can go to find information, request more detailed support, and meet other Grav users.

It's this dedication to community-driven development, along with Grav's free and open philosophy, that makes it a unique choice for anyone seeking a CMS that is fast, light, and simple to understand.

Creating a new page type with custom fields

The best way to get an idea of how Grav works from a development standpoint is to dive right in and see it in action. You can download Grav's core, some plugins, and even free themes from GetGrav.org. You can even find skeletons to help you get up and running with Grav, a theme, and some sample content.

To get us started, we will go over the process of creating a new page template with some unique styling and functionality. For the purpose of this example, we will assume that you have already installed the Core Grav package that includes a single home page, and the Antimatter theme.

A feature list is a common modern user interface technique that can quickly convey the major features of your product, company or service. These commonly take the appearance of a simple icon with a title and subtitle below.

It would be great if there were a simple way to easily create some initial features, and be able to modify them easily and add more if needed. This can be accomplished with Grav's built-in custom header functionality combined with a custom Twig template to render, and even a custom blueprint to provide an interface for the Admin plugin.

Let's get cracking!

1. Create a new page

The first thing we need to do is create a folder to house the markdown file which will represent the content. The folder also has the added ability to provide a default URL slug and order in the navigation. You will already have a homepage contained in 01.home, so simply create another folder at the same level called 02.features. This will ensure the features page comes after home, reachable by the slug /features.

In this folder, create a new file called features.md. By using the name features, we are also going to tell Grav to use a template file from our theme called features.html.twig. We will create this template later.

In this features.md file we need to define some headings in YAML format between --- markers. We commonly call this YAML frontmatter.

---
title: Features
features:
    - title: Crazy Fast
      subtitle: So fast it will make your head spin
      icon: fighter-jet
    - title: Easily Extended
      subtitle: Built to be highly extensible
      icon: puzzle-piece
    - title: Fun to Use
      subtitle: Making web development work fun again
      icon: truck
---

# Features List

Check out a taste of our amazing features

Although Grav supports a powerful set of header settings, all are optional.

However, we set the title for clarity. We have also created a custom field called features that consists of a YAML list. Each of the three feature items (denoted by the -) contains three elements: title, subtitle, and icon.

These names are completely arbitrary, and are simply named appropriately for our needs. Of course you can add more items if you wish, but these three will suffice for our example.

NOTE: We are using FontAwesome icon names, however the Antimatter theme already loads this for us. If you use a custom theme, you will need to ensure this is loaded.

Below the frontmatter section (as denoted by the --- markers) we have some basic markdown headers to provide a title a description for the features that will displayed in a grid.

2. Create a Twig template

When Grav initializes it will parse this page information and store the resulting object in cache. This is then available to be used to render appropriate HTML in the form of a Twig template.

Twig templates are typically stored in the templates/ folder or your current theme. Create a new file in your theme called features.html.twig. This will automatically be used to render the page because we used the page filename of features.md. In this file we will need to loop over the features we defined in the page and display them in a format we can easily manipulate with CSS:

{% extends 'partials/base.html.twig' %}

{% block content %}
<div class="features">
    {{ content }}
    <ul>
    {% for feature in page.header.features %}
        <li>
            <i class="fa fa-fw fa-{{ feature.icon }}"></i>
            <h4>{{ feature.title }}</h4>
            <p>{{ feature.subtitle }}</p>
        </li>
    {% endfor %}
    </ul>
</div>
{% endblock %}

The {% extends %} and the {% block %} definition are used to instruct Twig to extend the partials/base.html.twig template and replace the empty base content block with this custom one. The {{ content }} element will display the markdown content section of the features page. Below this, we loop over each of the list items in the page.header.features which is where we defined each feature item.

3. Give it some style

All that is left is to provide some CSS styling to ensure the features list is rendered appropriately. We can do this by creating a file in our theme's css/ folder called custom.css. In the Antimatter theme, this is automatically inserted into the page if it exists:

.features {
    text-align: center;
}

.features h1, .features h4 {
    margin-bottom: 0;
    line-height: 1.2;
}

.features > p {
    font-size: 1.1rem;
}

.features p {
    margin-top: 0;
}

.features ul {
    margin: 3rem 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
}

.features li {
    padding: 1rem 2rem;
    text-align: center;
    display: flex;
    flex-direction: column;
    width: 100%;
}

.features li i {
    font-size: 6rem;
    margin: 0 auto;
}

@media all and (min-width: 40em) {
    .features li {
        width: 50%;
    }
}
@media all and (min-width: 60em) {
    .features li {
        width: 33.33%;
    }
}

That is enough CSS to provide a basic representation that will display our features in a grid of 3 items across.

All that is left is to test the results. Simply point your browser to your Grav homepage and then add /features to the URL address. You should see something like this:

4. Admin Blueprint

Because Grav is a flat-file CMS, everything can be accomplished from the file system.

However, when providing a solution to clients, a Web-based administration UI is huge help to those who are unfamiliar or uncomfortable with these concepts. Grav has a flexible administration plugin that can be used in these cases, and the forms within it can be extended and modified with the use of YAML files called Blueprints.

A blueprint defines a form, and in the case of our custom features page, we want to add a new tab to house the list of features. This can be done by adding a new features.yaml file the blueprints/ folder of the Antimatter theme.

This basically tells the admin what the form for the feature template should look like in order to save the data appropriately in the features.md frontmatter. Below is an example of the blueprint file:

title: Features
@extends: 
    type: default
    context: blueprints://pages 

form:
  fields:
    tabs:
      fields:
        features:
          type: tab
          title: Features
          fields:
            header.features:
              name: features
              type: list
              label: Features

              fields:
                .title:
                  type: text
                  label: Title
                .subtitle:
                  type: text
                  label: Subtitle
                .icon:              
                  type: text
                  label: Icon

If you look over this file, you will discover it's very readable. In essence it simply extends the default.yaml blueprint that is provided by Grav. Then it adds a new tab with title fetaures. In that tab is a field of type list and that list contains a set of text fields for the title, subtitle and icon. After saving this file you will be able to view, edit and add new features via the admin panel:

That's it! You're now ready to hit the ground running with Grav. If you are interested in finding out more, or would like to learn more about how Grav works, you can check out Grav's detailed documentation.

Djamil Legato

About Djamil Legato

Djamil is an avid lover of technology with a passion for keeping up with the e latest and greatest solutions. He's a core developer of MooTools, and currently serves as Lead Developer for RocketTheme. He is directly involved with several open source projects including Grav and Gantry.

Recent Features

  • By
    5 Awesome New Mozilla Technologies You&#8217;ve Never Heard Of

    My trip to Mozilla Summit 2013 was incredible.  I've spent so much time focusing on my project that I had lost sight of all of the great work Mozillians were putting out.  MozSummit provided the perfect reminder of how brilliant my colleagues are and how much...

  • By
    Serving Fonts from CDN

    For maximum performance, we all know we must put our assets on CDN (another domain).  Along with those assets are custom web fonts.  Unfortunately custom web fonts via CDN (or any cross-domain font request) don't work in Firefox or Internet Explorer (correctly so, by spec) though...

Incredible Demos

Discussion

  1. Djamil, this is very well written. With your permission, I would like to include some of this for our students

    • Djamil

      Of course! No problem at all, feel free to join our Gitter chat also, if you have any questions.

  2. Alain

    I dont know if it’s a typo or older version of GRAV you used, but features.yaml works only with follow code:

    title: Features
    '@extends':
        type: default
        context: blueprints://pages
    
    form:
      fields:
        tabs:
          type: tabs
          active: 1
    
          fields:
            features:
              type: tab
              title: Features
              fields:
                header.features:
                  name: features
                  type: list
                  label: Features
    
                  fields:
                    .title:
                      type: text
                      label: Title
                    .subtitle:
                      type: text
                      label: Subtitle
                    .icon:              
                      type: text
                      label: Icon
    
  3. I added the features.yaml but didn’t see the tab appear.

    • Alain

      Just clear caches :-)

  4. Tom Conway

    After finding out about Grav from a post on the Rosehosting blog, i decided to try it.

    I must admin, I’m into unknown territory. I know jack shit about this platform.
    Stumbling upon your article is like a revelation to me. Many thanks for this how to.
    Keep up the good work.

  5. I know this is an old article but thanks so much, I’m just moving from Drupal to Grav for smaller site builds and this is the clearest explanation I have found on how to add form fields to the admin and display them on the site.

    I am now able to add per page banner slideshow to the site using the admin with list items for each slide and display a different banner on each page.

    Thanks again, saved me a lot of time!

    Richard

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!