Extended Jekyll Date Archives

Header image for Extended Jekyll Date Archives

Making the normal date archive gem do double duty.

3 minute reading time of 653 words (inc code)

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.


Reply via email