產生器

當您需要 Jekyll 根據您自己的規則建立其他內容時,您可以建立一個產生器。

產生器是 Jekyll::Generator 的子類別,它定義了一個 generate 方法,該方法接收 Jekyll::Site 的執行個體。 generate 的傳回值會被忽略。

在 Jekyll 清點現有內容後,產生器才會執行,而且會在產生網站之前執行。包含 front matter 的頁面會儲存為 Jekyll::Page 的執行個體,並可透過 site.pages 取得。靜態檔案會變成 Jekyll::StaticFile 的執行個體,並可透過 site.static_files 取得。請參閱 變數文件頁面Jekyll::Site 以取得詳細資料。

在以下範例中,產生器會在建置時注入計算出的範本變數值。名為 reading.html 的範本有兩個未定義的變數 ongoingdone,這些變數會在產生器執行時定義或指定值

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

下列範例是一個較複雜的產生器,用來產生新頁面。

在此範例中,產生器的目標是為 site 中註冊的每個類別建立一個頁面。這些頁面會在執行階段建立,因此其內容、前置資料和其他屬性需要由外掛程式本身設計。

  • 這些頁面用來呈現特定類別下所有文件的清單。因此,已呈現檔案的基本檔名應為 index.html
  • 透過 前置資料預設值 設定頁面的能力將會非常棒!因此,將特定 type 指定給這些頁面將會很有幫助。
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

現在,已產生的頁面可以設定為使用特定配置或輸出至目標目錄中的特定路徑,所有這些都可以透過設定檔使用前置資料預設值來完成。例如

# _config.yml

defaults:
  - scope:
      type: categories  # select all category pages
    values:
      layout: category_page
      permalink: categories/:category/

技術層面

產生器只需要實作一個方法

方法 說明

generate

產生內容作為副作用。

如果您的產生器包含在單一檔案中,則可以命名為您想要的任何名稱,但應具有 .rb 副檔名。如果您的產生器分佈在多個檔案中,則應將其打包為 Rubygem,並發佈在 https://rubygems.org/。在此情況下,寶石的名稱取決於該網站上名稱的可用性,因為沒有兩個寶石可以具有相同的名稱。

預設情況下,Jekyll 會在 _plugins 目錄中尋找產生器。但是,您可以透過在設定檔中將所需的目錄名稱指定給金鑰 plugins_dir 來變更預設目錄。