rcmdnk's blog

20150704_breadcrumbs_200_200

パンくずリスト(Breadcrumbs)を付けてみました。

カテゴリー分け

Octopressでは元々categoriesを付けられる様になっていますが、 このブログでは加えてタグも付けられる様になっています。

Octopressでのタグの運用

基本的にカテゴリーは1つにして複数のタグを付けてる感じ。

パンくずリストを作るにあたってどういう構造にしようか考えましたが、 色々変更するのも面倒なので、 まずカテゴリーを持ってきて、次にタグの中で一番最初のものを次の層とすることにしました。

ま、取り敢えず作ってみた、ということで。

こんな感じのファイルを_includes/post/に作ります。

source/_includes/post/breadcrumbs.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{% if post %}
  {% assign p = post %}
{% else %}
  {% assign p = page %}
{% endif %}
<ol class="breadcrumbs">
  <li><a href="{{site.url}}"><span>Top</span></a></li>
  {% if p.categories and p.categories.size > 0 %}
    {% capture c %}{{p.categories|first}}{% endcapture %}
    <li><span class="breadcrumbs_separator"></span>
    <a href="{{root_url}}/{{site.category_dir}}/{{c|downcase}}/"><span>{{c}}</span></a></li>
  {% endif %}
  {% if p.tags and p.tags.size > 0 %}
    {% capture t %}{{p.tags|first}}{% endcapture %}
    <li><span class="breadcrumbs_separator"></span>
    <a href="{{root_url}}/{{site.tag_dir}}/{{t|downcase}}/"><span>{{t}}</span></a>
    {% if p.tags.size > 1 %}
      {% for t in p.tags offset:1 %}
        <span>, </span>
        <a href="{{root_url}}/{{site.tag_dir}}/{{t|downcase}}/"><span>{{t}}</span></a>
      {% endfor %}
    {% endif %}
    </li>
  {% endif %}
</ol>

最初のpの設定はアーカイブページ等で読み込まれる場合に 各ページをpostという変数に入れて回す前提です。 (Octopressデフォルトのトップページとかだとそうなってます。)

後はただのolのリストですが、 最初にTopページを表示して、 カテゴリーが無かったりタグが無かったりする場合には飛ばす様にしています。

それから、タグに関しては複数ある場合があるので、 ここでは2番目以降のものもリンクを置くようにしています。

これだけだと最初のタグと後のタグと特に区別はありませんが、 下に書くクローラ向けの設定の所でちょっと変わってきます。

取り敢えず表示させたいだけならこれだけで、後は source/_includes/article.htmlとかに

1
2
3
     <p class="meta">
       {% include post/date.html %}{{ time }}
+      {% include post/breadcrumbs.html %}

みたいな感じで日付の近くとかに適当において上げればOK。

次に、見た目を整えるためにsass/partials/_blog.scss

sass/partials/_blog.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.breadcrumbs {
  margin: 0;
  > li {
    list-style: none;
    display: inline-block;
    text-decoration: none;
    a {
      white-space: normal;
    }
  }
  .breadcrumbs_separator {
    font-weight: bolder;
  }
}

.breadcrumbsクラスの情報を加えます。

さらにsass/partials/_archive.scss

sass/partials/_archive.scss
1
2
3
4
5
-  a.category, a.tag, time {
+  a.category, a.tag, .breadcrumbs, time {
     @extend .sans;
     color: $text-color-light;
   }

と、#blog-archivesの中の書式で、categorytagと同じ フォントや色になるように加えておきます。

これで

breadcrumbs

こんな感じのパンくずリストが付いてそれっぽくなります。

JSON-LDで書くSchema.org情報

Googleのクローラ向けにSchema.orgに従った情報を JSON-LD形式で追加します。

これを正しく記述することで、検索結果の表示のタイトル下の所で、なにもしないと

http://rcmdnk.github.io/blog/2015/06/03/computer-firefox-pocket/

みたいに単にURLが表示されるものが、

rcmdnk.github.io > Computer > Firefox

みたいにパンくずリストが表示される様になります。

最近丁度このSchema.orgのパンくずリストをGoogleもサポートした 1、とか言うのもあったので。

まだちょっと問題がある 2 みたいですが、取り敢えず使ってみたかっただけなのでその辺は余り気にせず。

Breadcrumbs Structured Data Google Developers を参考にして 以下の様な情報ファイルを作ります。

source/_includes/schema.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{% if page.categories or page.tags %}
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement":
  [
  {% assign pos = 1 %}
  {% if page.categories and p.categories.size > 0 %}
    {% capture c %}{{page.categories|first}}{% endcapture %}
    {
      "@type": "ListItem",
      "position": {{pos}},
      "item":
      {
        "@id": "{{site.url}}/{{site.category_dir}}/{{c|downcase}}/",
        "name": "{{c}}"
      }
    }
    {% capture pos %}{{ pos | plus:1}}{% endcapture %}
  {% endif %}
  {% if page.tags %}
  {% if page.tags and page.tags.size > 0 %}
    {% capture t %}{{page.tags|first}}{% endcapture %}
    {% if pos != '1' %},{% endif %}
    {
      "@type": "ListItem",
      "position": {{pos}},
      "item":
      {
        "@id": "{{site.url}}/{{site.tag_dir}}/{{t|downcase}}/",
        "name": "{{t}}"
      }
    }
    {% capture pos %}{{ pos | plus:1}}{% endcapture %}
  {% endif %}
  ]
}
</script>
{% endif %}

ここではタグは最初のものだけを使います。

