I was wondering if there is a way for a generator plugin to use a layout from a theme.
Almost copying the example from the documentation of Generators, I created this plugin:
# frozen_string_literal: true
require 'jekyll'
require 'liquid'
module Buckygem
# A generator plugin creating one new page per category found in the site.
class CategoryPageGenerator < Jekyll::Generator
safe true
def generate(site)
return unless site.layouts.key? 'category_index'
dir = site.config['category_dir'] || 'categories'
site.categories.each_key do |category|
# Slug from https://stackoverflow.com/questions/4308377/ruby-post-title-to-slug
site.pages << CategoryPage.new(site, site.source, File.join(dir, Buckygem.slugify(category)), category)
end
end
end
# A Page subclass used in the `CategoryPageGenerator`
class CategoryPage < Jekyll::Page
# rubocop:disable Lint/MissingSuper
def initialize(site, base, dir, category)
@site = site
@base = base
@dir = dir
@name = 'index.html'
process(@name)
puts site.layouts['category_index']
H
read_yaml(File.join(base, '_layouts'), 'category_index.html')
data['category'] = category
category_title_prefix = site.config['category_title_prefix'] || 'Category: '
data['title'] = "#{category_title_prefix}#{category}"
end
end
# rubocop:enable Lint/MissingSuper
# A Liquid filter to generate the path of a category resource.
module CategoryLinkFilter
def category_link(input)
"/categories/#{Buckygem.slugify(input)}"
end
end
end
But since I intend to use a category_index.html
layout from a theme (as opposed to a file in _layout/
of my project), I am getting the following error:
Error reading file /Users/.../_layouts/category_index.html: No such file or directory @ rb_sysopen - /Users/.../_layouts/category_index.html
Surely.
When you have the liberty to write and use plugins, your limits are endless.
The reason your plugin is failing is because it is trying to read a non-existing file path.
Remember, Jekyll builds a site in distinct phases:
reset => read => generate => render => write
That means, your plugin (which runs during the generate
phase) doesn’t have to read layout files again. It would already be available in the container site.layouts
.
I’m purposely not walking you through to the solution and it is upto you to dissect the site.layouts
container, extract the desired layout
and access the extracted layout
's data
attribute.
Good luck
2 Likes
Thanks @ashmaroli!
I’ve been digging further to take your advice into account, and see what #read_yaml
was doing and changed my page code to the following:
class CategoryPage < Jekyll::Page
# rubocop:disable Lint/MissingSuper
def initialize(site, base, dir, category)
@site = site
@base = base
@dir = dir
@name = 'index.html'
process(@name)
@data = site.layouts['category_index'].data
@content = site.layouts['category_index'].content
@data['category'] = category
category_title_prefix = site.config['category_title_prefix'] || 'Category: '
@data['title'] = "#{category_title_prefix}#{category}"
end
# rubocop:enable Lint/MissingSuper
end
Things work much better since I don’t get any errors when building.
But all my category pages end up using the last category
that was used, ie the page.title
in the layout ends up always being the last category’s title that was used by the generator’s iteration.
I am a little rusty with Ruby but it’s like there was some shared state between all pages that were created and I can’t put my finger where that might come from. Any idea of what is going wrong here?
The reason for that is because all of your generated pages have the same @name
attribute
equal to "index.html"
I had this idea already but it behaves the same if I use say index-#{slugify(category)}.html
.
Which makes sense since I can have many index.html
files in different directories (dir
is distinct for each category
).
Oh right!
You use @dir
to dictate what category the page is associated with…
That said, I have no clue what Buckygem.slugify(input)
does…
For further reference, please look into the code-base for jekyll-archives
1 Like
jekyll-archives
does pretty much what I wanted to do. I think I’ll just use it instead of developing my own thing.
I will try to look more into the source code anyway and if I manage to get a clear view of a generator’s requirements, I will also try to update https://jekyllrb.com/docs/plugins/generators/ since I believe it lacks quite some details.
Thanks a lot @ashmaroli!
1 Like