The project is in a healthy, maintained state
Provides a framework for writing and testing Jekyll plugins
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
 Dependencies
 Project Readme

jekyll_plugin_support Gem Version

Jekyll_plugin_support is a Ruby gem that provides a framework for writing and testing Jekyll plugins.

Jekyll_plugin_support can be used to create simple Jekyll plugins in the _plugins/ directory of your Jekyll project, or gem-based Jekyll plugins.

At present, only Jekyll tags and blocks are supported.

Plugins that use jekyll_plugin_support include:

... and also the demonstration plugins in jekyll_plugin_support

Installation

Jekyll_plugin_support is packaged as a Ruby gem. If your project is a custom plugin that will reside in a Jekyll project’s _plugins directory, add the following line to your Jekyll plugin’s Gemfile.

group :jekyll_plugins do
  ...
  gem 'jekyll_plugin_support', '>= 0.8.0'
  ...
end

Otherwise, if your custom plugin will be packaged into a gem, add the following to your plugin’s .gemspec:

Gem::Specification.new do |spec|
  ...
  spec.add_dependency 'jekyll_plugin_support', '>= 0.8.0'
  ...
end

Install the jekyll_plugin_support Ruby gem and mark it as a dependency of your project by typing:

$ bundle

Copy the CSS classes from demo/assets/css/jekyll_plugin_support.css to your Jekyll project’s CSS file.

About jekyll_plugin_support

JekyllSupport::JekyllBlock and JekyllSupport::JekyllTag provide support for Jekyll tag block plugins and Jekyll inline tag plugins, respectively. They are very similar in construction and usage.

Instead of subclassing your custom Jekyll block tag class from Liquid::Block, subclass from JekyllSupport::JekyllBlock. Similarly, instead of subclassing your custom Jekyll tag class from Liquid::Tag, subclass from JekyllSupport::JekyllTag.

Both JekyllSupport classes instantiate new instances of PluginMetaLogger (called @logger) and JekyllPluginHelper (called @helper).

JekyllPluginHelper defines a generic initialize method, and your tag or block tag class should not need to override it. Also, your tag or block tag class should not define a method called render, because jekyll_plugin_support defines one.

Instead, define a method called render_impl. For inline tags, render_impl does not accept any parameters. For block tags, a single parameter is required, which contains text passed from your block in the page.

Your implementation of render_impl can parse parameters passed to the tag / block tag, as described in Tag Parameter Parsing.

The following variables are predefined within render. See the Jekyll documentation for more information.

  • @argument_string – Original unparsed string from the tag in the web page
  • @config – Jekyll configuration data
  • @layout – Front matter specified in layouts
  • @modepossible values are development, production, or test
  • @page – Jekyll page variable
  • @paginator – Only has a value when a paginator is active; they are only available in index files.
  • @site – Jekyll site variable
  • @tag_name – Name of the inline tag or block plugin
  • @theme – Theme variables (introduced in Jekyll 4.3.0)

General Usage

Please see the demo/ project for a well-documented set of demonstration Jekyll plugins that are built from jekyll_plugin_support. Additional information is available here and the jekyll_plugin_support documentation.

JekyllSupport::JekyllBlock and JekyllSupport::JekyllTag provide support for Jekyll block tags and Jekyll inline tags, respectively. They are similar in construction and usage.

Instead of subclassing your Jekyll block tag class from Liquid::Block, subclass from JekyllSupport::JekyllBlock instead.

Likewise, instead of subclassing your Jekyll inline tag class from Liquid::Tag, subclass from JekyllSupport::JekyllTag instead.

Both JekyllSupport classes instantiate new instances of PluginMetaLogger (called @logger) and JekyllPluginHelper (called @helper).

Inline and Block Tag Plugin Implementation

Both JekyllSupport classes define a generic initialize method, and your inline tag or block tag class should not override it.

Also, your inline tag or block tag class should not define a method called render, because both JekyllSupport classes define this method.

Instead, define a method called render_impl. For inline tags, render_impl does not accept any parameters. For block tags, a single parameter is required, which contains any text enclosed within your block.

Predefined Plugin Variables

Jekyll_plugin_support defines the following Ruby variables that you can use in your plugin’s render_impl method:

  • @argument_string Unparsed markup passed as a parameter to your block tag and inline tag.

  • @attribution Attribution markup

  • @config YAML Jekyll site configuration file

  • @helper JekyllPluginHelper instance for your plugin.

  • @layout Layout information

  • @logger jekyll_plugin_logger instance for your Jekyll plugin.

  • @mode Indicates production or development mode.

  • @page Page variables

  • @paginator Pagination variables

  • @scopes See the jekyll_plugin_support demo project

  • @site Site variables

  • @tag_config Contents of the section of _config.yml named after your plugin.

  • @tag_name Name of your Jekyll block tag or inline tag plugin.

  • @theme Theme variables

  • text Content provided to your block tag.

Argument Parsing

Tag arguments can be obtained within render_impl. Both keyword options and name/value parameters are supported.

Both JekyllTag and JekyllBlock use the standard Ruby mechanism for parsing command-line options: shellwords and key_value_parser.

