Mike Slinn

Plugins Are Not The Only Way To Maintain a Jekyll Website

Published 2022-03-26.
Time to read: 1 minutes.

This page is part of the jekyll collection.

I wanted to put up a page that showed articles, ordered by most recently modified. After working on the problem for a bit, I realized that if every page had a last_modified_at entry in front matter the problem would be much easier.

So I wrote a Ruby program, not a Jekyll plugin, and processed each post in less than two shakes of a lamb’s tail.

#!/usr/bin/env ruby

# Add date: and last_modified_at: fields to front matter for posts that do not have them.

# @return number of lines between the --- lines, which demark front matter
def front_matter_length(contents)
  return nil unless contents[0].start_with? "---"

  contents[1..].find_index { |line| line.start_with? "---" }
end

# @return date from front matter, or the filename if front matter entry is not present
def read_date(front_matter)
  date_line = front_matter
                .find { |line| line.start_with? "date:" }
  return nil unless date_line

  date_line.delete_prefix("date:")
             .strip
end

def process(directory)
  Dir[directory].each do |file_name|
    contents = File.readlines(file_name, chomp: true)
    last_front = front_matter_length contents
    next unless last_front

    front_matter = contents[1..last_front]
    date = read_date front_matter
    unless date
      date = File.basename(file_name)[0..9]
      contents.insert(last_front + 1, "date: #{date}") # insert before 2nd ---
      last_front += 1
      must_save = true
    end

    modified_at = front_matter.find { |line| line.start_with? "last_modified_at:" }
    unless modified_at
      contents.insert(last_front + 1, "last_modified_at: #{date}") # insert before 2nd ---
      must_save = true
    end

    File.write(file_name, contents.join("\n")) if must_save
  end
end

[
  "collections/_posts/**/*.html",
  "collections/_drafts/**/*.html",
].each { |dir| process dir }

If you need to do something similar, you could modify the last bit of the program, and type in the paths to your Jekyll website posts.

Modified Ruby code
[
  "collections/_posts/**/*.html",
  "collections/_drafts/**/*.html",
].each { |dir| process dir }

BTW, I did not convert front matter to YAML because I did not want to change it in any way. Transforming it from text to YAML, and then transforming it back to text again almost certainly would alter the text. I did not want to disturb what was there before, so I just considered front matter as text, and it all went very nicely.

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.