Improve documentation on developing generators (#8527)
Merge pull request 8527
This commit is contained in:
parent
fc76919c69
commit
319cc95254
|
@ -3,36 +3,34 @@ title: Generators
|
||||||
permalink: /docs/plugins/generators/
|
permalink: /docs/plugins/generators/
|
||||||
---
|
---
|
||||||
|
|
||||||
You can create a generator when you need Jekyll to create additional content
|
You can create a generator when you need Jekyll to create additional content based on your own rules.
|
||||||
based on your own rules.
|
|
||||||
|
|
||||||
A generator is a subclass of `Jekyll::Generator` that defines a `generate`
|
A generator is a subclass of `Jekyll::Generator` that defines a `generate` method, which receives an instance of
|
||||||
method, which receives an instance of
|
[`Jekyll::Site`]({{ site.repository }}/blob/master/lib/jekyll/site.rb). The return value of `generate` is ignored.
|
||||||
[`Jekyll::Site`]({{ site.repository }}/blob/master/lib/jekyll/site.rb). The
|
|
||||||
return value of `generate` is ignored.
|
|
||||||
|
|
||||||
Generators run after Jekyll has made an inventory of the existing content, and
|
Generators run after Jekyll has made an inventory of the existing content, and before the site is generated. Pages with
|
||||||
before the site is generated. Pages with front matter are stored as
|
front matter are stored as instances of [`Jekyll::Page`]({{ site.repository }}/blob/master/lib/jekyll/page.rb) and are
|
||||||
instances of
|
available via `site.pages`. Static files become instances of
|
||||||
[`Jekyll::Page`]({{ site.repository }}/blob/master/lib/jekyll/page.rb)
|
|
||||||
and are available via `site.pages`. Static files become instances of
|
|
||||||
[`Jekyll::StaticFile`]({{ site.repository }}/blob/master/lib/jekyll/static_file.rb)
|
[`Jekyll::StaticFile`]({{ site.repository }}/blob/master/lib/jekyll/static_file.rb)
|
||||||
and are available via `site.static_files`. See
|
and are available via `site.static_files`. See [the Variables documentation page](/docs/variables/) and
|
||||||
[the Variables documentation page](/docs/variables/) and
|
[`Jekyll::Site`]({{ site.repository }}/blob/master/lib/jekyll/site.rb) for details.
|
||||||
[`Jekyll::Site`]({{ site.repository }}/blob/master/lib/jekyll/site.rb)
|
|
||||||
for details.
|
|
||||||
|
|
||||||
For instance, a generator can inject values computed at build time for template
|
In the following example, the generator will inject values computed at build time for template variables. The template
|
||||||
variables. In the following example, the template `reading.html` has two
|
named `reading.html` has two undefined variables `ongoing` and `done` that will be defined or assigned a value when
|
||||||
variables `ongoing` and `done` that are filled in the generator:
|
the generator runs:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
module Reading
|
module Reading
|
||||||
class Generator < Jekyll::Generator
|
class Generator < Jekyll::Generator
|
||||||
def generate(site)
|
def generate(site)
|
||||||
ongoing, done = Book.all.partition(&:ongoing?)
|
book_data = site.data['books']
|
||||||
|
ongoing = book_data.select { |book| book['status'] == 'ongoing' }
|
||||||
|
done = book_data.select { |book| book['status'] == 'finished' }
|
||||||
|
|
||||||
reading = site.pages.detect {|page| page.name == 'reading.html'}
|
# get template
|
||||||
|
reading = site.pages.find { |page| page.name == 'reading.html'}
|
||||||
|
|
||||||
|
# inject data into template
|
||||||
reading.data['ongoing'] = ongoing
|
reading.data['ongoing'] = ongoing
|
||||||
reading.data['done'] = done
|
reading.data['done'] = done
|
||||||
end
|
end
|
||||||
|
@ -40,42 +38,80 @@ module Reading
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
The following example is a more complex generator that generates new pages. In this example, the generator will create a series of files under the `categories` directory for each category, listing the posts in each category using the `category_index.html` layout.
|
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](/docs/configuration/front-matter-defaults/)
|
||||||
|
would be awesome! So assigning a particular `type` to these pages would be beneficial.
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
module Jekyll
|
module SamplePlugin
|
||||||
class CategoryPageGenerator < Generator
|
class CategoryPageGenerator < Jekyll::Generator
|
||||||
safe true
|
safe true
|
||||||
|
|
||||||
def generate(site)
|
def generate(site)
|
||||||
if site.layouts.key? 'category_index'
|
site.categories.each do |category, posts|
|
||||||
dir = site.config['category_dir'] || 'categories'
|
site.pages << CategoryPage.new(site, category, posts)
|
||||||
site.categories.each_key do |category|
|
|
||||||
site.pages << CategoryPage.new(site, site.source, File.join(dir, category), category)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# A Page subclass used in the `CategoryPageGenerator`
|
# Subclass of `Jekyll::Page` with custom method definitions.
|
||||||
class CategoryPage < Page
|
class CategoryPage < Jekyll::Page
|
||||||
def initialize(site, base, dir, category)
|
def initialize(site, category, posts)
|
||||||
@site = site
|
@site = site # the current site instance.
|
||||||
@base = base
|
@base = site.source # path to the source directory.
|
||||||
@dir = dir
|
@dir = category # the directory the page will reside in.
|
||||||
@name = 'index.html'
|
|
||||||
|
|
||||||
self.process(@name)
|
# All pages have the same filename, so define attributes straight away.
|
||||||
self.read_yaml(File.join(base, '_layouts'), 'category_index.html')
|
@basename = 'index' # filename without the extension.
|
||||||
self.data['category'] = category
|
@ext = '.html' # the extension.
|
||||||
|
@name = 'index.html' # basically @basename + @ext.
|
||||||
|
|
||||||
category_title_prefix = site.config['category_title_prefix'] || 'Category: '
|
# Initialize data hash with a key pointing to all posts under current category.
|
||||||
self.data['title'] = "#{category_title_prefix}#{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
|
||||||
|
{
|
||||||
|
:category => @dir,
|
||||||
|
:basename => basename,
|
||||||
|
:output_ext => output_ext,
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
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:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# _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:
|
Generators need to implement only one method:
|
||||||
|
|
||||||
<div class="mobile-side-scroller">
|
<div class="mobile-side-scroller">
|
||||||
|
@ -99,6 +135,10 @@ Generators need to implement only one method:
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
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.
|
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.
|
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.
|
||||||
|
|
Loading…
Reference in New Issue