この出力はこんな感じ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement":
  [
    {
      "@type": "ListItem",
      "position": 1,
      "item":
      {
        "@id": "http://rcmdnk.github.io/blog/categories/blog/",
        "name": "Blog"
      }
    },
    {
      "@type": "ListItem",
      "position": 2,
      "item":
      {
        "@id": "http://rcmdnk.github.io/blog/tags/octopress/",
        "name": "Octopress"
      }
    }
  ]
}
</script>

最初、position 1番目の所に上で書いた表示用のところと同じように Topを持ってきて、その後、2番めにカテゴリー、 3番目にタグ、とやっていたのですが、これだと 検索結果ページを見た時に、

rcmdnk.github.io > Top > Blog > Octopress

となって、最初の2つが被る状態になってしまうので Topの部分は外しました。

これをsource/_includes/after_footer.htmlとかで(</body>直前)読み込んでおきます。

これでしばらくするとGoogleが認識してくれます。

とりあえずサイトをアップデートしたら、 GoogleのStructured Data Testing Tool Google Developers でテストしてみます(実際にGoogleのクローラが見つける前でもページのHTMLを直接見てチェックしてくれます)。

structureddatatestingtool

こんな感じでBreadcrumbListが認識されてればOK。

これで2,3日経って認識してもらえると

googleresult

こんな感じでパンくずリスト表示されるようになります。

MICRODATAで書くSchema.org情報

上では実際にページに表示されるものと、 クローラ用の情報を別の場所に書きましたが、 MICRODATA(またはRDFA)の書式で書けば表示場所に全て書き込むことが出来ます。

source/_includes/post/breadcrumbs_microdata.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{% if post %}
  {% assign p = post %}
{% else %}
  {% assign p = page %}
{% endif %}
<ol class="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">
  <li><a href="{{site.url}}"><span>Top</span></a></li>
  {% assign pos = 1 %}
  {% if p.categories and p.categories.size > 0 %}
  {% capture c %}{{p.categories|first}}{% endcapture %}
  <li itemprop="itemListElement" itemscope
      itemtype="http://schema.org/ListItem">
    <span class="breadcrumbs_separator"> > </span>
    <a itemprop="item" href="{{site.url}}/{{site.category_dir}}/{{c|downcase}}/">
      <span itemprop="name">{{c}}</span></a>
    <meta itemprop="position" content="{{pos}}" />
  </li>
  {% capture pos %}{{ pos | plus:1}}{% endcapture %}
  {% endif %}
  {% if p.tags and p.tags.size > 0 %}
  {% capture t %}{{p.tags|first}}{% endcapture %}
  <li itemprop="itemListElement" itemscope
      itemtype="http://schema.org/ListItem">
    <span class="breadcrumbs_separator"> > </span>
    <a itemprop="item" href="{{site.url}}/{{site.tag_dir}}/{{t|downcase}}/">
      <span itemprop="name">{{t}}</span></a>
    <meta itemprop="position" content="{{pos}}" />
    {% if p.tags.size > 1 %}
      {% for t in p.tags offset:1 %}
        <span>, </span>
        <a href="{{root_url}}/{{site.tag_dir}}/{{t|downcase}}/"><span>{{t}}</span></a>
      {% endfor %}
    {% endif %}
    </li>
  </li>
  {% capture pos %}{{ pos | plus:1}}{% endcapture %}
  {% endif %}
</ol>

こんな感じ。

基本、 Breadcrumbs Structured Data Google Developers のMICRODATAのサンプルをそのまま使っただけです。

最初こっちの方が別の所に余計な事を書かなくて良いので良いかな、 と思ったのですが、 これだと同じページで2つ上と下にパンくずリストを見せたいと思うと 両方でSchema.orgの情報が見つかって邪魔臭いのと、 さらにアーカイブページとかで パンくずリストを載せてしまうとそのページに大量にパンくずリストが見つかってしまいます。

この辺、同じページに大量にあると最初のものだけを認識したりするみたいですが、 あまりすっきりしないので分けて、 schema.htmlの方は一つのページで最後に一つだけ読み込むようにしました。

まとめ

カテゴリー分けやタグ分けをしてれば Octopress(Jekyll)でも簡単にパンくずリストを表示することが出来ました。 (単に今までただ羅列してたのを整理しただけみたいなもんですが。)

さらにGoogleの検索結果にも反映させることが出来ました。 検索結果表示を自分で変更できるとちょっと楽しい。

それから上にも書いた問題点ですが、 このブログを更新した際にも

googleresultstrange

こんな感じで2番目の物がFirefox > Firefox > Firefox...となってしまったりしました。

これは最初にMICRODATAでやってた時のものですが、 JSON-LD形式の方がちゃんとしてるのかたまたまなのか、 今はきちんとこのページの表示もFirefox一つだけになってます。

まだ一部のページは反映されずにURLがそのまま載ってたりもしますが、 取り敢えず思ったよりも簡単に出来てGoogleの検索結果とかも変えられて面白かったな、と。

Sponsored Links
  1. これまでは Data-Vocabulary.org のものだけしか認識してくれなかったのが、 ようやくSchema.orgのものでも認識できる様になったとのこと。

    schema.orgのパンくずリストをようやくGoogleがサポート開始 海外SEO情報ブログ

  2. schema.orgのパンくずリストに不具合あり、実装は待ったほうがいいかも 海外SEO情報ブログ

Sponsored Links

« サーバーに接続できない->TIME_WAITが大量にポートを食い尽くしてる THERMOS 真空断熱タンブラーが机での作業で便利 »

}