Yearly archive for posts
Publii does not contain archives by date, but it is possible to create a helper which will create such functionality. To implement such feature we need two simple custom helpers.
Helpers source code
We need to built two helpers:
- first will be used to generate years
- second will retrieve posts from a specific year
Create the helpers.js
file and put the following code in it (if you have the helpers.js
file in your theme - please copy only the yearsInArchive
and getPostsByYear
functions from the below code):
let themeHelpers = {
yearsInArchive: function(startYear) {
let years = [];
let currentYear = new Date().getFullYear();
for (let i = currentYear; i >= startYear; i--) {
years.push(i);
}
return years;
},
getPostsByYear: function(posts, year) {
return posts.filter(post => new Date(post.createdAt).getFullYear() === year);
}
};
module.exports = themeHelpers;
The yearsInArchive
helper returns every year from the given date. So for example for value 2016 it will return an array with the following values: 2021, 2020, 2019, 2018, 2017, 2016. You can reverse the order of years (if you want to use ascending order) by adding:
years.reverse();
Directly before line:
return years;
We will need this array to generate lists of posts grouped by years and using the creation date. If you need to group your posts by the last modification date - just replace post.createdAt
with post.modifiedAt
.
How to create yearly archive
You need to create post template and as its content please use the following code in place of the normal post content:
<h2>Blog archive</h2>
<ol>
{{#each (yearsInArchive 2016) }}
<li>
<h3>{{ this }}</h3>
{{#if (getPostsByYear @website.contentStructure.posts this)}}
<ol>
{{#each (getPostsByYear @website.contentStructure.posts this)}}
<li>{{title}} - {{date createdAt 'YYYY-MM-DDTHH:mm'}}</li>
{{/each}}
</ol>
{{else}}
<strong>No posts</strong>
{{/if}}
</li>
{{/each}}
</ol>
The above code requires some explanation:
- In the <ol> element we generate archive using the yearsInArchive helper. Please notice, that we use Handlebars subexpressions
- To display the year, we are using the
{{ this }}
syntax - it will return years in the descending order. - To provide list of posts, we are using @website.contentStructure.posts global variable - it contains all posts of your website. Please remember - the contentStructure must be enabled in your theme.
- Also we support a case when there are no posts in a specific year. Then the No posts text is displayed.
Variant which displays only years with posts (it skips years without posts):
<h2>Blog archive</h2>
<ol>
{{#each (yearsInArchive 2016) }}
<li>
{{#if (getPostsByYear @website.contentStructure.posts this)}}
<h3>{{ this }}</h3>
<ol>
{{#each (getPostsByYear @website.contentStructure.posts this)}}
<li>{{title}} - {{date createdAt 'YYYY-MM-DDTHH:mm'}}</li>
{{/each}}
</ol>
{{/if}}
</li>
{{/each}}
</ol>
In the above code we have removed No posts handling and we have moved year display inside condition which checks if some posts are available.
Please remember - you can use any Post item elements inside the #each
loop which uses the getPostsByYear helper.
Summary
As you can see - creating yearly archive is not a complex task in Publii. It is also worth considering to create separate page for every year if you have a long list of posts. Then the additional loop with use of the yearsInArchive
helper won't be required.