[WordPress] 記事のカテゴリーを親子順に並び替え
スポンサーリンク
WordPressで記事が属するカテゴリーを、get_the_category
やget_the_category_list
を使って出力すると、通常は名前順にソートされた状態となります。一つの記事が複数のカテゴリーに属している時、そのカテゴリーの親子関係の順に沿ったリストを得ようとすると、すこし込み入った処理が必要となります。
最近、一つの記事は一つのカテゴリーに必ず属し、そのカテゴリーに親カテゴリーが存在する場合は、それらの先祖カテゴリーすべてにも属するという構成のサイトの開発を行いました。ようするにディレクトリ型のページ構成のサイトということですね。そして、そのサイトでは記事のカテゴリーを親子関係の順に出力する必要がありました。
初めは何も考えずにget_the_category_list
を使ってカテゴリーリストの出力を行なっていたのですが、これだと出力されるカテゴリーの一覧は、親子関係を全く反映していないものになるのですね。途中で気がついて、あわてて親子関係を反映するコードを用意しました。以下は、そのコードの作成手順と使い方についてのメモです。
記事がカテゴリー一つと、そのカテゴリーの先祖全てに属すという構成を持つと、カテゴリーを親子順に並べるだけで分かりやすいパンくずリストを作ることができます。仮に、「カテゴリー1」「CAT2」「分類3」「カテゴリー4」「CAT5」というカテゴリーが存在し、「CAT5」が子孫で「カテゴリー1」が先祖という親子関係を持っていたとします。記事Aは、この5つのカテゴリーすべてに属しています。
記事Aを表示する際、get_the_category_list
を使うと、カテゴリーを登録した順番によっては、以下の様なでたらめな並びになってしまいます。
本来は以下のように、親子関係を反映した順序で出力したいわけです。
さてではどう実現するかですが、あまり知られていないWordPress関数で、cat_is_ancestor_of
という、カテゴリーが他のカテゴリーの先祖カテゴリーであるかどうかを判定する関数がありますので、これを使うことにします。cat_is_ancestor_of
にカテゴリーIDを2つ渡すと、第1引数に渡したカテゴリーIDが、第2引数に渡したカテゴリーIDの先祖であればtrue
を、そうでないならfalse
を返します。ということは、cat_is_ancestor_of
がfalse
を返さなくなるまでソートを行えば、親子順に並んだカテゴリーリストを得られるわけです。まあ単純なバブルソートですね。
前置きが長くなってしまいましたが、それで作ったのが以下のfunctionです。これを、使用中のthemeのfunction.phpにペーストし、WordPressループ内のカテゴリーリストを表示させたい場所でsort_cats_parent_child_relationship
を使えば、親子関係の順に並び替えたカテゴリーリストのhtmlが得られます。
function sort_cats_parent_child_relationship() { //カテゴリー情報を取得 $cats = get_the_category(); //ソート配列を作成 foreach($cats as $cat){ $hash[] = $cat->term_id; $catarr[$cat->term_id] = $cat; } //バブルソートで判定(親カテゴリーが上) $n=count($hash); //親子関係でないカテゴリーをソートすると無限ループとなる //それが防ぐため、最大計算回数を超えてソートが終わっていない場合は打ち切る $worst = $n * ($n-1)/2;//最悪計算時間 $cnt = 0; for($i=0;$i<$n;$i++){ for($j=$n-1;$j>$i;$j--){ //カテゴリーIDを渡すと、前者が後者の先祖ならtrueを返す if( !cat_is_ancestor_of( $hash[$j-1], $hash[$j] ) ){ $tmp = $hash[$j]; $hash[$j] = $hash[$j-1]; $hash[$j-1] = $tmp; } } $cnt++; //最悪計算時間を超えていないかチェック if($cnt>$worst) break; } //順番が確定したので、$hashの並びを元にリストを作成 //以下で作っているのはtwitter bootstrapのパンくずリスト用のhtml foreach($hash as $cat_id) $cat_list[] = "<a href='".get_bloginfo("url")."/category/{$catarr[$cat_id]->slug}'>{$catarr[$cat_id]->cat_name}</a>"; $str = "<li>". implode(' <span class="divider">»</span></li><li>', $cat_list). " <span class='divider'>»</span></li>"; return $str; }
この関数は、記事に設定されたカテゴリー全てが1対1の親子関係である場合にのみ有効です。親子関係ではない複数のカテゴリーを設定しているような、タグ的な使い方をしている場合には有効ではありません。非常に狭いケースでのみ使用可能な関数となっています。
上記のfunctionでは、使うべきでない場面で使われた場合への対策で、最悪計算回数を超えてもソートが続いている場合は、並び替えを中断するようにしています。(17・18・30・32・33行目)
38行目以下の部分は、twitter bootstrapのパンくずリストのスタイルを適用するためのhtmlを出力しています。実際に使う場合には、この部分を都合のいいように書き変えてお使いください。
<ul class='breadcrumb'> <li><a href='<?php bloginfo('url');?>'>Home</a> <span class="divider">»</span></li> <?php echo sort_cats_parent_child_relationship();?> <li class='active'><?php echo get_the_title();?></li> </ul>
これで、下のようなカテゴリーが親子順に並べられたリストが出力できます。
スポンサーリンク
Twitter Bootstrapカテゴリーの投稿
- [Bootstrap4] container-fluidを使いつつ、max-widthも設定する
- [Bootstrap] レスポンシブイメージを常に正方形に
- [Bootstrap] IMG関連のスタイルおよびカスタマイズのまとめ
- [Bootstrap] 複数カラムにまとめてスタイルを適用
- [Bootstrap] inputとボタンが横に並んだフォームを作る
- [Bootstrap] パンくずリストのスタイルを変更
- [PHP] Twitter bootstrapのform-horizontalを楽に使う関数
WordPressカテゴリーの投稿
- [WordPress] 記事が更新された回数を取得する
- [WordPress] ダッシュボードのウィジェットを表示オプションを使わずに非表示化する
- [WordPress] 関連記事をカテゴリーに基づきアイキャッチ画像つきで表示
- [WordPress] バックアッププラグインの特徴と機能比較
- [WordPress] タグ版wp_list_categories
- [WordPress] have_comments()がFALSEを返しコメントが表示されない現象
- [WordPress] 個別記事ページでカテゴリーを表示するときの目的別の方法
- [PHP] 文字長がnバイト以下になるまで末尾の文字を1字づつカット
- [WordPress] wp_insert_post()でhtmlタグが除去されるのを防ぐ
- [WordPress] カテゴリー・タグ・カスタムタクソノミーを外部から登録・編集する