Mike Slinn
Mike Slinn

Jekyll Plugin Template Collection

Published 2020-12-30. Last modified 2020-01-02.
Time to read: about 2 minutes.

This article is categorized under Jekyll, Ruby

Here are templates for you to start writing your next Jekyll plugin in Ruby. Templates are provided for custom Jekyll filters, generators, tags and block tags. These templates all:

  • Set up their own custom logger as described in my previous blog post.
  • Provide the Jekyll site, page and mode variables in all the places you need them but don't have them available in scope. Note that generators are only invoked once for the entire site, when all the pages have been scanned and the site structure is available for processing, but unlike the other templates generators do not have access to the page variable because they are invoked on a per-site basis, not a per-page basis. It is common for generators to include code that loops through various collections of pages.
  • Come with documentation boilerplate for processing with yard.

You can view the rendered documentation.

Code Download Options

You have options for how you might download these F/OSS Jekyll plugin templates. Pick an option and save to your _plugins/ directory of your Jekyll-powered site. Your download options are:

  1. Download a zip file containing all the F/OSS Jekyll plugins I publish.
  2. Copy the following code to your clipboard by clicking on the clipboard icon at the top right of the code container, then save the code to _plugins/ directory of your Jekyll-powered site.

jekyll_filter_template.rb

This Jekyll filter template converts strings passed to it to upper case. Yard docs are here.

# frozen_string_literal: true

# @author Copyright 2020 {https://www.mslinn.com Michael Slinn}
# @license SPDX-License-Identifier: Apache-2.0
# Template for Jekyll filters.
module JekyllFilterTemplate
  require_relative 'logger_factory' # include the source of logger_factory.rb into this program

  @log = LoggerFactory.new.create_logger('my_filter_template', Jekyll.configuration({}), :warn, $stderr)

  # Accessor allows classes in this module to use the logger
  def self.log
    @log
  end

  # Describe the filter here.
  # @param input_strings [Array<String>] State what this parameter is for.
  # @return [String]
  # @example Describe an example of how to use it.
  #   {{ 1234 | my_filter_template }}
  def my_filter_template(input_strings)
    JekyllFilterTemplate.log.info "input_strings = #{input_strings}, upcased = #{input_strings.upcase}".cyan
    input_strings.upcase
  end
end

Liquid::Template.register_filter(JekyllFilterTemplate)

Output

Given this markup in an HTML file:

{{ "Hello, world!" | my_filter_template }}

This is what is rendered to the web page after being passed through the filter:

HELLO, WORLD!

jekyll_generator_template.rb

Yard docs are here.

# frozen_string_literal: true

# @author Copyright 2020 {https://www.mslinn.com Michael Slinn}
# @license SPDX-License-Identifier: Apache-2.0
# Describe this Jekyll generator here.
class JekyllGeneratorTemplate < Jekyll::Generator
  require_relative 'logger_factory'

  def initialize(config)
    super(config)
    @log = LoggerFactory.new.create_logger('my_generator_template', config, :warn, $stderr)
  end

  # Method prescribed by the Jekyll plugin lifecycle.
  # @param site [Jekyll.Site] Automatically provided by Jekyll plugin mechanism
  # @return [void]
  def generate(site)
    @config = site.config
    @mode = @config['env']['JEKYLL_ENV']
    @log.info "mode=#{@mode}".green
  end
end

Output

Generators do not display anything on the generated web site. They can create files containing pages in a directory. Generators usually log information to the console whenever a problem occurs, or progress needs to be shown.

jekyll_tag_template.rb

Yard docs are here.

# frozen_string_literal: true

