WordPress の get_the_category で親、子、孫の階層表示をする関数を作成!

WordPress の投稿のカテゴリーを表示するには get_the_category() が多用されますが、この関数は階層取得ができません。
カテゴリーを親、子、孫といった方法で設定が可能なのに、そのような並びで表示できないのは大問題ですね。
ちなみに以上のような単純な階層構造なら以下のコードで事足ります。おそらく。たぶん。知らん(投げやり)。
1 2 3 4 5 6 7 8 |
$categories = get_the_category(); uasort( $categories, function( $val1, $val2 ) { if ( $val1->parent === $val2->parent ) { return ( $val1->term_id < $val2->term_id ) ? -1 : 1; } return ( $val1->parent < $val2->parent ) ? -1 : 1; } ); |
以上が正しく動作するかどうかは、自身でテストしてください。何となくの思い付きで書いたものなので。。
私が解決したいのは、このような階層を保持したカテゴリーが複数設定されている場合の対応です。
これを以上のような順番で表示したいのです。
補足
このような無茶苦茶なカテゴリーの設定はするべきではありません。
このような無茶苦茶なカテゴリーの設定はするべきではありません。
あくまでも例です。
ちなみに私が開発した WordPress無料テーマ「SCRATCH」で実際に使用しているコードです。
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
/** * Order by term_order */ function categories_term_order( $categories ) { $category_tree = []; $branches = []; /* * Here $categories has a list of items in random order like this * This is just an example ok. This kind of category structure should never be made * * array( * 0 => { * 'term_id' => 26, * 'parent' => 4, * }, * 1 => { * 'term_id' => 39, * 'parent' => 2, * }, * 2 => { * 'term_id' => 45, * 'parent' => 25, * }, * 3 => { * 'term_id' => 4, * 'parent' => 25, * }, * 4 => { * 'term_id' => 2, * 'parent' => 0, * }, * 5 => { * 'term_id' => 53, * 'parent' => 25, * }, * 6 => { * 'term_id' => 25, * 'parent' => 0, * } * ) * * Let's go! */ foreach( $categories as $cat ) { if ( 0 === $cat->category_parent ) { $category_tree[ $cat->term_id ] = []; } else { $branches[ $cat->category_parent ][ $cat->term_id ] = ''; } } /* * Now it looks like this * * $category_tree = ( * 2 => array(), * 25 => array(), * ) * $branches = ( * 4 => array( * 26 => '', * ), * 2 => array( * 39 => '', * ), * 25 => array( * 45 => '', * 4 => '', * 53 => '', * ), * ) * * This means 2 and 25 are the oldest ancestors * 26 is a child of 4 * 39 is a child of 2 * 45 is a child of 25 * 4 is a child of 25 * 53 is a child of 25 * * Let's insert each branch into $category_tree! */ if ( count( $branches ) ) { foreach( $branches as $foundation => $branch ) { foreach( $branches as $key => $val ) { if ( array_key_exists( $foundation, $val ) ) { $branches[ $key ][ $foundation ] = $branches[ $foundation ]; break 1; } } } foreach ( $branches as $foundation => $branch ) { if ( isset( $category_tree[ $foundation ] ) ) { $category_tree[ $foundation ] = $branch; } else { /* * This else is when $category_tree and $branches look like these * * $category_tree = ( * 2 => array(), * 25 => array(), * ) * $branches = ( * 4 => array( * 26 => '', * ), * ) * * This means category 2, 25 and 26 are set but not 4. So 26 is like a lost child * * The code below makes $category_tree like this * * $category_tree = ( * 2 => array(), * 25 => array(), * 26 => array(), * ) */ $category_tree += [ key( $branch ) => [] ]; } } } /* * Now $category_tree looks like this * array( * 2 => array( * 39 => '', * ), * 25 => array( * 45 => '', * 4 => array( * 26 => '', * ), * 53 => '', * ), * ) * * Let's flatten it! */ // multidimensional array flatten $array_flatten = function ( $array ) use ( &$array_flatten ) { $return = []; foreach( $array as $key => $val ) { $return[] = $key; if ( is_array( $array[ $key ] ) ) { $return = array_merge( $return, $array_flatten( $array[ $key ] ) ); } } return $return; }; $category_tree = $array_flatten( $category_tree ); // $category_tree += [ key( $branch ) => [] ]; might make a redundant element in an array $category_tree = array_unique( $category_tree ); /* * Now $category_tree looks like this * array( * 0 => 2, * 1 => 39, * 2 => 25, * 3 => 45, * 4 => 4, * 5 => 26, * 6 => 53, * ) * * Let's insert category data into where it should be * Take it easy */ foreach ( $category_tree as $key => $cat ) { foreach ( $categories as $k => $c ) { if ( $cat === $c->term_id ) { $category_tree[ $key ] = $c; } } } return $category_tree; } |
以下のように使用してください。
1 |
categories_term_order( get_the_category() ); |
Category Order and Taxonomy Terms Order というカテゴリーの順序を変更する有名なプラグインがありますが、以上のコードで不具合などは発生しないのでご安心ください。
ちなみに以下のツイートは、このファンクションを記述した直後に投稿したものです。
PHPのような超高級言語で久しぶりにアルゴリズムを考えてコードを書いたら頭が痛くなった。
— Taku (@jt_taku) July 20, 2018
本当に勘弁してほしいですね。このようなコードは WordPressコアのほうで実装するべきだと思います。
そうすれば、このようなものも書かなくて済みます。
これよりシンプルで美しい方法を知っている方は、コメント欄で教えてください。