Create a Custom Collection with Eleventy

Posted on  • tagged with #eleventy#nunjucks#html

If you've built sites using Eleventy before, you're probably familiar with collections. Collections are a great feature to show blog posts on your site. If your posts are written inside of markdown files, you can give each post the tags key as front matter data to create a collection.

Front matter in 11ty is placed inside opening and closing document separators --- and uses YAML syntax. Two markdown files post-one.md and post-two.md will be the blog posts contained in the posts collection.

Filename: post-one.md
---
title: Blog post one
permalink: "/posts/{{ title | slug }}"
tags: posts
---
Some content in post one
Filename: post-two.md
---
title: Blog post two
permalink: "/posts/{{ title | slug }}"
tags: posts
---
Some content in post two

You might have noticed a permalink key in the front matter data. Eleventy's permalink does some cool stuff to make sure that "Cool URIs don't change". You can use the permalink key to remap a templates output to a path other than the default inputPath. The output from setting a permalink will leave off the file extension.

The two markdown files would be written to the _site output as:

/posts/blog-post-one/
/posts/blog-post-two/

Using the slug filter works nicely to slugify your posts title key. The above permalink could also be written as permalink: "/posts/blog-post-two/" if you wanted to manually write the equivalent of {{ title | slug }}.

Accessing Collection Data

Now that both of the blog posts have been given the posts tag. They can be easily accessed from the posts collection in the following way using a Nunjucks for loop.

{% for post in collections.posts %}
<a href="{{ page.url }}">{{ post.data.title }}</a>
{% endfor %}

This would iterate over the posts collection and access the front matter data title to create a link to each blog post.

<a href="/posts/blog-post-one/">Blog post one</a>
<a href="/posts/blog-post-two/">Blog post two</a>

If you wanted to show the markdown from blog posts in another template or layout file, you can use {{ content | safe }}.

Handling multiple tags

One way to create a new collection is simply by giving a .md file a new tag within the tags key. This method has been demonstrated above to access the posts collection.

When you have multiple tags on a blog post, such as html, css, js. You will add each tag to the tags key as a list of values.

---
tags:
- html
- css
- js
---

This is where creating a custom collection comes in handy. Instead of including the posts tag in the tags list for every blog post (which might be repetitive), just create a custom collection with the markdown files from /posts/ inside the .eleventy.js file. This way you can omit posts from the tags list within front matter data.

Create Custom Collections

All blog posts in this article are saved as .md files in the /posts/ directory. To create a custom collection, navigate to .eleventy.js. You will utilize the first argument of the config function eleventyConfig to call the API and use addCollection to create a new custom collection.

You can add the markdown files within /posts/ to the new collection using getFilteredByGlob(glob), which will match an arbitrary glob or array of globs against the input file's full path (inputPath).

Filename: .eleventy.js
module.exports = function(eleventyConfig) {
// Creates custom collection "myPosts"
eleventyConfig.addCollection("myPosts", function(collection) {
return collection.getFilteredByGlob("/posts/*.md");
});
}

Now a custom collection called myPosts has been created which contains all the markdown files in /posts/. You can access this custom collection just like a regular collection.

{% for article in collections.myPosts %}
<h2>{{ article.data.title }}</h2>
{% endfor %}

Another useful method is getFilteredByTags(tags) which will retrieve any content that includes all of the tags passed in.

eleventyConfig.addCollection("web", function(collection) {
return collection.getFilteredByTags("html", "css", "js");
});

Filter Recent Posts

If you wanted to dedicate a section of the page for some of your most recent blog posts. You could create a custom sorted collection and perform a slice array operation to filter the number of recent posts.

eleventyConfig.addCollection("recentPosts", function(collection) {
return collection.getAllSorted().reverse().slice(0, 3);
});

Conclusion

Custom collections along with the ability to build powerful shortcodes and filters in .eleventy.js using the configuration API is one of the main reasons why #eleventy rocks!