# @author Copyright 2020 {https://www.mslinn.com Michael Slinn}
# @license SPDX-License-Identifier: Apache-2.0
#
# Module-level description goes here.
#
# @example Heading for this example
#   Describe what this example does
#   {% my_tag_template "parameter" %}
#
# @example Heading for this example
#   Describe what this example does
#   {% my_tag_template "parameter" %}
module MyTagTemplate
  # Start of custom logger definition
  require_relative 'logger_factory' # include the source of logger_factory.rb into this program

  @log = LoggerFactory.new.create_logger('my_tag_template', Jekyll.configuration({}), :warn, $stderr)

  # This accessor allows classes in this module to use the logger.
  def self.log
    @log
  end

  # End of custom logger definition

  # This class implements the Jekyll tag functionality
  class MyTag < Liquid::Tag
    # Constructor.
    # @param tag_name [String] is the name of the tag, which we already know.
    # @param arguments [Hash, String, Liquid::Tag::Parser] the arguments from the tag.
    # @param tokens [Liquid::ParseContext] tokenized command line
    # @return [void]
    def initialize(tag_name, arguments, tokens)
      super(tag_name, arguments, tokens)
      MyTagTemplate.log.info "tag_name [#{tag_name.class}] = '#{tag_name}' [#{tag_name.class}]".green
      MyTagTemplate.log.info "arguments [#{arguments.class}] = '#{arguments}'".green

      # @site = context.registers[:site] # This variable is handy but not required
      # @config = @site.config # This variable is handy but not required
      # @mode = @config['env']['JEKYLL_ENV'] # This variable is handy but not required
      # MyTagTemplate.log.info "mode=#{@mode}".green

      @arguments = arguments
      @arguments = '' if @arguments.nil? || @arguments.empty?
    end

    # Method prescribed by the Jekyll plugin lifecycle.
    # @return [String]
    def render(context)
      @site = context.registers[:site]
      @config = @site.config
      @mode = @config['env']['JEKYLL_ENV']
      MyTagTemplate.log.info "mode='#{@mode}'".green

      @page = context.registers[:page]
      MyTagTemplate.log.info "page.path='#{@page.path}'".green
      MyTagTemplate.log.info "page.url='#{@page.url}'".green


      <<~HEREDOC
        <p style="color: green; background-color: yellow; padding: 1em; border: solid thin grey;">
          #{@arguments}
        </p>
      HEREDOC
    end
  end

  private

  # Describe the function's purpose
  # This is a link {https://domain.com with some text}.
  # @param parameter [String] Describe this parameter's purpose
  # @return [String, nil] Describe the return value
  def my_private_function(parameter)
    log.info "my_private_function.parameter=#{parameter}"
  end

  # parse, or return the args
  # @note you can pass in parsed args
  # @return [Liquid::Tag::Parser]
  def parse_args(args)
    return args if args.is_a?(Liquid::Tag::Parser) || args.is_a?(Hash)
    Liquid::Tag::Parser.new(
      @args
    )
  end
end

Liquid::Template.register_tag(MyTagTemplate.log.progname, MyTagTemplate::MyTag)

Output

Given this markup in an HTML file:

{% my_tag_template This is a little song I wrote, I hope you sing it note for note... %}

This is how it looks after the block tag is rendered to the page:

This is a little song I wrote, I hope you sing it note for note...

jekyll_block_template.rb

Yard docs are here.

# frozen_string_literal: true

# @author Copyright 2020 {https://www.mslinn.com Michael Slinn}
# @license SPDX-License-Identifier: Apache-2.0
#
# Module-level description goes here.
#
# @example Heading for this example
#   Describe what this example does
#   {% my_block_template "parameter" %}
#     Hello, world!
#   {% endmy_block_template %}
#
# @example Heading for this example
#   Describe what this example does
#   {% my_block_template "parameter" %}
#     Hello, world!
#   {% endmy_block_template %}
module MyBlockTagTemplate
  # Start of custom logger definition
  require_relative 'logger_factory' # include the source of logger_factory.rb into this program

  @log = LoggerFactory.new.create_logger('my_block_template', Jekyll.configuration({}), :warn, $stderr)

  # This accessor allows classes in this module to use the logger.
  def self.log
    @log
  end

  # End of custom logger definition

  # This class implements the Jekyll tag functionality
  class MyBlock < Liquid::Block
    # Constructor.
    # @param tag_name [String] the name of the tag, which we already know.
    # @param text [Hash, String, Liquid::Tag::Parser] the arguments from the tag.
    # @param tokens [Liquid::ParseContext] parsed and tokenized command line
    # @return [void]
    def initialize(tag_name, arguments, tokens)
      super(tag_name, arguments, tokens)
      MyTagTemplate.log.info "tag_name [#{tag_name.class}] = '#{tag_name}' [#{tag_name.class}]".green
      MyTagTemplate.log.info "arguments [#{arguments.class}] = '#{arguments}'".green
      @arguments = arguments
      @arguments = '' if @arguments.nil? || @arguments.empty?
    end

    # Method prescribed by the Jekyll plugin lifecycle.
    # @return [String]
    def render(context)
      content = super # This magically underdocumented assignment somehow returns the text within the block.

      @site = context.registers[:site]
      @config = @site.config
      @mode = @config['env']['JEKYLL_ENV']
      MyBlockTagTemplate.log.info "mode='#{@mode}'".green

      @page = context.registers[:page]
      MyBlockTagTemplate.log.info "page.path='#{@page.path}'".green
      MyBlockTagTemplate.log.info "page.url='#{@page.url}'".green

      <<~HEREDOC
        <p style="color: green; background-color: yellow; padding: 1em; border: solid thin grey;">
          #{content}
        </p>
      HEREDOC
    end
  end
end

Liquid::Template.register_tag(MyBlockTagTemplate.log.progname, MyBlockTagTemplate::MyBlock)

Output

Given this markup in an HTML file:

{% my_block_template %}Hello, world!{% endmy_block_template %}

This is how it looks after the block tag is rendered to the page:

Hello, world!