Ramblings of General Geekery

Blog Archives in PieCrust

The question has come up a couple times already via email or Twitter, so here’s a quick recipe to write a nice looking archive page for your PieCrust blog.

There are 2 main types of blog archives: monthly archives and yearly archives. We’ll look at them one at a time after the break.

Yearly archives

This is the simplest one. Because PieCrust exposes your posts sorted by year in the blog.years template variable, you just need to loop on that with a for loop. Each object returned in the loop contains the following attributes:

  • posts: the list of posts for that year.
  • name: the name of the year (although you can also use the object itself, which is what we’ll do).

You end up with something like this:

---
layout: blog
title: Blog Archives
format: none
---
{% for y in blog.years %}
<h2>{{ y }}</h2>
<ul class="archive-list">
    {% for p in y.posts %}
    <li>
        <p>
            <a href="{{ p.url }}">{{ p.title }}</a>
            <time datetime="{{ post.date|atomdate }}">{{ p.timestamp|date('M d') }}</span>
        </p>
    </li>
    {% endfor %}
</ul>
{% endfor %}

Note how we render the date of each post with a custom format using the date filter (here using only the day and month). For more information about the date filter, check out the Twig documentation. Also, to provide a little bit of metadata, we use a time tag along with the atomdate filter, which is a handy shortcut for using the date filter specifically with an XML date format. Of course, you don’t have to keep that same markup – you can reuse the Twig logic but completely change the rest.

Monthly archives

This one is a bit more complicated. Although PieCrust also exposes your posts sorted by month in blog.months, you still need to spot changes in years so you can print a nice title or separator. To do this, we keep a variable curYear up to date with the current post’s year. If the post has a different year than the post before it, we print the new year in an h2 tag.

Each object in the blog.months has the following attributes:

  • posts: the list of posts in that month.
  • timestamp: the timestamp of the month, so you can render it to text with the |date filter.

So to get the year of each month, we use month.timestamp|date("Y"). To print the name of each month we use month.timestamp|date("F").

In the end, it goes something like this:

---
layout: blog
title: Blog Archives
format: none
---
{% set curYear = 0 %}
{% for month in blog.months %}
    {% set tempYear = month.timestamp|date("Y") %}
    {% if tempYear != curYear %}
        {% set curYear = tempYear %}
        <h2>{{curYear}}</h2>
    {% endif %}
    
    <h3>{{ month.timestamp|date("F") }}</h3>
    <ul>
    {% for post in month.posts %}
        <li>
            <a href="{{ post.url }}">{{ post.title }}</a>
            <time datetime="{{ post.date|atomdate }}">{{ post.date }}</time>
        </li>
    {% endfor %}
    </ul>
{% endfor %}

Again, feel free to keep the logic and change the markup to your liking – that’s the whole point of PieCrust!