Generators
You can create a generator when you need Jekyll to create additional content based on your own rules.
A generator is a subclass of Jekyll::Generator
that defines a generate
method, which receives an instance of
Jekyll::Site
. The return value of generate
is ignored.
Generators run after Jekyll has made an inventory of the existing content, and before the site is generated. Pages with
front matter are stored as instances of Jekyll::Page
and are
available via site.pages
. Static files become instances of
Jekyll::StaticFile
and are available via site.static_files
. See the Variables documentation page and
Jekyll::Site
for details.
In the following example, the generator will inject values computed at build time for template variables. The template
named reading.html
has two undefined variables ongoing
and done
that will be defined or assigned a value when
the generator runs:
module Reading
class Generator < Jekyll::Generator
def generate(site)
book_data = site.data['books']
ongoing = book_data.select { |book| book['status'] == 'ongoing' }
done = book_data.select { |book| book['status'] == 'finished' }
# get template
reading = site.pages.find { |page| page.name == 'reading.html'}
# inject data into template
reading.data['ongoing'] = ongoing
reading.data['done'] = done
end
end
end
The following example is a more complex generator that generates new pages.
In this example, the aim of the generator is to create a page for each category registered in the site
. The pages are
created at runtime, so their contents, front matter and other attributes need to be designed by the plugin itself.
- The pages are intended to render a list of all documents under a given category. So the basename of the rendered file
would be better as
index.html
. - Having the ability to configure the pages via front matter defaults
would be awesome! So assigning a particular
type
to these pages would be beneficial.
module SamplePlugin
class CategoryPageGenerator < Jekyll::Generator
safe true
def generate(site)
site.categories.each do |category, posts|
site.pages << CategoryPage.new(site, category, posts)
end
end
end
# Subclass of `Jekyll::Page` with custom method definitions.
class CategoryPage < Jekyll::Page
def initialize(site, category, posts)
@site = site # the current site instance.
@base = site.source # path to the source directory.
@dir = category # the directory the page will reside in.
# All pages have the same filename, so define attributes straight away.
@basename = 'index' # filename without the extension.
@ext = '.html' # the extension.
@name = 'index.html' # basically @basename + @ext.
# Initialize data hash with a key pointing to all posts under current category.
# This allows accessing the list in a template via `page.linked_docs`.
@data = {
'linked_docs' => posts
}
# Look up front matter defaults scoped to type `categories`, if given key
# doesn't exist in the `data` hash.
data.default_proc = proc do |_, key|
site.frontmatter_defaults.find(relative_path, :categories, key)
end
end
# Placeholders that are used in constructing page URL.
def url_placeholders
{
:path => @dir,
:category => @dir,
:basename => basename,
:output_ext => output_ext,
}
end
end
end
The generated pages can now be set up to use a particular layout or output at a particular path in the destination directory all via the config file using front matter defaults. For example:
# _config.yml
defaults:
- scope:
type: categories # select all category pages
values:
layout: category_page
permalink: categories/:category/
Technical Aspects
Generators need to implement only one method:
Method | Description |
---|---|
|
Generates content as a side-effect. |
If your generator is contained within a single file, it can be named whatever you want but it should have an .rb
extension. If your generator is split across multiple files, it should be packaged as a Rubygem to be published at
https://rubygems.org/. In this case, the name of the gem depends on the availability of the name at that site because
no two gems can have the same name.
By default, Jekyll looks for generators in the _plugins
directory. However, you can change the default directory by
assigning the desired name to the key plugins_dir
in the config file.