Build a Blog

Download and install locally the Blog Site skeleton from, or at least have ready the repository to check. This is a sample site that uses the Antimatter theme. Having an up and running Grav site that already works with a Blog structure will surely give a hand if you’re stuck or you don’t understand what to do next.

Check your theme provides the Blog and Item page templates

Let’s start simple: choose a theme that already provides a blog page template. For example Antimatter, TwentyFifteen, Deliver, Lingonberry, Afterburner2, and many others. How do you check if your theme already provides a blog page template? Go in the /user/themes/[yourtheme]/templates folder, and check the existence of the blog.html.twig and item.html.twig files.

If you’ve already chosen a theme, and your theme does not come with those files, then copy them from Antimatter: (If you copy the files from this theme, you will also need the two partials named blog_item.html.twig and sidebar.html.twig. These must be placed in the templates/partials folder.)

You might need to tweak the markup to suit your theme. The best option if you’re just starting out if to use a theme that already comes with them.

Create the blog pages structure

There are different ways to structure the pages. The default and simpler one is to have a parent page, of type Blog, and have child pages for the blog posts.

With the Admin Plugin

Create a page of type Blog. That page is the blog "Homepage", with the blog posts list.

Create one or more child pages of type Item. Those are the blog posts.


Go in your pages/ folder, create a page (change the number to reflect your menu structure), add a file in it. In this file, add this content:

    items: '@self.children'

This tells Grav to iterate over the subpages (the blog posts).

Create a subfolder for each post you want to add, and add in each folder an file, with the content of the blog post.


The structure explained above will create blog posts with /blog/ in the URL. This might not be what you need. For example: If a blog is all you have on your site, and the blog posts listing is the home page. In these cases, you would just want your root domain to access this content rather than referring visitors to a child directory.

In this case, in system.yaml (System configuration in Admin) set home.hide_in_urls option (Hide Home in URLs in Admin) to true.

The inner workings

You might want to know how this works. The Blog template, the content of the blog.html.twig file provided in the theme templates/ folder, simply iterates over its child pages.

In its simplest way:

{% set collection = page.collection() %}

{% for child in collection %}
        {% include 'partials/blog_item.html.twig' with {'blog':page, 'page':child, 'truncate':true} %}
{% endfor %}

page.collection() by default picks the content.items property of the page YAML frontmatter, and returns an array containing the elements that match that definition.

If the page contains:

    items: '@self.children'

then collection will be the array of the subpages of the current page.

In this case the theme includes the partial partials/blog_item.html.twig, responsible for rendering the single blog post, and passes it the child object containing the actual blog post to render.

To learn more

Found errors? Think you can improve this documentation? Simply click the Edit link at the top of the page, and then the icon on Github to make your changes.