Preface
Goal: Apply Tag Collection based on Zach’s Code.
Source Code
This article use tutor-03 theme. We will create it step by step.
1: About Collections
Freedom
Just like most SSG, eleventy
can show article index,
by chronology, or by tags.
Those content can be queried, filtered, and finally shown,
as the site author decide to.
Eleventy arrange this content list with collections
.
Eleventy comes with built in tag
collection.
This way, eleventy
can create tag based list manually.
Although first this looks thougher than most common SSG,
this eleventy approach also free you from SSG limitation.
Because you can freely make your own kind of collections
Official Documentation
Reference
2: Archive
Before we go on into custom collections, consider refresh our memory to our simple default collections.
Reference
Page Content: pages/archive
---
layout : archive
title : Archive
permalink : /pages/
eleventyExcludeFromCollections: true
---
<ul>
{%- for post in collections.all | reverse -%}
<li>
<a href="{{ post.url | url }}">
{{ post.data.title }}</a>
</li>
{%- endfor -%}
</ul>
This time this content wears archive
layout.
Layout: Nunjucks Archive
Template inheritance in nunjucks
,
start with the word extends
.
{% extends "layouts/base.njk" %}
{% block main %}
<h2>{{ title or metadata.title }}</h2>
<strong>This is an archive kind layout.</strong>
<br/>
{{ content | safe }}
{% endblock %}
Render: Browser
Now you can see the result in the browser.
The Loop
The loop is as simple as all collections, but shown backward:
{% for post in collections.all | reverse %}
...
{% endfor %}
The word reverse
here is builtin filter from nunjucks
.
3: Keys in Collections
The Riddle?
What other keys are inside collections?
So what is this collections.all
after all?
Or let me rephrase with better question.
What’s inside these collections?
.eleventy.js
To answer this we need other other filter
in .eleventy.js
.
// values Filter: MDN web docs
eleventyConfig.addNunjucksFilter("keys", function(array) {
return Object.keys(array);
});
Page Content: pages/keys
And apply to views
<p>collections: [{{ collections | keys | join(", ") }}]</p>
Render: Browser
Now you can see the result in the browser.
collections: [all, subtitle, story, tagList]
It turned out that collections
has four members
-
all (default)
-
subtitle (tag)
-
story (tag)
-
tagList (manual collections)
Manual
We have this tagList
from manual collection
in .eleventy.js
.
// Copy paste from Zach
eleventyConfig.addCollection("tagList",
require("./views/_11ty/getTagList"));
Tags
And we have these subtitle
and story
from frontmatter.
layout : post
title : Every Day
date : 2015-10-03 08:08:15
slug : every-day
tags : ['subtitle', 'story']
4: Set (ECMAScript 2015)
Before we get down to generate each tag page, consider this simple javascript.
Reference
The Songs Script
This script utilize Set
introduced in ECMAScript 2015
,
to collect tag names.
And convert the the set
output back simple array
.
songs = [
{ title: "Cantaloupe Island", tags: ["60s", "jazz"] },
{ title: "Let it Be", tags: ["60s", "rock"] },
{ title: "Knockin' on Heaven's Door", tags: ["70s", "rock"] },
{ title: "Emotion", tags: ["70s", "pop"] },
{ title: "The River" }
];
let tagSet = new Set();
// using set feature to collect tag names
songs.forEach(function(song) {
if( "tags" in song ) {
let tags = song.tags;
console.log(tags);
for (const tag of tags) {
tagSet.add(tag);
}
}
});
console.log(tagSet);
// normalize to array
let alltags = [...tagSet];
console.log(alltags);
Running in CLI
Run this script, and you will get
$ node songs.js
[ '60s', 'jazz' ]
[ '60s', 'rock' ]
[ '70s', 'rock' ]
[ '70s', 'pop' ]
Set(5) { '60s', 'jazz', 'rock', '70s', 'pop' }
[ '60s', 'jazz', 'rock', '70s', 'pop' ]
This way, you can apply to 11ty
tags in frontmatter.
Page Content: every-day.md
---
layout : post
title : Every Day
date : 2015-10-03 08:08:15
slug : every-day
tags : ['subtitle', 'story']
---
I've been thinking about this
over and over and over.
<!-- more -->
I mean, really, truly,
imagine it.
Have a look at this line in frontmatter:
tags : ['subtitle', 'story']
These tags
in frontmatter will be,
compiled internally by 11ty
into collections
.
So later, you can access directly as below:
{% set postslist = collections[ tag ] %}
5: Collections: getTagList.js
Consider apply those script above to eleventy.
.eleventy.js
We are going to add this script manually as a collections
.
// Copy paste from Zach
eleventyConfig.addCollection("tagList",
require("./views/_11ty/getTagList"));
Complete Script
You can use complete script from here:
Simpler Script
For explanation purpose, I stripped down the script.
The underscore in _11ty
, means this folder is not a website content,
and won’t be rendered. Very useful for utility folder.
module.exports = function(collection) {
let tagSet = new Set();
collection.getAll().forEach(function(item) {
if( "tags" in item.data ) {
let tags = item.data.tags;
for (const tag of tags) {
tagSet.add(tag);
}
}
});
return [...tagSet];
};
This script is very similar to previous CLI
script above.
6: Loop: All Tags
With the result of above tagList
collections,
we can just show the tag,
just like we display the index page.
Page Content: tags.html
---
layout : tags
title : List of Tags
eleventyExcludeFromCollections: true
---
<ul>
{% for tag in collections.tagList %}
<li>
{% set tagUrl %}/tags/{{ tag }}/{% endset %}
<a href="{{ tagUrl | url }}" class="tag">{{ tag }}</a>
</li>
{%- endfor -%}
</ul>
Layout: Nunjucks Tags
Nothing special yet about this layout.
Template inheritance in nunjucks
,
start with the word extends
.
{% extends "layouts/base.njk" %}
{% block main %}
<h2>{{ title or metadata.title }}</h2>
<strong>This is a tags kind layout.</strong>
<br/>
{{ content | safe }}
{% endblock %}
Render: Browser
Now you can see the result in the browser.
The Loop
The loop is as simple as all collections, but shown backward:
{% for tag in collections.tagList %}
...
{% endfor %}
We use manually crafted taglist
collection.
7: Pagination: Tag Name
The last page is a little bit hard, because this page utilize pagination. And pagination in eleventy have weird approach.
This page will generate many pages. One page for each tag name.
Reference
A brilliant approach.
Paginated Content: tag-name.html
Pagination also can be used to manage tag
names.
---
layout : tag-name
eleventyExcludeFromCollections: true
pagination:
data: collections
size: 1
alias: tag
filter: tagList
permalink: /tags/{{ tag }}/
---
Directory Tree
This arrangement will automatically generate tag pages as below:
Notice there is also all
tags.
Filter
I add filter: tagList
,
to avoid tagList/index.html
comes out in the tree.
8: Render Data
Beside permalink
, we can render any data, with pagination
.
For example we can change the title to reflect current tag.
---
...
permalink: /tags/{{ tag }}/
renderData:
title: Tagged “{{ tag }}”
---
We can use this render data in layout.
Layout: Nunjucks Tag Name
Beware of the difference.
This layout use renderData.title
.
{% extends "layouts/base.njk" %}
{% block main %}
<h2>{{ renderData.title or title or metadata.title }}</h2>
<strong>This is a tag-name kind layout.</strong>
<br/>
{{ content | safe }}
{% endblock %}
Layout: Nunjucks Head
Also use it in head.
<title>{{ renderData.title or title or metadata.title }}</title>
<link href="/assets/favicon.ico"
rel="shortcut icon" type="image/x-icon" />
9: Using Collections Object
We still have to output the post for each tag.
Reference
The code is almost verbatim copy, from this link below.
Paginated Content: tag-name.html
---
layout : tag-name
eleventyExcludeFromCollections: true
pagination:
data: collections
size: 1
alias: tag
permalink: /tags/{{ tag }}/
renderData:
title: Tagged “{{ tag }}”
---
{% set postslist = collections[ tag ] %}
<ul>
{%- for post in postslist -%}
<li>
<a href="{{ post.url | url }}">
{{ post.data.title }}</a>
</li>
{%- endfor -%}
</ul>
<p>List of <a href="{{ '/tags/' | url }}">all tags</a>.</p>
Render: Browser
Now you can see the result in the browser.
The Loop
The loop is just about using collections.
{%- for post in collections[ tag ] -%}
...
{%- endfor -%}
Wait?
Where is this collections[ tag ]
comes from???
Explanation
The official 11ty
site said:
First up notice how we’re pointing our pagination
to iterate over collections,
which is an object keyed with tag names pointing
to the collection of content containing that tag.
This will be clear in this reference:
Allright, the hardest part is over. The next chapter should be easy.
What is Next ?
Consider continue reading [ Eleventy - Bulma - CSS Intro ]. We need to revamp the looks of this good eleventy, with proper stylesheet.
Thank you for reading.