All your code has to do is to specify the keywords to search for in the string passed from the HTML page that your tag is embedded in. The included demo website has examples; both demo/_plugins/demo_inline_tag.rb and demo/_plugins/demo_block_tag.rb contain the following:

@keyword1  = @helper.parameter_specified? 'keyword1'
@keyword2  = @helper.parameter_specified? 'keyword2'
@name1     = @helper.parameter_specified? 'name1'
@name2     = @helper.parameter_specified? 'name2'

Example

demo/index.html, contains the following inline tag invocation:

{% demo_inline_tag keyword1 name1='value1' unreferenced_key unreferenced_name="unreferenced_value" %}

The demo/_plugins/demo_inline_tag.rb plugin uses @helper.parameter_specified? provided by jekyll_support_plugin to parse the string passed to the tag, which is keyword1 name1='value1' unreferenced_key unreferenced_name="unreferenced_value".

  • Because keyword1 was referenced by @helper.parameter_specified? above, that keyword option is removed from the argument string.
  • Because the name1 key/value parameter was referenced by @helper.parameter_specified? above, that name/value pair is removed from the argument string.
  • The remainder of the argument string is now unreferenced_key unreferenced_name="unreferenced_value".

To Quote Or Not To Quote

Parameter values can be quoted.

If the value consists of only one token then quoting is optional. The following name/value parameters all have the same result:

  • pay_tuesday="true"
  • pay_tuesday='true'
  • pay_tuesday=true
  • pay_tuesday

If the values consist of more than one token, quotes must be used. The following examples both yield the same result:

  • pay_tuesday="maybe not"
  • pay_tuesday='maybe not'

Remaining Markup

After your plugin has parsed all the keyword options and name/value parameters, call @helper.remaining_markup to obtain the remaining markup that was passed to your plugin.

Liquid Variable Definitions

jekyll_plugin_support provides support for Liquid variables to be defined in _config.yml, in a section called liquid-vars. The following _config.yml fragment defines 3 variables called var1, var2 and var3:

liquid-vars:
  var1: value1
  var2: 'value 2'
  var3: value3

Liquid variables defined in this manner are intended to be embedded in a webpage. They are expanded transparently, and can be referenced like any other Liquid variable. These Liquid variables can be passed as parameters to other plugins and includes.

In the following example web page, the Liquid variable called var1 is expanded as part of the displayed page. Liquid variables var1 and var2 are expanded and passed to the my_plugin plugin.

This is the value of <code>var1</code>: {{var1}}.

{% my_plugin param1="{{var1}}" param2="{{var2}}" %}

Jekyll_plugin_support expands all but one of the plugin variables described above, replacing Liquid variable references with their values. The exception is @argument_string, which is not expanded.

Liquid Variable Values Specific To Production And Development Modes

jekyll_plugin_support allows Liquid variables defined in _config.yml to have different values when Jekyll is running in development, production and test modes. When injecting variables into your Jekyll website, Jekyll_plugin_support refers to definitions specific to the current environment, and then refers to other definitions that are not overridden.

Here is an example:

liquid-vars:
  development:
    var1: 'http://localhost:4444/demo_block_tag.html'
    var2: 'http://localhost:4444/demo_inline_tag.html'
  production:
    var1: 'https://github.com/django/django/blob/3.1.7'
    var2: 'https://github.com/django-oscar/django-oscar/blob/3.0.2'
  var3: 'https://github.com/mslinn'

For the above, the following variable values are set in development mode:

  • var1: http://localhost:4444/demo_block_tag.html
  • var2: http://localhost:4444/demo_inline_tag.html
  • var3: https://github.com/mslinn

... and the following variable values are set in production and test modes:

  • var1: https://github.com/django/django/blob/3.1.7
  • var2: https://github.com/django-oscar/django-oscar/blob/3.0.2
  • var3: https://github.com/mslinn

Liquid Variables in jekyll_plugin_support Subclasses

You can define additional Liquid variables in plugins built using jekyll_plugin_support. To do this, make entries in _config.yml under a key named after the value of @tag_name.

For example, let’s imagine you create a plugin using jekyll_plugin_support, and hou register it with the name phonetic_alphabet. You could define Liquid variables that would be made available to content pages in web applications that incorporate the phonetic_alphabet plugin. The following section in _config.yml defines variables called x, y and z, with values xray, yankee and zulu, respectively:

phonetic_alphabet:
  x: xray
  y: yankee
  z: zulu

The above definitions allow you to write content pages that use those variables, like the following page containing markup:

---
layout: default
title: Variable demo
---
The letter `x` is pronounced {{x}}.
Similarly, the letters `y` and `z` are pronounced {{y}} and {{z}}.

no_arg_parsing Optimization

If your tag or block plugin only needs access to the raw arguments passed from the web page, without tokenization, and you expect that the plugin might be invoked with large amounts of text, derive your plugin from JekyllBlockNoArgParsing or JekyllTagNoArgParsing.

Subclass Attribution

