太陽がまぶしかったから

C'etait a cause du soleil.

はてなブログでパンくずリストを認識させたよ

f:id:bulldra:20140923205005p:plain

修正版のご連絡

 以下に紹介しているスクリプトは古いので、上記をご覧ください。

はてなブログのカテゴリ構造をGoogleに認識させる

 シブヤタクトさんの『カテゴリー構造の最適化とバックリンクのチェックでPVアップを目指しましょう | 日常ぴよぴよ』を読んで、「うちのブログもカテゴリ分けを意識しないといけないなー」とつぶやいていたのですが、はてなブログのカテゴリではパンくずリストのマークアップが実現されていない事を教えて頂きました。

せっかくカテゴリー構造を最適化しても、それをGoogleが確認できないんじゃーもったいないです。 必ずパンくずリストを設定し、マイクロデータ形式でマークアップしてあげましょう。 Wordpressで言うと、SEOに強いと謳っているテーマのStinger3やGush、principleはマークアップがデフォルトで実装されております。

カテゴリー構造の最適化とバックリンクのチェックでPVアップを目指しましょう | 日常ぴよぴよ

 最近のGoogle検索ではブログ内のカテゴリを認識して、検索結果がサイト上のどこに位置付けられているかを表示するようになっているのですが、breadcrumbタグを利用したマークアップをしていないとGoogleから認識してもらえないのです。

f:id:bulldra:20140923213746p:plain

 このためJavaScriptでパンくずリストを生成してGoogleに認識させ、またGoogleにカテゴリ認識をさせるのであればカテゴリの階層構造化も実装することを考えました。そうは言っても本当に実現可能かどうかは半信半疑であって、シブヤさんにも相談してJavaScriptの作成を手伝って頂きました。

 結論から言えば、はてなブログでもカテゴリ階層化とGoogleからの認識が可能です。『Google』をご覧ください。

f:id:bulldra:20140921163843p:plain

カテゴリの疑似階層構造の仕組み

 はてなブログには標準機能でカテゴリの階層構造化ができませんが、「親カテゴリ」「親カテゴリ-子カテゴリ」といった命名規則を用いることで擬似的に管理可能とします。「-」を区切り文字にしているのは子カテゴリ名での検索対策))。「TOP > 親カテゴリ > 子カテゴリ」の三段階のみ対応です。

f:id:bulldra:20140923212435p:plain

 あるエントリを書く場合においては、「サブカル」「サブカル-ゲーム」といった2つのカテゴリに属させることで、「サブカル」としての絞り込みと「サブカル-ゲーム」としての絞り込みを可能とします。画面上では「サブカル」と「サブカル-ゲーム」がある場合には「TOP > サブカル > ゲーム」といった形にスクリプトで表示を変形させています。

f:id:bulldra:20140923220650p:plain

 また本スクリプトを有効にした状態でサイドバーのカテゴリー表示機能を利用した場合には親カテゴリのみを表示するようにします。エントリを複数のカテゴリに属させる事も可能ですが、パンくずリストが認識するのは1つ目の子カテゴリとなっています。

JavaScriptの配置

 デザイン画面のフッタに以下のスクリプトを配置します。

f:id:bulldra:20140923211820p:plain

※JavaScript中の「topUrl」には自サイトのURLをお願いします

<script type="text/javascript">

/* カテゴリモジュールでルートカテゴリのみ表示 */
var rootCategories = new Array();
var childCategories = new Array();
var categoryModule = document.querySelector("div.hatena-module-category div.hatena-module-body");

if(categoryModule != null) {
  var cateogryList = categoryModule.querySelectorAll("ul li a");
  for(var idx in cateogryList) {
      if(cateogryList[idx] == null || cateogryList[idx].text == null) {
          continue;
      }
      var es = cateogryList[idx].text.split("-");
      if(es.length >= 2) {
        cateogryList[idx].text = es[es.length - 1];
        var key = es[0].replace(/\s+/g, "");
        if(childCategories[key] == null) {
          childCategories[key] = new Array();
        }
        childCategories[key].push(cateogryList[idx]);
      } else {
        var key = cateogryList[idx].text.replace(/\s+/g, "");
        key = key.replace(/\([0-9]+\)$/,"");
        rootCategories[key] = cateogryList[idx];
      }
  }

  var html = '<ul class="hatena-urllist">';
  for(var key in rootCategories) {
    if(!(rootCategories[key].outerHTML === void 0)) {
      html += '<li>' + rootCategories[key].outerHTML + '</li> ';
    }
  }
  categoryModule.innerHTML= html;
}

/* カテゴリー階層化対応 */
var topUrl = "";
var categoryElements = document.querySelectorAll("div.categories a");
var urlMap = new Array();
var flagMap= new Array();

function appendCategoryLink(span, title, url) {
  var a = document.createElement('a');
  a.innerHTML = title;
  a.href = url;
  a.itemprop="url";
  span.appendChild(a);
}

for(var idx in categoryElements) {
  var c = categoryElements[idx];
  if(c.text == null) {
    continue;
  } 
  urlMap[c.text] = c.href.replace(topUrl + '/category', topUrl + '/archive/category');;
  flagMap[c.text] = false;
}

for(var idx in categoryElements) {
  var c = categoryElements[idx];
  if(c.text == null) {
    continue;
  }
  c.href = c.href.replace(topUrl + '/category',topUrl + '/archive/category');
  var es = c.text.split('-');
  if(es.length >= 2) {
    c.innerHTML = es[es.length - 1];
  }
}

var categoryResult = new Array();
var result = new Array();

