外観のメニュー情報を取得

Markup (JSON-LD) structured in schema.orgプラグインのSchema.org定義に「SiteNavigationElement」というタイプがあって、管理メニュー内にある「外観」→「メニュー」で設定する値を取得してJSON-LD形式で出力しています。(構造化データテストツール参照

このサイトではグローバルナビゲーションを定義対象にしていて、メニュー名をプラグインのテキストボックに直接入力してそのメニュー名から情報を取得する方法をとっています。

Site Navigation テキスト入力画面

この入力形式だと設定する時に外観のメニューを見てからコピーなどして貼り付けという作業がちょっと手間。いずれにしろ登録されていないメニューは表示されないので、登録されているメニューから選択する形式にしたほうがミスも減るなと思い取得方法を調査することにしました。

wp_get_nav_menus関数

外観→メニューのプルダウンの実装を見てみる

外観→メニューを表示しているPHPファイル(/wp-admin/nav-menus.php)を見ていたら発見。wp_get_nav_menus関数で、wp_termwp_term_taxonomyテーブル内にあるメニュー情報を取得してくれるようです。

// Get all nav menus.
$nav_menus = wp_get_nav_menus();

取得した内容をダンプしてみると以下のようなデータを返してくれます。

array (size=8)
  0 => 
    object(WP_Term)[11575]
      public 'term_id' => int 132
      public 'name' => string 'All Pages' (length=9)
      public 'slug' => string 'all-pages' (length=9)
      public 'term_group' => int 0
      public 'term_taxonomy_id' => int 132
      public 'taxonomy' => string 'nav_menu' (length=8)
      public 'description' => string '' (length=0)
      public 'parent' => int 0
      public 'count' => int 40
      public 'filter' => string 'raw' (length=3)
  1 =>
      (以下省略)

欲しいデータは、nameプロパティの値(5行目)なので、この値を使用してselect要素を作成します。

プルダウンの作成

wp_get_nav_menus関数はコールすると配列でデータを返してくれるので、まず配列に値が入っているかチェック。それから1件以上存在すれば、select要素を出力して、ループでoption要素を出力する仕組み。とてもシンプル。

$nav_menus = wp_get_nav_menus();

if ( count( $nav_menus ) > 0 ) {
    echo '<select>';

    foreach ( (array) $nav_menus as $menu ) {
        echo '<option value="' . esc_attr( $menu->name ) . '">';
        echo esc_html( $menu->name );
        echo '</option>';
    }

    echo '</select>';
}

プラグインへの実装

属性の追加

サンプルを元にプラグインに実装します。select要素にname属性をセットしたり、登録している名前とマッチしたらoption要素にselected属性を設定して選択状態にする処理などを追加しました。

private function page_render ( array $option ) {
    $html  = '<table class="schema-admin-table">';
    $html .= '<caption>Basic Setting</caption>';
    $html .= '<tr><th class="require"><label for="menu_name">Menu Name :</label></th><td>';

    $nav_menus = wp_get_nav_menus();

    if ( count( $nav_menus ) > 0 ) {
        $html .= '<select name="option[' . "menu_name" . ']" id="menu_name">';

        foreach ( (array) $nav_menus as $menu ) {
            if ( $option['menu_name'] === $menu->name ) {
                $html .= '<option value="' . esc_attr( $menu->name ) . '" selected>';
            } else {
                $html .= '<option value="' . esc_attr( $menu->name ) . '">';
            }
            $html .= esc_html( $menu->name );
            $html .= '</option>';
        }

        $html .= '</select>';
    }

    $html .= '</td></tr>';
    $html .= '</table>';
    echo $html;

    echo '<p>Setting Knowledge : <a href="https://schema.org/SiteNavigationElement" target="_blank">https://schema.org/SiteNavigationElement</a></p>';
    submit_button();
}

いい感じでできた!\(^o^)/

Site Navigation プルダウン対応

wp_get_nav_menu_items関数

今回の修正では変更することはなかったのですが、選択したメニューにセットしてある内容を出力する、wp_get_nav_menu_items関数に少しふれておきます。

/**
 * Setting schema.org Site Navigation
 *
 * @version 3.2.3
 * @since   3.1.0
 * @param   array $options
 */
private function set_schema_site_navigation ( array $options ) {
    if ( isset( $options['menu_name'] ) && wp_get_nav_menu_items( $options['menu_name'] ) ) {
        $items_array = wp_get_nav_menu_items( $options['menu_name'] );
        $name_array  = array();
        $url_array   = array();

        foreach ( (array) $items_array as $key => $menu_item ) {
            $url_array[]  = $menu_item->url;
            $name_array[] = $menu_item->title;
        }

        if ( count( $items_array ) > 0 ) {
            $args = array(
                "@context" => "http://schema.org",
                "@type"    => "SiteNavigationElement",
                "name"     => $name_array,
                "url"      => $url_array
            );
            $this->set_schema_json ( $args );
        }
    }
}

引数として登録しているメニュー名を渡します。戻り値はWP_Postオブジェクトの配列です。まぁ、メニューの項目は、wp_postテーブルのpost_typeカラムの「nav_menu_item」なので当然そうなりますね。マニュアルにもあるオプションでpost_typeが変更できるという謎の仕様があるのですが、何か便利な使い方があるのだろうか?