In a previous post, I added some Ruby code to be able to update the categories of the posts by simply moving the post from one subfolder to another. This works well if there are no links between the posts, but it causes issues otherwise.

For example, before moving the editing minima post(_posts/2022-12-26-editing-minima.md) to the category subdirectory, I would refer to it from other posts using post_url liquid tag like this:

{% post_url_short 2022-12-26-editing-minima %}

Once I move the post to the subdirectory _posts/site-updates, the link reference will break (and prevent me from serving the site). This issue can be solved by updating the path in the reference - see the updated reference below.

<!-- non-convenient approach (default tag)-->
{% post_url_short site-updates/2022-12-26-editing-minima %}

The solution above is not a great solution. Even if I go through every link and update it, there is still a big issue remaining: if in the future I want to move one post from one category to another (from one subdir to another) it will be necessary to update every other post that links to the one I am moving.

What caught my attention is that Jekyll matching method “path-date-slug”, while it is very accurate, it is too much for the way my site works. I will never have two posts on the same date with the same slug, therefore if I had a tag that identified the post by matching “date-slug”, it would be good enough for me. The code below creates such a tag:

# _plugins/post_url_short_tag.rb
module Jekyll
  class PostUrlShortTag < Liquid::Tag
    def initialize(tag_name, input, tokens)
      super
      @input = input.strip
    end

    def render(context)
      puts "Executing tag 'post_url_short', input: '#{@input}'"
      # Splitting the text inputted when the tag was called (argument)
      date = @input[0...10]  # Extract the first 10 characters as date
      puts "\tDate extracted from input: '#{date}'"          
      slug = @input[11..-1]  # Extract from the 12th character to the end as slug
      puts "\tSlug extracted from input: '#{slug}'"          
      
      # We are considering slug as the text after the date in the filename of the post file.
      # If we were specifically checking the slug we would go `p.data['slug']`, but it's
      # not the case - we consider the slug the last part of the file name (in `YYYY-MM-DD-example.md`  
      # it would be `example`, ignoring the front matter). This assumes that filenames are unique.
      site = context.registers[:site]
      post = site.posts.docs.find { |p| p.date.strftime('%Y-%m-%d') == date && p.basename.split('.').first[11..-1] == slug }
      if post
        puts "\tPost found with title '#{post.data['title']}', of date '#{post.data['date']}'"
      else
        puts "\tPOST NOT FOUND"
      end
      post.url if post
    end
  end
end

Liquid::Template.register_tag('post_url_short', Jekyll::PostUrlShortTag)

Using the new tag post_url_short, I will not need to change the path of the references to a post every time I change it from one subdir to the other. See below for an example of how the new tag is used.

<!-- convenient approach (new tag) -->
{% post_url_short 2022-12-26-editing-minima %}