Jekyll: How to write a Filter
Officially, filters and tags are plugins so they go into the jekyll-root/_plugins
directory. Once again, no _config.yml
modifications necessary (in the version of Jekyll (3.7.3) that I was using) to enable things.
This is where I admit that I don’t really know how to program Ruby (or Liquid). That said, I have been a programmer for 40 years, although the last 10 have rarely needed more than HTML, so I’m rusty as hell, but programming languages are programming languages (hubris!?) and Google will tell me the extra details I need to know. To get started, in Ruby we don’t need to declare variables before we start using them, Ruby is very white space (indent) sensitive, and getting variable values in a string is done by "#{variable}"
Now, I’m going to try to duplicate what I’ve already gotten working as an include function. This will be Ruby so jekyll-root/_plugins/filename.rb
Changes to plugins requires a full restart of your Jekyll instance, unlike includes where you can just fiddle and reload the page in your browser to see your progress.
It turns out that filters (Ruby?) don’t like blank parameters. If it is possible that a parameter might be there, and it is not then Ruby will not compile/Jekyll will not restart. Even if you test for undefined variables before using them, Ruby balks. So, instead of one include, I ended up with four filters.
They are called like so:
{{ "recordKey" | canlink }}
{{ "recordKey" | canlinka: "anchor text" }}
{{ "recordKey" | canlinkt: "title text=" }}
{{ "recordKey" | canlinkat: "anchor text", "title text" }}
I don’t remember if I needed the module Jekyll
right from the beginning or if I added it later, but it doesn’t hurt anything so…
######################################################################
# custom liquid *filter* to generate canonical links based on
# _data/links.json
######################################################################
module Jekyll
module LinkMunge
# set anchor text
def anch(avar, adat, key, url)
avar = "error: URL for #{key} not set" unless url
if avar != ""
return avar
elsif adat
return adat
else
return key
end
end
# set title text
def titl(tvar, tdat)
if tvar != ""
return ' title="' + tvar + '"'
elsif tdat
' title="' + tdat + '"'
end
end
# create a link based solely on the json record
def canlink(key)
site = @context.registers[:site] # the incantation required to access the site data
linkey = site.data["links"][key] # getting to my specific links.json data record
if linkey
url = linkey["url"]
anchor = anch("", linkey["anchor"], key, url)
titletext = titl("", linkey["title"])
# no "return" or print needed. The following line is the output of the <strong>filter</strong>
"<a href=\"#{ url }\"#{titletext }>#{ anchor }</a>"
else
"*error: link for #{ key } not found*"
end
end
# create a link with user defined anchor text override
def canlinka(key, anchor)
site = @context.registers[:site]
linkey = site.data["links"][key]
if linkey
url = linkey["url"]
anchor = anch(anchor, linkey["anchor"], key, url)
titletext = titl("", linkey["title"])
"<a href=\"#{ url }\"#{titletext }>#{ anchor }</a>"
else
"*error: link for #{ key } not found*"
end
end
# create a link with user defined title text override
def canlinkt(key, title)
site = @context.registers[:site]
linkey = site.data["links"][key]
if linkey
url = linkey["url"]
anchor = anch("", linkey["anchor"], key, url)
titletext = titl(title, linkey["title"])
"<a href=\"#{ url }\"#{titletext }>#{ anchor }</a>"
else
"*error: link for #{ key } not found*"
end
end
# create a link with user defined anchor and title text overrides
def canlinkat(key, anchor, title)
site = @context.registers[:site]
linkey = site.data["links"][key]
if linkey
url = linkey["url"]
anchor = anch(anchor, linkey["anchor"], key, url)
titletext = titl(title, linkey["title"])
"<a href=\"#{url}\"#{titletext}>#{anchor}</a>"
else
"*error: link for #{ key } not found*"
end
end
end # LinkMunge module
end # Jekyll module
Liquid::Template.register_filter(Jekyll::LinkMunge) # this is all you need to start using your filters, no _config.yml stuff required
Trading elegance of implementation (includes) for (sort of!) elegance of use (filters).
Let’s see how it goes with tags.