/* 階層化カテゴリ用 */
for(var key in urlMap) {
  var es = key.split('-');
  if(es.length >= 2) {
    if(urlMap[es[0]] != null) {
      var categorySpan =  document.createElement("span");
      appendCategoryLink(categorySpan, "TOP", topUrl);
      categorySpan.appendChild(document.createTextNode(" > "));
      appendCategoryLink(categorySpan, es[0], urlMap[es[0]]);
      categorySpan.appendChild(document.createTextNode(" > "));
      appendCategoryLink(categorySpan, es[es.length - 1],  urlMap[key]);
      categoryResult.push(categorySpan);
      
      var html = "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
      html += "<a href='" + topUrl + "' itemprop='url'>";
      html += "<span itemprop='title'>TOP</span>";
      html += "</a>";
      html += "</div>";
 
      html += " > ";
      html += "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
      html += "<a href='" + urlMap[es[0]] + "' itemprop='url'>";
      html += "<span itemprop = 'title'>" + es[0] + "</span>";
      html += "</a>";
      html += "</div>";
      html += " > ";
      html += "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
      html += "<a href='" + urlMap[key] + "' itemprop='url'>";
      html += "<span itemprop = 'title'>" + es[es.length - 1] + "</span>";
      html += "</a>";
      html += "</div>";
      
      var title = document.querySelector("h1.entry-title a");

      if(title != null){
        html += " > ";
        html += "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
        html += "<span itemprop = 'title'>" + title.text + "</span>";
        html += "</div>";
      }
      console.log(html);
      result.push(html);
      flagMap[es[0]] = true;
      flagMap[key] = true;
    } else {
      flagMap[key] = false;
    }
  }
}

/* 階層化してないカテゴリ用 */
for(var key in flagMap) {
  if(flagMap[key] == false) {
    var categorySpan = document.createElement("span");
    appendCategoryLink(categorySpan, "TOP", topUrl);
    categorySpan.appendChild(document.createTextNode(" > "));
    appendCategoryLink(categorySpan, key, urlMap[key]);
    categoryResult.push(categorySpan);
  
    var html = "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
    html += "<a href='" + topUrl + "' itemprop='url'>";
    html += "<span itemprop='title'>TOP</span>";
    html += "</a>";
    html += "</div>";
 
    html += " > ";
    html += "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
    html += "<a href='" + urlMap[key] + "' itemprop='url'>";
    html += "<span itemprop = 'title'>" + key + "</span>";
    html += "</a>";
    html += "</div>";

    var title = document.querySelector("h1.entry-title a");
    if(title != null) {
      html += " > ";
      html += "<div itemscope='' itemtype='http://data-vocabulary.org/Breadcrumb'>";
      html += "<span itemprop = 'title'>" + title.text + "</span>";
      html += "</div>";
    }
    result.push(html);
  }
}

/* パンくずリスト書き出し */
var categoryHTML = document.querySelector("div#breadcrumb");
if(result.length > 0 && categoryHTML != null) {
  categoryHTML.innerHTML = '';
  categoryHTML.innerHTML = result[0];
  
  var categories = document.querySelector("div.categories");
  if(categoryResult.length > 0 && categories != null) {
    categories.innerHTML = '';
    for(var idx in categoryResult) {
     if(categories !=null && categoryResult[idx] != null && !(categoryResult[idx].outerHTML === void 0)){
        categories.innerHTML += categoryResult[idx].outerHTML;
        if(idx < result.length -1) {
          categories.innerHTML += '<br/>';
        }
     }
    }
  }
}

</script>

 記事上や記事下などのパンくずリストを表示させたい場所に以下のHTMLを記述します。

f:id:bulldra:20140923212043p:plain

<style>
div #breadcrumb div {
    display: inline;
    font-size: 13px;
}
</style>
<div id="breadcrumb"></div>

GoogleのJavaScript認識評価

 現在のGoogleはJavaScriptを実行した上で生成されたリンクやマークアップを解釈しています。『Webmasters – Google』の「Fetch as Google」においてGoogle Botが行ったレンダリング結果が取得できますので、こちらを確認するとJavaScriptで生成されたパンくずリストもGoogle Botは認識可能であるということが分かります。

f:id:bulldra:20140923210514p:plain

 ちなみに、はてなスターを司っているJavaScriptファイルは「robots.txt により拒否されました」となっており、Google Bot上でのリンク生成も行われていないため、「はてなスターによってSEOやリンクジュースに悪影響がある」といった話はデマであると判断しています。

f:id:bulldra:20140923210655p:plain

 本スクリプトの運用開始から1週間ほどかけてGoogleからクロールしなおされ、Googleからカテゴリを認識してもらえるようになります。ウェブマスターツールの構造化データの画面から、どこまで認識しているのかのグラフが表示可能です。

 以上のようなハックを用いることで、はてなブログのカテゴリを階層構造に対応にさせてGoogleにカテゴリ認識させる事が可能となります。SEOとしての実際的な効果については保証ができませんし、適用についても自己責任にして頂きたいと考えておりますが、検索エンジンからのナビゲーションがよくなるのは明白です。本来的には基本機能として実装されるべきものですが「ないものは作る」の精神で作りました。こういうのを勉強して実現していくのはなかなか楽しいですね。なお、設置サポートや表示スタイル/アルゴリズムのカスタマイズ等のご依頼がありましたらサポートライセンスの購入をお願いいたします。

How Google Works (ハウ・グーグル・ワークス)  ―私たちの働き方とマネジメント

How Google Works (ハウ・グーグル・ワークス) ―私たちの働き方とマネジメント

  • 作者: エリック・シュミット,ジョナサン・ローゼンバーグ,アラン・イーグル,ラリー・ペイジ,土方奈美
  • 出版社/メーカー: 日本経済新聞出版社
  • 発売日: 2014/10/09
  • メディア: 単行本
  • この商品を含むブログ (15件) を見る

関連記事