JekyllTag and JekyllBlock subclasses of jekyll_plugin_support can utilize the attribution option if they are published as a gem. JekyllTagNoArgParsing and JekyllBlockNoArgParsing subclasses cannot. This feature is usually only desired for JekyllBlock subclasses.

  • When used as a keyword option, a default value is used for the attribution string.
  • When used as a name/value option, the attribution string can be specified.

Using the attribution option cause subclasses to replace their usual output with HTML that looks like:

<div id="jps_attribute_12345" class="jps_attribute">
  <a href="https://github.com/mslinn/jekyll_outline">
    <b>Generated by <code>jekyll_outline</code>.
  </a>
</div>

The id attribute is in the sample HTML above is randomized so more than one attribution can appear on a page.

Usage

Typical usage for the attribution tag is:

{% my_block_tag attribution %}
  Content of my_block_tag.
{% endmy_block_tag %}

Normal processing of my_block_tag is augmented by interpolating the attribution format string, which is a Ruby-compatible interpolated string.

The default attribution format string is:

"Generated by the #{name} #{version} Jekyll plugin, written by #{author} #{date}."

Because jekyll_plugin_suppprt subclasses are gems, their gemfiles define values for name, version, homepage, and authors, as well as many other properties. The date property is obtained from the plugin/gem publishing date.

An alternative attribution string can be specified properties can be output using any of the above properties:

{% my_tag attribution="Generated by the #{name} #{version} Jekyll plugin, written by #{author} #{date}" %}

Attribution Generation

You can decide where you want the attribution string for your Jekyll tag to appear by invoking @helper.attribute. For example, this is how the jekyll_outline tag generates output:

<<~HEREDOC
<div class="outer_posts">
#{make_entries(collection)&.join("\n")}
</div>
#{@helper.attribute if @helper.attribution}
HEREDOC

Development

After checking out the jekyll_plugin_suppprt repository, run bin/setup to install dependencies.

bin/console provides an interactive prompt that allows you to experiment.

To build and install this gem onto your local machine, run:

$ bundle exec rake install
jekyll_plugin_support 0.1.0 built to pkg/jekyll_plugin_support-0.1.0.gem.
jekyll_plugin_support (0.1.0) installed.

Examine the newly built gem:

$ gem info jekyll_plugin_support

*** LOCAL GEMS ***

jekyll_plugin_support (0.1.0)
    Author: Mike Slinn
    Homepage:
    https://github.com/mslinn/jekyll_plugin_support
    License: MIT
    Installed at: /home/mslinn/.gems

    Provides support for writing Jekyll plugins.

Pry Breakpoint On StandardError

A pry breakpoint will be set in the StandardError handler if pry_on_standard_error: true is set in variable configuration section of _config.yml.

For example, if your plugin is called blah, enable the breakpoint with the following section:

blah:
  pry_on_standard_error: true

Demonstration Plugins and Website

A demo / test website is provided in the demo directory. It can be used to debug the plugin or to run freely.

Run Freely

  1. Run from the command line:

    $ demo/_bin/debug -r
  2. View the generated website, which might be at http://localhost:4444, depending on how you configured it.

Plugin Debugging

  1. Set breakpoints in Visual Studio Code.

  2. Initiate a debug session from the command line by running the demo/_bin/debug script:

    $ demo/_bin/debug
    Fetching gem metadata from https://rubygems.org/..........
    Resolving dependencies...
    Fetching public_suffix 5.0.4
    Fetching nokogiri 1.15.5 (x86_64-linux)
    Installing public_suffix 5.0.4
    Installing nokogiri 1.15.5 (x86_64-linux)
    Bundle complete! 17 Gemfile dependencies, 96 gems now installed.
    Use `bundle info [gemname]` to see where a bundled gem is installed.
    
    INFO PluginMetaLogger: Loaded DraftFilter plugin.
    INFO PluginMetaLogger: Loaded outline_js v1.2.1 plugin.
    INFO PluginMetaLogger: Loaded outline v1.2.1 plugin.
    Configuration file: /mnt/f/jekyll_plugin_support/demo/_config.yml
              Cleaner: Removing /mnt/f/jekyll_plugin_support/demo/_site...
              Cleaner: Removing /mnt/f/jekyll_plugin_support/demo/.jekyll-metadata...
              Cleaner: Removing /mnt/f/jekyll_plugin_support/demo/.jekyll-cache...
              Cleaner: Nothing to do for .sass-cache.
    DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:37177)
    DEBUGGER: wait for debugger connection...
  3. Once the DEBUGGER: wait for debugger connection... message appears, run the Visual Studio Code launch configuration called Attach with rdbg.

  4. View the generated website, which might be at http://localhost:4444, depending on how you configured it.

Build and Push to RubyGems

To release a new version:

  1. Update the version number in version.rb.

  2. Add an entry to CHANGELOG.md describing the changes since the previous version.

  3. Commit all changes to git; if you don't the next step might fail with an unexplainable error message.

  4. Run the following:

    $ bundle exec rake release

    The above creates a git tag for the version, commits the created tag, and pushes the new .gem file to RubyGems.org.

Contributing

  1. Fork the project
  2. Create a descriptively named feature branch
  3. Add your feature
  4. Submit a pull request

License

The gem is available as open source under the terms of the MIT License.