David Scott
David Scott

Reputation: 886

Jekyll Internal Post Links

This is a pretty niche problem, but... I run a blog that runs on Jekyll and I post very regularly. To keep my editing sane I regularly archive posts, and those archived posts get a pretty strict structure. But, I go a full year before archiving.

Where this hurts is in links to other posts. I used to be able to absolutely reference the file name (per jekyll markdown internal links), but this appears to be being deprecated:

Deprecation: A call to '{% post_url 2018-09-06-peppermint %}' did not match a post using the new matching method of checking name (path-date-slug) equality. Please make sure that you change this tag to match the post's name exactly.

Now, if I have to include the full path to the file, then when I archive my posts for the year I have to parse all of the posts for the entire year and update any links between them to include the new file path for their archived location, defeating the point of using this tool at all. A direct link to the page would actually be better, given that I change my URL structure less often.

Is there a better solution for internal links that doesn't depend on the file structure, allowing a file to be moved without having to update every link to that file?

Example File structure:

 _posts
   -2018
     -post1
     -post2
     -etc
   -Archive
     -2017
     -2016

If there's no better answer, I may just have to go back to using absolute external links.

Upvotes: 5

Views: 1072

Answers (2)

Martin
Martin

Reputation: 197

It is possible to create a custom tag that instead of using "path-date-slug" uses "date-slug" as a matching method. If we call this new tag post_url_short, you will use it like this:

<!-- link to post _posts/subdir/2018-09-06-peppermint.md -->
{% post_url_short 2018-09-06-peppermint %}

To use the post_url_short, you'll need to add this file to your jekyll project:

# _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)

I'm not a Ruby programmer, so comments are welcome.

Upvotes: 0

Mr. Hugo
Mr. Hugo

Reputation: 12582

Solution 1. Use your own include

Create an post_url.html file and write this:

{% include post_url.html slug="2018-09-06-peppermint" %}

The include (called post_url.html) should find the post with the right slug and echo the link, like this:

{% assign link = site.posts | where:'slug',include.slug %}
<a href="{{ link[0].url }}">{{ link[0].title }}</a>

Solution 2. Search and replace

You have to parse posts? A simple search and replace on all files, looking for (/2018/ and replace with (/Archive/2018/ should do the trick (if you use markdown links). This should take just a few seconds.

Upvotes: 3

Related Questions