Extended Jekyll Date Archives
Making the normal date archive gem do double duty.
As much as I like the straightforwardness of Jekyll, it is surprisingly deficient in some areas - notably, out-of-the-box archives and pagination.
If you’re able to use plugins, it’s fairly easy to rectify this with the jekyll-archives and jekyll-paginate-v2 gems, and monkey patch the two together with a third plugin paginate_archive.rb so that all the archive pages behave as you’d expect.
Shouldn’t be necessary in 2024, but there you go.
I wanted to take this setup one step further - I’ve got quite a lot of posts that have been updated years after they were originally written, and I’d prefer to have them appear in both years’ archives instead of just the latest one.
So, there’s now a fourth plugin… Starting from a direct copy of the jekyll-archives.rb file, I stripped out all the bits I didn’t need (ie. references to tags, categories, configuration etc) and extended its date_attr_hash
function to cope with my front matter:
require "jekyll"
require "jekyll-archives"
module Jekyll
class MoreArchives < Jekyll::Generator
safe true
def generate(site)
@site = site
@posts = site.posts
@archives = []
read
@site.pages.concat(@archives)
# don't overwrite the category/tag etc archives already done by jekyll-archives
@site.config["archives"] = @site.config["archives"] + @archives
end
def read
years.each do |year, y_posts|
# call jekyll-archives Archive class
@archives << Jekyll::Archives::Archive.new(@site, { :year => year }, "year", y_posts)
end
end
def years
date_attr_hash(@posts.docs, "%Y")
end
private
def date_attr_hash(posts, id)
hash = Hash.new { |hsh, key| hsh[key] = [] }
posts.each {
|post|
# do the normal date thing
hash[post.date.strftime(id)] << post
# now see if we have a second date to show the post in
if defined?(post["original_date"]) and not post["original_date"].nil?
date = post["original_date"]
# strftime doesn't like the dates I've written with HH:MM added, so parse them here
if not date.is_a?(Date)
date = Date.parse(date)
end
hash[date.strftime(id)] << post
end
}
hash.each_value {
# add uniq! to make sure each year still only has one copy of the post
|posts| posts.sort!.reverse!.uniq!
}
hash
end
end
end
Don’t forget to remove the year archives from the original jekyll-archives configuration, else you’ll get lots of duplicate permalink warnings at the least.
And now, a post originally written in 2016 and then revised 3 years later can appear in the /2016 archive as well as the /2019 archive.
This approach could be extended further, and track every time a post was updated - eg. for my various photo collection posts - but I’ll settle for the start and end pair for now.