This post will only be of interest to Jekyll users, but if you want to start creating your own customizations to your Jekyll setup, this will be an easy start.

Jekyll posts include YAML frontmatter at the top of the post. After the default keys (title, date, layout, etc.), you can define any key you want and assign data to it. That data is then available in your template using Liquid output tags (via {{ page.[key] }}). For example, I use a “description” key that—if it’s set in the post—will generate custom <meta> tags in head.html for “description” (and its OpenGraph counterparts) with the key’s value.

Going further, you can also affect the custom page/post data with Liquid tags in the post content. A short custom plugin is all that’s needed to define a custom tag that will set metadata before the template renders.

When a Jekyll finds a {% tag %} it calls render on the plugin that registered that tag. It passes a context object to the plugin which contains the data for the post or page currently being processed (among a lot of other info). The data for the current page is contained within the first element of the context.environments array, and modifications to that data are passed by reference.

Thus, if you wanted to create a block tag called “describe” and use it to surround text which will be lifted into the page.description data for a post, you could use something as simple as:

module Jekyll

  class OGDescriptionTag < Liquid::Block
    def initialize(tag_name, markup, tokens)
      super
    end

    def render(context)
      output = super
      context.environments.first['page']['description'] = output
      output
    end
  end
end

Liquid::Template.register_tag('describe', Jekyll::OGDescriptionTag)

The initialize and render functions are standard and called automatically when the plugin loads and when it runs. The only line in the code above that matters is:

context.environments.first['page']['description'] = output

In the case of this block tag, it’s simply modifying (or adding) the value of description key in the page data hash for the current post. Then it returns the original contents of the tag unmodified. You could also make an inline tag that sets boolean values or processes the tag’s tokens to set anything you want.

With the above plugin saved in your plugins folder, you could use markup like this anywhere in a post to set the description value:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed 
do eiusmod {% describe %}stempor incididunt ut labore et dolore magna 
aliqua.{% enddescribe %} Ut enim ad minim veniam, quis nostrud 
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

This version does no processing or modification of the contents. You could, if desired, do things like HTML escape or truncate the content before setting the variable, but I usually handle that with custom Liquid filters.

What you do with it from there is up to your template, but simple plugins like this offer some interesting customization possibilities. Consider that instead of passing back the original contents, the plugin could modify it or add elements based on its context. As a wild example, you could create a block tag that added HTML wrappers that varied based on its contents, and then assigned a key to the page data to change a body class.

Hopefully that gives you some ideas for your own customizations!