wp_nav_menu カスタムメニューにメタデータを埋め込む

wp_nav_menu 関数はカスタムメニューを表示するための関数(テンプレートタグ)です。 メニューの前後に表示する(HTML)テキストを指定したり、メニューを覆うラッパーの要素を指定するなど、細かな制御が可能です。

しかしながら、schema.org が提唱するような、itemprop などを用いたメタデータを埋め込むための機能は用意されていません。 nav_menu_item_id などのフィルタにフックすれば、class 名や id 名を細かく制御することができますが、 いずれの方法でも、class 名や id 名以外を設定することはできません。

したがって、メニューに関する独自のデータや、あるいはメタデータを埋め込みたい場合には、 wp_nav_menu 関数が出力する HTML テキストを独自にカスタマイズする必要があります。

幸いなことに wp_nav_menu 関数は、独自の HTML テキストを出力するための機能を備えています。 パラメータ walker に対し、独自に実装するクラスを指定することで、メタデータの埋め込みなどが可能になります。

ここでは schema.org の提唱するメタデータ SiteNavigationElement を埋め込む例を示します。

wp_nav_menu - Codex 日本語版

wp_nav_menu 関数の設定

先に wp_nav_menu 関数の設定について解説しておきます。 ここで解説されない項目や詳細については公式のページを確認してください。

<nav class="site-navigation main-navigation" role="navigation"
     itemscope itemtype="http:\/\/schema.org/SiteNavigationElement">
    wp_nav_menu
    (array('theme_location' => '設定したメニューのスラッグ',
           'container' => false,
           'items_wrap' => '<ul>%3$s</ul>',
           'walker' => new Karakuri_Walker_Nav_Menu));
</nav>
wp_nav_menu の設定

container パラメータ に false を指定して、div や nav などのラッパーを出力しないようにします。 代わりに schema.org のSiteNavigationElement メタデータを埋め込んだ nav 要素を任意に追加します。

items_wrap パラメータには、出力するメニューの一番外側の要素を指定します。 このとき、%3$s の記述を忘れないようにします。ここに具体的なメニュー (li 要素) が挿入されます。 nav 要素ではなく、ここで指定する ul 要素に itemscopeitemtype を指定するのも手だと思います。

最後に指定する walker パラメータが重要です。 walker には、具体的なメニューを出力するクラス Walker_Nav_Menu を指定します。 標準のメニューを出力する Walker_Nav_Menu クラスではなく、 独自のメニューを出力する Walker_Nav_Menu を指定します。

Walker_Nav_Menu クラスの実装(定義)

標準の Walker_Nav_Menu クラスは、./wp-includes/nav-menu-template.php ファイルの中に定義されています。 この Walker_Nav_Menu` クラスを継承したクラスを実装します。

"継承" はプログラミングする際に用いられる用語なので、WordPress などのみを触っている人には理解しにくいかもしれません。 ちょうど CSS の継承の概念を想像すれば良いのですが、端的には、元々あった機能を引き継いだ、わずかに変更された機能を作ることを継承と言います。

ここでは、標準の Walker_Nav_Menu クラス(の機能)を引き継いだ、別の Walker_Nav_Menu を作ることになります。 新たに作る Walker_Nav_Menu を仮に Custom_Walker_Nav_Menu とします。

次のコードが schema.org のメタデータを埋め込む Custom_Walker_Nav_Menu クラスです。 functions.php など、wp_nav_menu 関数が参照できる場所(ファイル)に定義します。

class Custom_Walker_Nav_Menu extends Walker_Nav_Menu
{   
    function start_el(&$output, $item, $depth, $args)
    {
        $output .= '<li itemprop="name" class="menu-item">';
        $item_output .= '<a itemprop="url" href="'
                        . esc_attr($item -> url) .'">'
                        . $item -> title . '</a>';
        $output .= apply_filters('walker_nav_menu_start_el',
                                  $item_output,
                                  $item,
                                  $depth,
                                  $args);
    }
}
schema.org を埋め込む Walker_Nav_menu

Walker_Nav_Menu クラスには他にもいくつかの関数(機能)がありますが、"継承" しているので、 Custom_Walker_Nav_Menu クラスでは改めてそれらの関数を作る必要がありません。

start_el 関数だけが元の機能を書き換えています。 元の関数(機能)を書き換えるためには、関数名を一致させる必要があるので注意してください。 同じ関数名で上書きすることを、プログラミング用語では、関数のオーバーライドと呼びます。

start_el 関数は、li 要素を出力する関数です。 したがって、ここで schema.org のメタデータを埋め込むことができます。

schema.org のメタデータについてはここでは解説しません。 <li itemprop="name" class="menu-item"> のように、 独自のデータが埋め込まれていることが分かると思います。

wp_nav_menu 関数では、before や after などのパラメータが定義されます。 それらは、$args -> before$args -> after のようにして取得することができます。 汎用的な Walker_Nav_Menu を作るためには、それらを出力に追加する必要がありますが、 ここでは簡単に説明するために省略しています。

理想的な出力結果の例

ここで実装した Custom_Walker_Nav_Menu クラスを使った理想的なカスタムメニューの例を示します。 例えば、テンプレートファイル内で次のようにカスタムメニューを出力させます。

<nav class="site-navigation main-navigation" role="navigation">
<?php
wp_nav_menu
(array('theme_location' => '設定したメニューのスラッグ',
       'container' => false,
       'items_wrap' => '<ul itemscope itemtype="http:\/\/schema.org/SiteNavigationElement">%3$s</ul>',
       'walker' => new Custom_Walker_Nav_Menu));
?>
</nav>
wp_nav_menu

出力結果は次の通りです。

<nav class="site-navigation main-navigation" role="navigation"
     itemscope itemtype="http:\/\/schema.org/SiteNavigationElement">
    <ul>
    <li itemprop="name" class="menu-item">
        <a itemprop="url" href="URL">メニュータイトル</a>
        <ul class="sub-menu">
        <li itemprop="name" class="menu-item">
            <a itemprop="url" href="URL">サブメニュータイトル</a>
        </li>
        </ul>
    </li>
    </ul>
</nav>
Custom_Walker_Nav_Menu から出力された美しい HTML

紹介する都合上、出力結果を整形しています。出力されるソースコードを適切にインデントしたい場合には、 start_el 関数の引数 $depth を使って、メニューの深度に応じてインデントするコードを出力します。

SiteNavigationElement のマークアップ方法について

schema.org の提唱する SiteNavigationElement の指定方法については、執筆時時点(2015.06)では明らかにされていません。 単に SiteNavigationElement だけを指定し、itemprop="name"itemprop="url" を指定しない、という見方もあります。 状況に応じて、適宜更新するなどしてください。

What is the correct use of schema.org SiteNavigationElement? - stackoverflow

ここで紹介する方法は、Google の構造化テストツールではエラーが起きませんでした。 一方で、メタデータとして正しい構造であるか、正しい意味を伝えられているのかどうか、は不明です。