Reputation: 886
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
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
Reputation: 12582
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>
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