パンくずリストの構造化(schema.org)

更新:

schema.org のマークアップによりパンくずリストを構造化する手順。

構造化

パンくずリストというのはサイトでよく見かける[トップ > パソコン > Windows]のような階層を表すナビゲーションですが、その構造を HTML 内に記述することで Google などの検索エンジンに構造を伝えることができます。 それにより、検索結果のスニペットの URL が表示される部分に階層を表す文字列が表示されるようになります。

構造化していると思われるサイトのソースを見ると data-vocabulary.org や schema.org というドメイン名を見かけます。 data-vocabulary.org のマークアップは古く、今から使うメリットは特にないので、ここでは新しい schema.org のマークアップについて書く。

schema.org

microdata

構造化については、実際に schema.org のマークアップが使われているサイトのソースを見るのが一番分かりやすいと思います。 2018年現在、schema.org を使っている大きいサイトとしては、ウェブサイト制作ではお馴染みの Mozilla のサイト MDN があります。 例えば、nav 要素のページのパンくずリストを見ると以下のように記述されています。

<ol typeof="BreadcrumbList" vocab="https://schema.org/" aria-label="パンくずリスト">

<li property="itemListElement" typeof="ListItem" class="crumb">
<a href="/ja/docs/Web" property="item" typeof="WebPage">
<span property="name">開発者向けのウェブ技術</span>
</a>
<meta property="position" content="1">
</li>

<li property="itemListElement" typeof="ListItem" class="crumb">
<a href="/ja/docs/Web/HTML" property="item" typeof="WebPage">
<span property="name">HTML</span>
</a>
<meta property="position" content="2">
</li>

<li property="itemListElement" typeof="ListItem" class="crumb">
<a href="/ja/docs/Web/HTML/Element" property="item" typeof="WebPage">
<span property="name">HTML 要素リファレンス</span>
</a>
<meta property="position" content="3">
</li>

<li property="itemListElement" typeof="ListItem" class="crumb">
<span property="name">&lt;nav&gt;: ナビゲーションセクション要素</span>
</li>

</ol>

li 要素に property="itemListElement" typeof="ListItem"、a 要素に property="item" typeof="WebPage"、span 要素に property="name" で階層の名前、meta 要素に property="position" content="1" で階層を記述する。 階層の上から順に 1、2、3、・・・。 MDN では最終的に表示されるページには meta 要素がありません。 サイトによってはここにも meta 要素を書いている例もあります。

aria-label や class="crumb" は MDN のサイトのものなので書かなくても問題ありません。

ol や li 要素で記述していますが、div や span などで書いても OK です。

階層のトップはトップページでなくても OK です。

注意点としては、同じ階層にある別々のページで同じ階層名を使わないようにします。 上の例では span 要素で囲んだ部分が階層名になります。 自分で階層構造と階層名を把握しておく必要があります。

Google サーチコンソールで確認する

サイトの構造が認識されているかどうか Google サーチコンソールにて確認できます。 まず登録したサイトを選んだ後、メニューの[検索での見え方]→[構造化データ]と進みます。 正しく認識されていれば、[データタイプ]BreadcrumbList、[ソース]マークアップ: schema.org、さらにページ数などが表示されます。 さらにクリックして進むとページの URL のリストも表示されます。 Google に認識されるまで多少時間がかかります。

私のサイトは MDN と同じ書き方をして、サーチコンソールで構造化を確認できました。

PHP で変換して出力する

メジャーな CMS だと、構造化の便利なプラグインが見つかるかもしれませんが、私のサイトは CMS を使わず自作しているので、どうしようかなと。 タグを書くのが面倒なので、とりあえず PHP で microdata を生成する関数を作ってみることにしました。 まあ、探せば便利なコードが見つかるかもしれませんが。

microdata に必要なデータとしては、階層のパス(またはURL)、階層名、階層レベルの3点。 とりあえず階層の上から順にパスと名前の組み合わせを配列で作り、それを関数に投げると microdata になれば良いかなと考えた。

検索エンジンに階層を伝える手段として microdata の他に JSON-LD もあります。 これは特に何かをページに表示するわけでもなく、単に構造を伝えるだけのデータです。 どうせ作るなら JSON-LD も生成できるようにした。

$item_list = array(
    array('https://example.com/', 'トップ'),
    array('https://example.com/pc/', 'パソコン'),
    array('https://example.com/pc/windows/', 'Windows'),
    array('https://example.com/pc/windows/soft/', 'ソフト')
    );

echo get_breadcrumb_list($item_list)['plain'];//普通のパンくずリスト
echo get_breadcrumb_list($item_list)['microdata'];//microdata
echo '<script type="application/ld+json">'
	. get_breadcrumb_list($item_list)['json']
	. '</script>';//JSON-LD

