Skip to content

Commit

Permalink
updates post by year logic (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
simpixelated authored Mar 13, 2024
1 parent d6e0c2c commit 2247531
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 54 deletions.
13 changes: 0 additions & 13 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,6 @@ module.exports = function (eleventyConfig) {

// custom collections
eleventyConfig.addCollection("tagList", getAllTags)
// thanks to https://github.com/11ty/eleventy/issues/1284#issuecomment-1026679407
eleventyConfig.addCollection("postsByYear", collection => {
const posts = collection.getFilteredByTag("posts").reverse()
const years = posts.map(post => post.date.getFullYear())
const uniqueYears = [...new Set(years)]
const postsByYear = uniqueYears.reduce((prev, year) => {
const filteredPosts = posts.filter(
post => post.date.getFullYear() === year
)
return [...prev, [year, filteredPosts]]
}, [])
return postsByYear
})

// template helpers (shortcodes and filters)
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`)
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## 2.3.4 - 2024-03-13

### Changed

- switched to simpler [posts by year logic](src/posts/group-posts-by-year-in-eleventy-js.md)

## 2.3.3 - 2024-03-03

### Changed
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simpixelated.com",
"version": "2.3.3",
"version": "2.3.4",
"description": "personal website and blog of Jordan Kohl (simpixelated)",
"main": ".eleventy.js",
"author": "Jordan Kohl",
Expand Down
4 changes: 2 additions & 2 deletions src/blog.njk
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ layout: base.njk
<a href="/tag">View all tags</a>
</header>

{% for year, posts in collections.postsByYear %}
{% for year, posts in collections.posts | groupby("data.year") | dictsort | reverse %}
<h4>{{ year }}</h4>
<ul>
{% for post in posts %}
{% for post in posts | reverse %}
{% set tags = post.data.tags | exclude('posts') %}
<li>
<a href="{{ post.url }}">{{ post.data.title }}</a><br />
Expand Down
76 changes: 38 additions & 38 deletions src/posts/group-posts-by-year-in-eleventy-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,31 @@ tags:
- development
---

I tend to sporadically publish blog posts. I'll do a burst of content for a few months, then kind of sputter out for awhile (sometimes years). Because of this inconsistent schedule, it makes more sense to group my blog posts by year. That makes it more obvious that two consecutive blog posts might be separated by a long break. It also just feels like a more natural grouping.
I tend to sporadically publish blog posts. I'll do a burst of content for a few months, then kind of sputter out for awhile (sometimes years). Because of this inconsistent schedule, it makes more sense to group my blog posts by year. That makes it more obvious that two consecutive blog posts might be separated by a long break.

There are probably many different ways to accomplish this, but the way that worked for me was creating a custom collection in Eleventy:
Since I want the newest content at the top, I want the years reverse chronological order and the posts within each year also in reverse chronological order. From the beginning, I had hoped to accomplish this with just Nunjuck's filters and I thought it would be as simple as this:

```jsx
eleventyConfig.addCollection("postsByYear", collection => {
const posts = collection.getFilteredByTag("posts").reverse()
const years = posts.map(post => post.date.getFullYear())
const uniqueYears = [...new Set(years)]
const postsByYear = uniqueYears.reduce((prev, year) => {
const filteredPosts = posts.filter(post => post.date.getFullYear() === year)
return [...prev, [year, filteredPosts]]
}, [])
return postsByYear
})
{% raw %}

```jinja2
{% for year, posts in collections.posts | groupby("data.year") | reverse %}
```

Then it gets used on my blog page like so:
{% endraw %}

But no matter what, I couldn't make it work. Turns out [Christopher Kirk-Nielsen](https://chriskirknielsen.com/blog/group-posts-by-year-with-nunjucks-in-eleventy/) also ran into and eventually solved this problem:

> The only issue with this approach is that the year keys we get are sorted in ascending order, and throwing in a reverse before grouping does nothing, while adding reverse at the end breaks object entirely — it only works for strings and arrays, and sort doesn’t operate on objects. So while we see posts within each year sorted from newest to oldest thanks to reverse in the second for-loop, the years themselves are sorted from oldest to newest.
It turns out the answer is to use `dictsort` on the `year` object prior to reversing it. The end result is a fairly simple for loop in my Nunjucks template:

{% raw %}

```jinja2
{% for year, posts in collections.postsByYear %}
{% for year, posts in collections.posts | groupby("data.year") | dictsort | reverse %}
<h4>{{ year }}</h4>
<ul>
{% for post in posts %}
{% for post in posts | reverse %}
{% set tags = post.data.tags | exclude('posts') %}
<li>
<a href="{{ post.url }}">{{ post.data.title }}</a><br />
Expand All @@ -45,13 +44,9 @@ Then it gets used on my blog page like so:

{% endraw %}

That’s it! Note: the `exclude('posts')` bit prevents "posts" from showing in the tag list for every post (since all posts have this tag, in addition to whatever custom tags you've added).

### Alternatives Considered

While I wanted to accomplish this with just Nunjucks filters, I couldn’t figure out how to sort the years correctly. No matter what I did, it wanted to go in descending order. I haven’t looked at it since I first tried this last year. Perhaps it was a bug? But more likely it was my inability to understand the manual. I’ll include what I tried here in case someone else runs into a similar problem:
Note: there are two uses of `reverse` above: one for the `year` object and one for `posts`. Also, the `exclude('posts')` bit prevents "posts" from showing in the tag list for every post (since all posts have this tag, in addition to whatever custom tags you've added).

First I added a custom attribute ([computed data](https://www.11ty.dev/docs/data-computed/)) to my posts like:
The above also depends on a `year` custom attribute in my [computed data](https://www.11ty.dev/docs/data-computed/):

```jsx
module.exports = {
Expand All @@ -61,33 +56,38 @@ module.exports = {
}
```

Then I used it in the templates like so:
### Alternatives Considered

Prior to discovering the `dictsort` filter, a custom Eleventy collection was how I accomplished this. It's more complex, but still works the same:

```jsx
eleventyConfig.addCollection("postsByYear", collection => {
const posts = collection.getFilteredByTag("posts").reverse()
const years = posts.map(post => post.date.getFullYear())
const uniqueYears = [...new Set(years)]
const postsByYear = uniqueYears.reduce((prev, year) => {
const filteredPosts = posts.filter(post => post.date.getFullYear() === year)
return [...prev, [year, filteredPosts]]
}, [])
return postsByYear
})
```

Then it gets used on my blog page, just like the simpler solution above:

{% raw %}

```jinja2
{% for year, posts in collections.posts | groupby("data.year") %}
<h4>{{ year }}</h4>
<ul>
{% for post in posts | reverse %}
{% set tags = post.data.tags | exclude('posts') %}
<li>
<a href="{{ post.url }}">{{ post.data.title }} {{ post.data.year }}</a><br />
<small class="post-meta"><time>{{ post.data.date | postDate }}</time>{% if tags | length %} - {% include "tag-list.html" %}{% endif %}</small>
</li>
{% endfor %}
</ul>
{% endfor %}
{% for year, posts in collections.postsByYear %}
```

{% endraw %}

However this didn’t work. It kept showing the blogs in descending order. Eventually I gave up and just used the custom collection at the start of this post.

### Other Posts That Inspired Me
### Other posts that inspired me

- [Group posts by year in Eleventy](https://darekkay.com/blog/eleventy-group-posts-by-year/)
- [How do you list all posts grouped by year? 11ty/eleventy#1284 (comment)](https://github.com/11ty/eleventy/issues/1284#issuecomment-1026679407)
- [Comment by Reddit user five35](https://www.reddit.com/r/eleventy/comments/1bds2q2/comment/kup0d9u/)

### Leave a comment

Expand Down
1 change: 1 addition & 0 deletions src/posts/posts.11tydata.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = function () {
data.title
)}-social-card.png`
},
year: data => new Date(data.date).getFullYear(),
},
}

Expand Down

0 comments on commit 2247531

Please sign in to comment.