J W
J W

Reputation: 2871

Get a hash into a Jekyll Liquid template from a Plugin for use in the FOR loop?

This one's got me stumped...

I'd like to share a YAML hash from a single file among a few other Jekyll pages.

I know you can put it in the Front Matter (which would require duplicating it), and I know you can generate (write) pages via a plugin (but I'm using it in a few different types of pages, which would be complex). Neither is what I'm looking for.

I'd like to loop over the hash with Liquid in my pages, but I can't seem to get the hash from the plugin to Liquid. {% capture %} only works with strings and {% assign %} won't let you call a tag within itself, like {% assign projects = gethash %} where gethash is a custom Liquid tag.

Basically, I'd like to use the separate YAML file like a text-based database.

YAML File has this in it:

projects:

  category1:
     -
       title: Project 1
       desc: Description
       etc...
     -
       title: Project 2
       etc...

    category2:
     -
       title: Project 3
       desc: Description
       etc...
     -
       title: Project 4
       etc...

Plugin is calling (which gives a Ruby Hash of the YAML):

def...
  YAML::load(File.read('projects.yml'))
end...

And in template, I want to:

{% for p in projects %}
  ...

This should be really simple, but it's one of those Liquid things that is a pain.

How can you get a hash into Liquid from a plugin for use in the {% for %} loop?

Upvotes: 5

Views: 2349

Answers (2)

J W
J W

Reputation: 2871

Here's the solution that I came up:

A Jekyll Plugin that create's a Liquid Tag: yaml_to_liquid. This plugin parses the yaml file into a hash and then adds it to the Jekyll page variable.

module Jekyll

  class YamlToLiquid < Liquid::Tag
    def initialize(tag_name, arg, tokens)
      super

      if arg.length == 0
        raise 'Please enter a yaml file path'
      else
        @yml_path = arg
      end
    end

    def render(context)

      yml = YAML::load(File.read(@yml_path))
      context.registers[:page]['yml'] = yml
    end
  end
end

Liquid::Template.register_tag('yaml_to_liquid', Jekyll::YamlToLiquid)

To use it. Place the tag at the top of your .html or .md page just below the Yaml Front Matter and then access the yml variable as usual. This loop will only output the code hash (allows you to access the whole hash or just sub-hashes):

---
layout: page
---
{% yaml_to_liquid work/_projects.yml %}

<ul>
  {% for n in page.yml.projects.code %}
    <li>
    <a href="{{ n.url }}">{{ n.title }}</a>
    </li>
  {% endfor %}
</ul>

Example of work/_projects.yml:

projects:

  code:
    - title:
      url:

    - title:
      url:

  websites:
    - title:
      url:

    - title:
      url:

Upvotes: 5

Carlos Agarie
Carlos Agarie

Reputation: 4002

Well, if you don't need it to be a plugin, it can be put in your _config.yml. For a plugin, you might need to append the hash to the site variable.

I think that a generator would suffice. There is a page about plugins that you should take a look.

This is what I'd use (I can't test right now, so it might be wrong!):

module Jekyll
  class ProjectsGenerator < Generator
    safe true

    def generate(site)
      # This probably won't work.
      site.projects = YAML::load(File.read('projects.yml'))
    end
  end
end

Anyway, I really think that if you don't need the extra complexity (having a separate file, creating a new plugin just for you, etc), just put the data in _config.yml. Simplicity is good.

Hope that helps. :)

Upvotes: 0

Related Questions