意外と大変なパンくずリスト
WordPressサイトに限らず、SEOの面でも重要視されるパンくずリスト(breadcramb nav)。
WordPressでガチで実装すると意外と面倒ですよね。
個別投稿ページだけでも、
A. 標準投稿
HOME > 親カテゴリ > 子カテゴリ > 投稿名
B. 固定ページ
HOME > 親ページ > ページ名
C. カスタム投稿
HOME > タイプ名 > 親ターム > 子ターム > 投稿名
のように、色々なパターンがあります。
これに、各種アーカイブページまで考え始めると、なかなか大変です。
また仕様面でも、
1. 投稿タイプに複数種類のタクソノミー(例えばカテゴリーとタグ)が紐付いている場合、どちらをパンくずリストに使用するのか
2. 投稿に複数のターム(例えばカテゴリAとカテゴリーB)が設定されている場合、どちらを表示するのか
など、考えなければいけません。
逆に仕様さえ決まってしまえば、やることは単純なので、プラグインなしでパンくずリストを表示するのはそれほど難しくありません。
パンくずリストを表示するためのクラス(microdata版)
上記1・2の課題に関しては
1. 使用するタクソノミーを定数で定義する
2. term_id が最も大きなものを採用する(子孫カテゴリほど term_id が大きくなりやすいので)
という対応を取っています。
マークアップ形式は Schema.org 準拠の microdata です。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
<?php class My_Breadcramb { //パンくずの起点部分のトップページへのリンク。不要な場合は空白に。 const HOME_LABEL = "HOME"; //個別投稿ページのパンくずに表示するタクソノミー。不要な場合は空白もしくは項目削除。 const SHOW_TAXONOMIES = array( 'post' => 'category', 'products' => 'genre' ); private $paths = array(); private $post = null; private $term = null; private $post_type = null; public function __construct() { $this->prepare(); } /** * パンくずに使う情報を取得して配列に格納 */ public function prepare() { //まずは必要なオブジェクトを取得 if ( is_singular() ) { //個別ページ global $post; $this->post = $post; //標準投稿と固定ページ以外なら投稿タイプを取得 if ( $post->post_type != 'post' && $post->post_type != 'page' ) { $this->post_type = get_post_type_object( $post->post_type ); } //タクソノミーを使用する場合は、1番新しいタームを取得 if ( ! empty( self::SHOW_TAXONOMIES[$post->post_type] ) ) { $terms = get_the_terms( $post->ID, self::SHOW_TAXONOMIES[$post->post_type] ); if ( $terms ) { foreach ( $terms as $term ) { if ( ! $this->term || $this->term->id < $term->id ) { $this->term = $term; } } } } } elseif ( is_tax() || is_category() ) { //タクソノミーアーカイブ $this->term = get_queried_object(); //標準投稿と固定ページ以外なら投稿タイプを取得 $tax = get_taxonomy( $this->term->taxonomy ); $post_type = get_post_type_object( $tax->object_type[0] ); if ( $post_type->name != 'post' && $post_type->name != 'page' ) { $this->post_type = $post_type; } } elseif ( is_post_type_archive() ) { //投稿タイプアーカイブ $this->post_type = get_queried_object(); } //末端から順番に配列に入れていく $paths = array(); if ( $this->post ) { //親投稿も遡っていく $cursor = $this->post; while ( $cursor ) { $paths[] = array( 'label' => $cursor->post_title, 'link' => get_permalink( $cursor ) ); $cursor = $cursor->post_parent ? get_post( $cursor->post_parent ) : null; } } if ( $this->term ) { //親タームも遡っていく $cursor = $this->term; while ( $cursor ) { $paths[] = array( 'label' => $cursor->name, 'link' => get_term_link( $cursor ) ); $cursor = $cursor->parent ? get_term( $cursor->parent, $cursor->taxonomy ) : null; } } if ( $this->post_type ) { $paths[] = array( 'label' => $this->post_type->labels->name, 'link' => get_post_type_archive_link( $this->post_type->name ) ); } if (self::HOME_LABEL) { $paths[] = array( 'label' => self::HOME_LABEL, 'link' => home_url() ); } if ( $paths ) { //最初に入れたもの(=末端)はリンクをなくす $paths[0]['link'] = null; //順番をひっくり返す $this->paths = array_reverse( $paths ); } } /** * パンくず表示 */ public function display() { if ( $this->paths && count( $this->paths ) > 1 ) { $output = '<ul itemscope itemtype="http://schema.org/BreadcrumbList">'; foreach ( $this->paths as $index => $cramb ) { $output .= '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">'; if ( $cramb['link'] ) { $output .= '<a itemprop="item" href="' . $cramb['link'] . '">'; } $output .= '<span itemprop="name">' . $cramb['label'] . '</span>'; if ( $cramb['link'] ) { $output .= '</a>'; } $output .= '<meta itemprop="position" content="' . ($index + 1) . '" />'; $output .= '</li>'; } $output .= '</ul>'; echo $output; } } } |
ポイントとしては、先祖投稿や先祖タームをさかのぼりながら取得して、最後に逆順に並び替えるところでしょうか。
ul / li タグで出力して言いますが、タグを変えたい場合は、display() メソッドのところをHTML的にいじってください。
パンくずリストを microdata ではなく RDFa でマークアップしたい場合も同様です。
あとは functions.php でこのファイルを読み込み、
1 2 3 |
if ( ! is_admin() ) { require_once( TEMPLATEPATH . '/includes/class-my-breadcramb.php' ); } |
テンプレートファイル内の、パンくずリストを表示したい箇所で、
1 2 |
$breadcramb = new My_Breadcramb(); $breadcramb->display(); |
とすれば、パンくずリストが表示されます。