Include jekyll / liquid template data in a YAML variable?
Today I ran into a similar problem. As a solution I created the following simple Jekyll filter-plugin which allows to expand nested liquid-templates in (e.g. liquid-variables in the YAML front matter):
module Jekyll module LiquifyFilter def liquify(input) Liquid::Template.parse(input).render(@context) end endendLiquid::Template.register_filter(Jekyll::LiquifyFilter)
Filters can be added to a Jekyll site by placing them in the '_plugins' sub-directory of the site-root dir. The above code can be simply pasted into a yoursite/_plugins/liquify_filter.rb file.
After that a template like...
---layout: defaultfirst_name: Harrylast_name: Pottergreetings: Greetings {{ page.first_name }} {{ page.last_name }}!---{{ page.greetings | liquify }}
... should render some output like "Greetings Harry Potter!". The expansion works also for deeper nested structures - as long as the liquify filter is also specified on the inner liquid output-blocks. Something like {{ site.url }} works of course, too.
Update - looks like this is now available as a Ruby gem: https://github.com/gemfarmer/jekyll-liquify.
I don't believe it's possible to nest liquid variables inside YAML. At least, I haven't figure out how to do it.
One approach that will work is to use a Liquid's replace filter. Specifically, define a string that you want to use for the variable replacement (e.g. !SITE_URL!
). Then, use the replace filter to switch that to your desired Jekyll variable (e.g. site.url
) during the output. Here's a cut down .md file that behaves as expected on my jekyll 0.11 install:
---layout: postexcerpt: In the [earlier post in this series](!SITE_URL!/2013/01/12/)---{{ page.excerpt | replace: '!SITE_URL!', site.url }}
Testing that on my machine, the URL is inserted properly and then translated from markdown into an HTML link as expected. If you have more than one item to replace, you can string multiple replace calls together.
---layout: postmy_name: Alan W. Smithmulti_replace_test: 'Name: !PAGE_MY_NAME! - Site: [!SITE_URL!](!SITE_URL!)'---{{ page.multi_replace_test | replace: '!SITE_URL!', site.url | replace: '!PAGE_MY_NAME!', page.my_name }}
An important note is that you must explicitly set the site.url value. You don't get that for free with Jekyll. You can either set it in your _config.yml
file with:
url: http://alanwsmith.com
Or, define it when you call jekyll:
jekyll --url http://alanwsmith.com
If you need to replace values in data/yml
from another data/yml
file, I wrote plugin. It's not so elegant but works :
I did some code improvements. Now it catch all occurrences in one string and work with nested values.
module LiquidReplacer class Generator < Jekyll::Generator REGEX = /\!([A-Za-z0-9]|_|\.){1,}\!/ def replace_str(str) out = str str.to_s.to_enum(:scan, REGEX).map { m = Regexp.last_match.to_s val = m.gsub('!', '').split('.') vv = $site_data[val[0]] val.delete_at(0) val.length.times.with_index do |i| if val.nil? || val[i].nil? || vv.nil? ||vv[val[i]].nil? puts "ERROR IN BUILDING YAML WITH KEY:\n#{m}" else vv = vv[val[i]] end end out = out.gsub(m, vv) } out end def deeper(in_hash) if in_hash.class == Hash || in_hash.class == Array _in_hash = in_hash.to_a _out_hash = {} _in_hash.each do |dd| case dd when Hash _dd = dd.to_a _out_hash[_dd[0]] = deeper(_dd[1]) when Array _out_hash[dd[0]] = deeper(dd[1]) else _out_hash = replace_str(dd) end end else _out_hash = replace_str(in_hash) end return _out_hash end def generate(site) $site_data = site.data site.data.each do |data| site.data[data[0]] = deeper(data[1]) end end endend
place this code in site/_plugins/liquid_replacer.rb
in yml
file use !something.someval!
like as site.data.something.someval
but without site.data
part.
example :
_data/one.yml
foo: foo
_data/two.yml
bar: "!one.foo!bar"
calling {{ site.data.two.bar }}
will produce foobar
=======OLD CODE======
module LiquidReplacer class Generator < Jekyll::Generator REGEX = /\!([A-Za-z0-9]|_|\.){1,}\!/ def generate(site) site.data.each do |d| d[1].each_pair do |k,v| v.to_s.match(REGEX) do |m| val = m[0].gsub('!', '').split('.') vv = site.data[val[0]] val.delete_at(0) val.length.times.with_index do |i| vv = vv[val[i]] end d[1][k] = d[1][k].gsub(m[0], vv) end end end end endend