function get_breadcrumb_list($item_list){
    $breadcrumb_list = array();
    $item_list_last = array_pop($item_list);
    $count = count($item_list);
    
    $plain_item = '';
    $microdata_item = '';
    $json_item = array();
    
    for($i=0;$i<$count;$i++){
        $plain_item .= '<li><a href="' . $item_list[$i][0] . '">' . $item_list[$i][1] . '</a></li>';
        
        $microdata_item .= '<li property="itemListElement" typeof="ListItem"><a href="' . $item_list[$i][0]
            . '" property="item" typeof="WebPage"><span property="name">' . $item_list[$i][1]
            . '</span></a><meta property="position" content="' . ($i + 1) . '"></li>';
        
        $json_item[] = '{"@type": "ListItem", "position": ' . ($i + 1) . ', "item": {"@id": "'
            . $item_list[$i][0] . '", "name": "' . $item_list[$i][1] . '"}}';
    }
    
    $breadcrumb_list['plain'] = '<ol>' . $plain_item
        . '<li>' . $item_list_last[1] . '</li></ol>';
    
    $breadcrumb_list['microdata'] = '<ol typeof="BreadcrumbList" vocab="https://schema.org/">'
        . $microdata_item
        . '<li property="itemListElement" typeof="ListItem"><span property="name">'
        . $item_list_last[1] . '</span></li></ol>';
    
    $breadcrumb_list['json'] = '{"@context": "http://schema.org", "@type": "BreadcrumbList", "itemListElement": ['
        . implode(',', $json_item) . ']}';
    
    return $breadcrumb_list;
}

まず、階層名とそのURLを書いた配列を用意します。 position の指定はせず、多次元配列の先頭から順に 1、2、3、・・・とみなします。 連想配列を使うことも考えましたが、多次元配列の方がパラメータが増えたときに都合が良さそうです。

次にその配列を get_breadcrumb_list() 関数に渡します。 この関数は「ただのパンくずリスト」、「microdata」、「JSON-LD」の3種類を格納した配列を返します。 配列のキーはそれぞれ [plain]、[microdata]、[json] になっているので、取り出すときは該当するキーを指定します。 関数の第2引数に取得したいデータを指定し、必要な値だけ受け取る方法も考えましたが、全部生成して、配列から必要なものだけ取り出す形にしました。

多次元配列にある最後の配列を最終ページとみなします。 MDN のサイトと同じように最終ページは meta 要素を書かず、リンクを張らないスタイルにしています。 それに伴い JSON-LD も最終ページは出力せず、その上の階層までを出力しています。

ol、li 要素を使っているので、これを横に並べる場合、例えば以下のような CSS を書きます。 「>」マークは CSS にて表示します。 ここでは class や id を指定していませんが、サイトに合わせて適宜指定します。

ol {margin:0;padding:0;}
ol li {display:inline-block;margin:0 0 0 0.5em;padding:0;}
ol li:first-child {margin:0;}
ol li:first-child:before {content:"";}
ol li:before {content:"> ";}

とりあえず適当に作りましたが、サイトによっていろいろ都合があるので、この方法が良いか分かりません。 ここまで書いておいて、自分のサイトでまだ使っていません。 気が向いたら実装しようと思います。

data-vocabulary.org

冒頭で使うメリットはないと言いつつ、一応 data-vocabulary.org の microdata も書いておきます。

2018年現在、data-vocabulary.org でパンくずリストを記述している大手のサイトとしては、Yahoo!知恵袋と価格.comがあります。

以下、Yahoo!知恵袋のパンくずリストです。

<ol id="bcrmb" data-ult_sec="1">
<li itemtype="http://data-vocabulary.org/Breadcrumb" itemscope="">
<a itemprop="url" href="https://chiebukuro.yahoo.co.jp"><span itemprop="title">知恵袋トップ</span></a>
&gt;
</li>
<li itemtype="http://data-vocabulary.org/Breadcrumb" itemscope="">
<a itemprop="url" href="https://chiebukuro.yahoo.co.jp/dir/list/d2080401469/new"><span itemprop="title">スマートデバイス、PC、家電</span></a>
&gt;
</li>
<li itemtype="http://data-vocabulary.org/Breadcrumb" itemscope="">
<a itemprop="url" href="https://chiebukuro.yahoo.co.jp/dir/list/d2080401529/new"><span itemprop="title">パソコン</span></a>
</li>
</ol>

階層のページがページ送りなどで複数のページに渡る場合でも、その階層のトップ(最初のページ)の URL が指定されています。

以下、価格.comのパンくずリストです。

<div class="path">
<span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/" itemprop="url"><span itemprop="title">ホーム</span></a>
</span>
&gt; 
<span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="/pc/" itemprop="url"><span itemprop="title">パソコン</span></a>
</span>
&gt; 
<span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">メモリー</span>
</span>
</div>

両サイトで書き方が若干異なる部分がありますが、schema.org よりシンプルな印象です。