Skip to main content

A custom collection to sort events with Eleventy

I created and update the Helsinki Pedestrians' Association's website and since we do events I wanted to be able to display upcoming events in the order they coming up in. This wasn't so straightforward, since Eleventy doesn't support a secondary date data, only the creation date.

Objectives for the custom collection

I figured that I have to make a custom collection, because I wanted to

  • sort the event posts by the event date, not the creation date
  • filter out events that have past
  • generate a "past event" banner to past events.

Front matter in a post for the Nunjucks and collection to work

Here is the front matter data for an event post:

tags:
- Event

eventDate: 2024-05-06
publishDate: 2024-04-21
---

I wanted to use the tag "Event" to pick up the relevant collection. Then I wanted the sorting of events to happen based on the eventDate data, not publishDate.

The custom collection in the configuration file

I delved into the Eleventy documentation, which isn't the clearest (to me). So, in addition I ran into somebody asking a sort of similar question on Eleventy GitHub.

From there I figured an outline that I should get to work. The finished code is next.

In the .eleventy.js (or equivalent configuration file):

eleventyConfig.addCollection("events", (collection) =>
collection
.getFilteredByTag("Event")
.filter(function (item) {
var dateToday = new Date();
if (item.data.eventDate > dateToday) {
return item;
}
})
.sort((a, b) => {
return a.data.eventDate - b.data.eventDate;
})
);
  1. I used the eleventyConfig.addCollection() function. I gave the collection name "events".

  2. Next filter the collection, so that you only get the posts tagged "Event" with .getFilteredByTag("Event").

  3. After that I make the custom filter that uses the current day's date for filtering out past events.

    • The Date() function returns the current date in this kind of format: "Thu May 09 2024 03:00:00 GMT+0300 (Eastern European summer time)". Then it gets compared to the post's eventDate with the if statement: if (item.data.eventDate > dateToday). The condition passes the upcoming event to the array.
  4. The last part .sort() sorts the array according the eventDate data rather than the default date.

Now the this filtered custom collection can be used in a template.

How to implement the custom collection in Nunjucks

The Nunjucks snippet that produces the event list or a message with the text that there are no upcoming events:

{% set nextEvents = collections.events %}

## Upcoming events ({{ nextEvents.length }})

{% if nextEvent.length == 0 %}

<div class="post-card">

<p>No upcoming events at this time!</p>

</div>
{% else %}

{% for post in nextEvents %}

{% include "partials/index-postCard.njk" %}

{% endfor %}
{% endif %}
  • Using the custom collections happens right at the start with {% set nextEvents = collections.events %}.
  • ## Upcoming events ({{ nextEvents.length }}) generates a count of upcoming events.

The rest is pretty self-explanatory use of an if statement.

This snippet produces the filtered list of events that is sorted in a way that the next upcoming event is first and the latest is in the bottom.

Important! You have to notice that the events list gets updated only when the site is built. So, either you can set up an automatic way of doing this or just let your natural build cycle filter past events out.

Updating the event with the past notice

Global data for the current date to use anywhere in the files in .eleventy.js (or equivalent configuration file):

eleventyConfig.addGlobalData("dateToday", () => new Date());

This one I have implemented in my post.njk layout right after the post's heading:

{% if eventDate < dateToday %}
<div class="alert">
<p>
<strong>This is a past event</strong> See the upcoming events on the home page.</a>.
</p>
</div>
{% endif %}

Important! This one also gets updated when it gets built.