插件

Jekyll 支持插件功能,你可以很容易的加入自己的代码。

在 GitHub Pages 使用插件

GitHub Pages 是由 Jekyll 提供技术支持的,考虑到安全因素,所有的 Pages 通过 --safe 选项禁用了插件功能,因此如果你的网站部署在 Github Pages ,那么你的插件不会工作。

不过仍然有办法发布到 GitHub Pages,你只需在本地做一些转换,并把生成好的文件上传到 Github 替代 Jekyll 就可以了。

安装插件

可以使用以下三种方式安装插件:

  1. 在网站根下目录建立 _plugins 文件夹,插件放在这里即可。 Jekyll 运行之前,会加载此目录下所有以 *.rb 结尾的文件。
  2. 在你的_config.yml文件,添加一个键为gems的新数组,其值为你想要使用的gem插件的名字,例如:

     gems: [jekyll-coffeescript, jekyll-watch, jekyll-assets]
     # This will require each of these gems automatically.
    

    然后安装插件使用命令 gem install jekyll-coffeescript jekyll-watch jekyll-assets

  3. Gemfile 中的一个Bundler组里添加相关的插件,例如:

     group :jekyll_plugins do
       gem "my-jekyll-plugin"
       gem "another-jekyll-plugin"
     end
    

    然后需要从Bundler组中安装所有插件,使用命令bundle install

_plugins, _config.yml and Gemfile 可以同时使用

如果你愿意,可以在网站中同时使用上述安装插件的方法,使用一种安装方法并不会影响别的方法生效。

通常,插件最终会被放在以下的目录中:

  1. 生成器 - Generators
  2. 转换器 - Converters
  3. 命令 - Commands
  4. 标记 - Tags
  5. 钩子 - Hooks

生成器 - Generators

当你需要Jekyll根据你自己的规则来添加额外的内容时,你可以创建一个生成器。

生成器是 Jekyll:Generator 的子类,定义了一个 generate 方法, 接收一个Jekyll::Site类型的实例, 方法的返回值会被忽略。

生成器在Jekyll生成现存内容详细目录之后,网站生成之前运行, 含有YAML头信息的页面储存为Jekyll::Page实例,可以通过site.pages变量获取, 静态文件储存为Jekyll::StaticFile实例,可以通过site.static_files变量获取, 详情见变量文档Jekyll::Site

比如,生成器可以为模板变量注入构建过程中计算出的变量值,在下面的例子中, 我们在生成器中为模板reading.html的两个变量ongoingdone赋了值:

module Reading
  class Generator < Jekyll::Generator
    def generate(site)
      ongoing, done = Book.all.partition(&:ongoing?)

      reading = site.pages.detect {|page| page.name == 'reading.html'}
      reading.data['ongoing'] = ongoing
      reading.data['done'] = done
    end
  end
end

下面是一个更复杂的生成器例子,可以生成新的页面:

module Jekyll

  class CategoryPage < Page
    def initialize(site, base, dir, category)
      @site = site
      @base = base
      @dir = dir
      @name = 'index.html'

      self.process(@name)
      self.read_yaml(File.join(base, '_layouts'), 'category_index.html')
      self.data['category'] = category

      category_title_prefix = site.config['category_title_prefix'] || 'Category: '
      self.data['title'] = "#{category_title_prefix}#{category}"
    end
  end

  class CategoryPageGenerator < Generator
    safe true

    def generate(site)
      if site.layouts.key? 'category_index'
        dir = site.config['category_dir'] || 'categories'
        site.categories.keys.each do |category|
          site.pages << CategoryPage.new(site, site.source, File.join(dir, category), category)
        end
      end
    end
  end

end

本例中,生成器在 categories 下生成了一系列文件。并使用布局 category_index.html 列出所有的文章。

生成器只需要实现一个方法:

Method Description

generate

String output of the content being generated.

转换器 - Converters

如果想使用一个新的标记语言,可以用你自己的转换器实现,Markdown 和 Textile 就是这样实现的。

记住你的 YAML 头信息

Jekyll 只会转换带有 YAML 头信息的文件,即使你使用了插件也不行。

下边的例子实现了一个转换器,他会用 UpcaseConverter 来转换所有以 .upcase 结尾的文件。

module Jekyll
  class UpcaseConverter < Converter
    safe true
    priority :low

    def matches(ext)
      ext =~ /^\.upcase$/i
    end

    def output_ext(ext)
      ".html"
    end

    def convert(content)
      content.upcase
    end
  end
end

转换器需要最少实现以下 3 个方法:

方法 描述

matches

检查文件后缀名是否是所要的,传入的参数是文件的后缀名(包括点号),接受的返回值是 truefalse

output_ext

生成文件的后缀名(包括点号),通常是 ".html"

convert

转换逻辑,传入原始文件内容(不包含YAML头信息),返回值需要是 String 。

在上边的例子中, UpcaseConverter#matches 检查文件后缀名是不是 .upcase ;UpcaseConverter#convert 会处理检查成功文件的内容,即将所有的字符串变成大写;最终,保存的结果将以作为后缀名 .html

命令 - Commands

从2.5.0版本开始,Jekyll可以使用插件提供的子命令来扩展jekyll命令。 可以通过在Gemfile:jekyll_plugins组中包括相关的插件来实现:

group :jekyll_plugins do
  gem "my_fancy_jekyll_plugin"
end

每个Command必须是Jekyll::Command类的子类,而且必须要包含类方法init_with_program,例如:

