親子関係の配列を階層ごと取得したい
PHPの再帰処理でカテゴリ階層を取得する方法という前回の記事でカテゴリーの再帰処理を実装しました。WordPressの記事表示時に、その記事が属しているカテゴリーの階層(リンク+カテゴリー名)を取得するために考えたのですが、どうやらWordPressにはすでにそういう関数が準備されているようなので、そちらを採用することにしました。今回はそのまとめ。
get_the_terms関数で記事が属しているカテゴリーを取得
まず、投稿ページ(is_single
関数判定)で記事が属しているカテゴリーのデータをget_the_terms
関数で取得します。
global $post; if ( is_single() ) { $terms = get_the_terms( $post->ID, 'category' ); }
カテゴリー設定例のような記事のカテゴリーを取得した場合、以下のようなデータが返ってきます。
array (size=5) 0 => object(WP_Term)[991] public 'term_id' => int 22 public 'name' => string 'カテゴリー 1' (length=17) public 'slug' => string '%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc-1' (length=47) public 'term_group' => int 0 public 'term_taxonomy_id' => int 22 public 'taxonomy' => string 'category' (length=8) public 'description' => string '' (length=0) public 'parent' => int 0 public 'count' => int 2 public 'filter' => string 'raw' (length=3) 1 => object(WP_Term)[992] public 'term_id' => int 23 public 'name' => string 'カテゴリー 2' (length=17) public 'slug' => string '%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc-2' (length=47) public 'term_group' => int 0 public 'term_taxonomy_id' => int 23 public 'taxonomy' => string 'category' (length=8) public 'description' => string '' (length=0) public 'parent' => int 22 public 'count' => int 2 public 'filter' => string 'raw' (length=3) 2 => object(WP_Term)[993] public 'term_id' => int 67 public 'name' => string '子カテゴリー 01' (length=21) public 'slug' => string 'child-category-01' (length=17) public 'term_group' => int 0 public 'term_taxonomy_id' => int 67 public 'taxonomy' => string 'category' (length=8) public 'description' => string 'This is a description for the Child Category 01.' (length=48) public 'parent' => int 62 public 'count' => int 2 public 'filter' => string 'raw' (length=3) 3 => object(WP_Term)[994] public 'term_id' => int 154 public 'name' => string '第3階層カテゴリー' (length=27) public 'slug' => string '%e7%ac%ac%ef%bc%93%e9%9a%8e%e5%b1%a4%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc' (length=81) public 'term_group' => int 0 public 'term_taxonomy_id' => int 154 public 'taxonomy' => string 'category' (length=8) public 'description' => string '' (length=0) public 'parent' => int 23 public 'count' => int 1 public 'filter' => string 'raw' (length=3) 4 => object(WP_Term)[995] public 'term_id' => int 62 public 'name' => string '親カテゴリー' (length=18) public 'slug' => string '%e8%a6%aa%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc' (length=54) public 'term_group' => int 0 public 'term_taxonomy_id' => int 62 public 'taxonomy' => string 'category' (length=8) public 'description' => string '' (length=0) public 'parent' => int 0 public 'count' => int 2 public 'filter' => string 'raw' (length=3)
term_id
が自分自身のユニークID、parent
が親IDを指します。この2つの列を使用して、カテゴリー階層の取得を行います。
最下層のカテゴリーIDだけの配列を作成
前回の記事と同様に親子関係のカテゴリーから親カテゴリー配列を作成して、最下層カテゴリーを抽出します。
$terms = get_the_terms( $post->ID, 'category' ); $term_bottom = array(); if ( $terms && ! is_wp_error( $terms ) ) { $parent_ids = array(); foreach ( $terms as $term ) { if ( $term->parent != 0 ) { $parent_ids[] = $term->parent; } } foreach ( $terms as $term ) { if ( !in_array( $term->term_id, $parent_ids ) ) { $term_bottom[] = $term->term_id; } } }
get_the_terms
関数の戻り値は、WP_Errorオブジェクトを返すので、4行目のように、is_wp_error
でエラーでないかの判定をします。Trueであれば7〜11行目で親IDの配列生成をし、その後12〜16行目で、最下層のカテゴリー配列を生成します。
get_ancestors関数
前回の記事では、ここから再帰処理用の関数を作って……という流れでしたが、ここでWordPressのget_ancestors
関数を使用します。以下、引用。
指定されたオブジェクトの祖先オブジェクトの配列を返します。祖先オブジェクトの種類を第2引数で指定します。カスタム投稿タイプやカスタムタクソノミーの場合は第3引数も使います。
WordPress Codex 関数リファレンス/get ancestors より引用
要はカテゴリーの番号を引数で渡すとその親階層を全て取得してくれるというステキ関数です。先程、最下層のカテゴリー配列を作成したので、それをループしてget_ancestors
関数に渡してあげれば取得できます。
if ( count( $term_bottom ) > 0 ) { $ancestors = array_reverse( get_ancestors( $term_bottom[0], 'category' ) ); $ancestors[] = $term_bottom[0]; foreach ( $ancestors as $ancestor ) { $item_array[] = get_cat_name( $ancestor ); } }
これで$term_array
変数に配列としてカテゴリー名が格納されます。2行目の$term_bottom[0]
と添字を「0」と渡しているのは、パンくずリストは複数必要ないからです。実際は、例題のデータで実験すると以下のようなカテゴリーが取得できます。(カテゴリーの名前横のカッコは自身のID)
- カテゴリー 1(22) > カテゴリー 2(23) > 第3階層カテゴリー(154)
- 親カテゴリー(62) > 子カテゴリー 01(67)
$term_bottom[0]
には、「154」、$term_bottom[1]
には「67」が格納されている状態です。どちらのカテゴリーを優先するかというのは難しいので、配列の最初のデータを優先するようにしました。
パンくずリスト自体は、1記事につき1つの構造が望ましいと僕は思います。公開しているプラグインMarkup (JSON-LD) structured in schema.orgでもこの方式を採用しました。
ちょっと前の動画ですが、複数のパンくずをもたせること自体が悪ではないようです。あくまで構造的に正しければ問題ないとのこと。動画でも発言していますが、極端に20カテゴリーに属しているとかそういうのはなしだよねと言っています。ちょっと対応するかどうか悩みどころ。