Nanoc のカスタマイズ - タグを管理する

Written by @dr_taka_n at 2010/07/25 15:32:45 [, ]

Nanoc でページに付加したタグを管理できるようにする。

ページをタグで管理する

ページをタグ付けして管理する。

やろうとしていることは以下の通り。

  1. 個別のページ(article)で、タグ付けされているタグの名称を表示する
  2. タグの一覧を表示する
    • タグ名とそのタグ付けがされているページの件数を表示
    • タグ名は、同じタグを持つページ一覧へのリンクを持つ
  3. 同じタグを持つページ一覧を表示する
    • 一覧にはページのタイトルが表示される

タグ自体は、各ページ(item)のメタデータで定義をしている。

 --- 
 title: Nanoc のカスタマイズメモ
 tags: [nanoc, ruby]
 created_at: 2010/07/25 15:32:45
 kind: article
 excerpt: Nanoc のカスタマイズメモ
 publish: true
 ---

定義しているタグを表示させるには、標準で用意されているヘルパー Nanoc3::Helpers::Tagging を使う。

以下のメソッドが利用できるようになる。

  • (Array) items_with_tag(tag)
    引数で与えられたタグ名でタグ付けされている全ての item を返す
  • (String) link_for_tag(tag, base_url)
    引数で与えられたタグのリンクを返す。
    例えば、link_for_tag("ruby", "/tags/")という呼び出しを行うと、 <a rel="tag" href="/tags/ruby">ruby</a> という html を返す。
  • (String) tags_for(item, params = {})
    引数で与えられた item にタグ付けされたタグを特定の書式のリストで返す。
    params = {} に指定するオプションとしては、base_url(default: “http://technorati.com/tag/”)、 none_text(default: “(none)”)、separator(default: “, “) がある。

また、過去触れていたが、Nanoc にはタグ関連だけでなく、他にもいろいろな便利な helper メソッドが用意されており、 ここでは、以下の3つのヘルパーが include されていることを前提とする。

include Nanoc3::Helpers::Blogging
include Nanoc3::Helpers::Tagging
include Nanoc3::Helpers::Rendering
include Nanoc3::Helpers::LinkTo

ただ、これからやろうとしていることには、標準の helper メソッドだけでは不足するものあるので、必要なものは随時追加していく。

1. 個別のページで、タグ付けされているタグの名称を表示する

これは、既存の Nanoc3::Helpers::Tagging.tags_for(item, params = {}) を使うことで実現できる。

<%= tags_for(item, { :base_url => '/tags/', :separator => ', ' }) %>

上記は、

<a rel="tag" href="/tags/nanoc">nanoc</a>
,
<a rel="tag" href="/tags/ruby">ruby</a>

と展開される。このサイトでいうと、以下の部分。

Nanoc tags_for

2. タグの一覧を表示する

これを実現するためのユーティリティは標準で用意してくれても・・・と思ったが、無さ気なので用意する。

サイト内のページで定義しているタグ名と、そのタグ付けがされているページの件数をハッシュで返すメソッドを用意する。

lib ディレクトリ配下に、tag_util.rb を用意し、以下の記述を行う。

lib/tag_util.rb:

module TagUtil
  def count_by_tag(items = nil)
    items = @items if items.nil?

    count_by_tag = Hash.new(0)
    items.each do |item|
      if item[:tags]
        item[:tags].each do |tag|
          count_by_tag[tag] += 1
        end
      end
    end
    count_by_tag
  end
end

include TagUtil

上記で記載した TagUtil.count_by_tag と、Nanoc3::Helpers::Tagging.link_for_tag を使って、表示部分を記述する。

表示部分は、部分テンプレートで用意する。layouts ディレクトリに、_tag_summary.html を用意し、以下の記述を行なう。

layouts/_tag_summary.html:

<% tags = count_by_tag(@items) %>

<% if tags %>
  <ul>
  <% tags.sort_by{|e| e[0]}.each do |k, v| %>
    <li><%= link_for_tag(k, "/tags/") %> x <%= v %></li>
  <% end %>
  </ul>
<% else %>
  <p>(none)</p>
<% end %>

上記の部分テンプレートを表示するために、layouts/default.html に記載されているサイドバー部分に表示部分を追加しておく。

<div id="sidebar-wrapper">
  <h2>Tags</h2>
    <%= render('_tag_summary') %>
  ...

これで、「タグ名とそのタグ付けがされているページの件数を表示」「タグ名は、同じタグを持つページ一覧へのリンクを持つ」ことができた。このサイトでいうと、以下の部分。

Tag Summary

次に同じタグを持つページ一覧を表示するページを用意する。

3. 同じタグを持つページの一覧を表示する

タグは、ページを作成する際に、メタデータとして

tags: [nanoc]

という風に書いていく。新なタグを追加する度にそのタグが付けられているページの一覧を表示するためのページをマニュアル(手動)で作成していくのは現実的ではない。

ここでは、動的に on memory でタグ付けされたページの一覧を表示するためのページ(Item)を作成するようにする。

Rules には、preprocess というメソッドに、 全てのデータがロードされた後で、かつ、サイト(Site)がコンパイルされる前に実行されるブロックを記述することができる。

ここで、タグ付けされたページの一覧を表示する Item を動的に作成するようにする。

まず、別出しでメソッドを用意しておく。lib/helper.rb に以下のコードを追加する。

lib/helper.rb:

def create_tag_pages
  tag_set(items).each do |tag|
    items << ::Nanoc3::Item.new(
      "<%= render('_tag_page', :tag => '#{tag}') %>",
      { :title => "Tags: #{tag}", :is_hidden => true },
      "/tags/#{tag}/",
      :binary => false
    )
  end
end

上記の tag_set というのは、全ての Item から使用されているタグの名称を配列で取得するヘルパーメソッドである。これは、lib/tag_util.rb に追加している。

lib/tag_util.rb:

module TagUtil
  def tag_set(items = nil)
    require 'set'

    items = @items if items.nil?
    tags = Set.new
    items.each do |item|
      next if item[:tags].nil?
      item[:tags].each { |tag| tags << tag }
    end
    tags.to_a
  end
  ...

render で使用しているパーシャルページは以下の内容になる。

layouts/_tag_page.html:

<h2>Contents tagged with "<%= tag %>"</h2>

<% if taged_items = items_with_tag(tag) %>
  <ul>
    <% taged_items.sort_by{|e| e[:created_at]}.reverse.each do |item| %>
      <li>
        <%= link_to(item[:title], item.path) %><br />
        <span class="summary-meta-info">
          <%= render('_summary_meta_info', :item => item) %>
        </span>
      </li>
    <% end %>
  </ul>
<% else %>
  <p>none</p>
<% end %>

Rulespreprocess メソッドのブロックに以下の記載を追加し、タグ付けされたページの一覧を表示するための Item を動的に生成する。

Rules:

preprocess do
  ...
  create_tag_pages
end

以上で完了となる!

このサイトでいうと、以下の部分。

Nanoc Tag Page

参考サイト

関連記事

  1. 静的な Web サイト生成ツール Nanoc 基本編 - まずは試してみる
  2. Nanoc のカスタマイズ - 最近の記事一覧の表示
  3. Nanoc のカスタマイズ - タグを管理する
  4. Nanoc のカスタマイズ - 年月毎の記事のアーカイブを用意する
blog comments powered by Disqus