class MyNewCommand < Jekyll::Command
  class << self
    def init_with_program(prog)
      prog.command(:new) do |c|
        c.syntax "new [options]"
        c.description 'Create a new Jekyll site.'

        c.option 'dest', '-d DEST', 'Where the site should go.'

        c.action do |args, options|
          Jekyll::Site.new_site_at(options['dest'])
        end
      end
    end
  end
end

命令应该实现这个单例方法:

方法 描述

init_with_program

这个方法接受一个参数, Mercenary::Program 实例,表示Jekyll程序本身,程序之上,命令可以通过上述方式创建,详情可以参见Github.com上的Mercenary库。

标记 - Tags

如果你想使用 liquid 标记,你可以这样做。 Jekyll 官方的例子有 highlightinclude 等标记。下边的例子中,自定义了一个 liquid 标记,用来输出当前时间:

module Jekyll
  class RenderTimeTag < Liquid::Tag

    def initialize(tag_name, text, tokens)
      super
      @text = text
    end

    def render(context)
      "#{@text} #{Time.now}"
    end
  end
end

Liquid::Template.register_tag('render_time', Jekyll::RenderTimeTag)

liquid 标记最少需要实现如下方法:

方法 描述

render

输出标记的内容。

你必须同时用 Liquid 模板引擎注册自定义标记,比如:

Liquid::Template.register_tag('render_time', Jekyll::RenderTimeTag)

对于上边的例子,你可以把如下标记放在页面的任何位置:

<p>{% render_time page rendered at: %}</p>

我们在页面上会得到如下内容:

<p>page rendered at: Tue June 22 23:38:47 –0500 2010</p>

Liquid 过滤器

你可以像上边那样在 Liquid 模板中加入自己的过滤器。过滤器会把自己的方法暴露给 liquid。所有的方法都必须至少接收一个参数,用来传输入内容;返回值是过滤的结果。

module Jekyll
  module AssetFilter
    def asset_url(input)
      "http://www.example.com/#{input}?#{Time.now.to_i}"
    end
  end
end

Liquid::Template.register_filter(Jekyll::AssetFilter)
提示™:用 Liquid 访问 site 对象

Jekyll 允许通过 Liquid 的context.registers 特性来访问 site 对象。比如可以用 context.registers.config 访问配置文件 _config.yml

Flags

当写插件时,有两个标记需要注意:

标记 描述

safe

告诉 Jekyll 此插件是否可以安全的执行任意代码。 GitHub Pages 用他来决定那个插件可以使用,哪些不可以使用。如果你的插件不允许执行任意代码,把它设为 true 即可。 GitHub Pages 仍然不会加载你的插件,但是如果你把他夹杂到核心中,最后保证此值设置的正确!

priority

此标记决定加载插件的顺序。可以是这些值::lowest, :low, :normal, :high, 还有 :highest。优先级高的先执行,优先级低的后执行。

以上边例子的插件为例,应该这样设置这两个标记:

module Jekyll
  class UpcaseConverter < Converter
    safe true
    priority :low
    ...
  end
end

钩子 - Hooks

通过使用钩子,你的插件可以精细控制构建过程中的各个方面。 如果你的插件定义了钩子,Jekyll就会在预定义时调用钩子。

钩子需要注册一个容器名称和事件名称,可以使用 Jekyll::Hooks.register 来注册, 传递一个容器名称、事件名称,以及钩子触发时调用的代码。 比如,假设你想要在 Jekyll 每次渲染博客时执行一些自定义的功能代码,你可以这样注册钩子:

Jekyll::Hooks.register :posts, :post_render do |post|
  # Jekyll 渲染博客后要调用的代码
end

Jekyll 分别为 :site:pages:posts:documents 提供了钩子。 在任何情况下,Jekyll 都会以容器对象作为第一个回调参数来调用你的钩子, 但是所有的 :pre_render:site, :post_render钩子都会提供一个负载哈希值作为第二个参数。 如果是 :pre_render,负载可以让你完全掌控渲染过程中的变量。 若是 :site, :pre_render,负载包括渲染所有网站的最后值(可以用于站点地图,订阅等)

完整的钩子列表如下:

容器名 事件名 调用时机

:site

:after_init

在网站初始化时,但是在设置和渲染之前,适合用来修改网站的配置项

:site

:after_reset

网站重置之后

:site

:post_read

在网站数据从磁盘中读取并加载之后

:site

:pre_render

在渲染整个网站之前

:site

:post_render

在渲染整个网站之后,但是在写入任何文件之前

:site

:post_write

在将整个网站写入磁盘之后

:pages

:post_init

每次页面被初始化的时候

:pages

:pre_render

在渲染页面之前

:pages

:post_render

在页面渲染之后,但是在页面写入磁盘之前

:pages

:post_write

在页面写入磁盘之后

:posts

:post_init

每次博客被初始化的时候

:posts

:pre_render

在博客被渲染之前

:posts

:post_render

在博客渲染之后,但是在被写入磁盘之前

:posts

:post_write

在博客被写入磁盘之后

:documents

:post_init

每次文档被初始化的时候

:documents

:pre_render

在渲染文档之前

:documents

:post_render

在渲染文档之后,但是在被写入磁盘之前

:documents

:post_write

在文档被写入磁盘之后

可用的插件

下边的插件,你可以按需索取:

生成器

转换器

过滤器

标签

集合

其他

期待你的作品

如果你有一个 Jekyll 插件并且愿意加到这个列表中来,可以阅读此须知,并参照着来做。

此网站由 @xcatliu 维护,由 开源爱好者们 共同翻译。若发现错误或想贡献翻译,请访问: xcatliu/jekyllCN