11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AdventureAdvent Calendar 2018

Day 19

wordpressで記事の最下層カテゴリを取得したい

Last updated at Posted at 2018-12-19

株式会社アドベンチャーのフロントエンド@a-yamamotoです。
特にフロントネタが思いつかなかったので、先日wordpressいじってて困ったことでも備忘録として残しておこうと思います。

欲しいカテゴリが取れない問題

キレイにカテゴリ作っても、記事を書く人によってカテゴリの付け方が微妙に違ったりするんですよね。
もしくは後からカテゴリが増えて付け方が変わっちゃったとか。
どういう事かと言いますと・・・

カテゴリ1つの場合

こういうツリー構造で 上野 だけを選択したパターン
01.png

これはカテゴリ取得しても当然1つしかないので、よく見る↓のコードで十分。

$category = get_the_category();
$cat_name = $category[0]->cat_name;

丁寧にツリーの頭から選んだ場合は?

02.png

先ほどのコードを使っても $category[0]上野 が入るとは限らないんですよね。
そもそも get_the_category() でカテゴリを取得した時、4つのカテゴリがどういう順で入るのかは、WP次第らしいです。
なので、本来は上のコードで賄えてたはずなのに、気づけば中階層の微妙なカテゴリが表示されてるなんてことが。。

一番下のやつでいんだけど!なんで親から順番に取ってくれないの!
って数年前も同じこと思った気がするけど、ここの仕様は変わらないのかしら。

最下層カテゴリを取得する

そんな時は↓をfunction.phpにペッ。

function.php
function get_lowest_category ($sbjcat = '', $taxonomy = 'category') {
  $terms = get_the_terms($sbjcat, $taxonomy);
  if (empty($terms)) return false;
  $candidate = $terms;
  $cnt = count($terms);
    if ($cnt > 1) {
      foreach ($terms as $key => $term) {
        foreach ($terms as $term2) {
          if (term_is_ancestor_of($term->term_id, $term2->term_id, $taxonomy)) {
            unset($candidate[$key]);
            break;
          }
        }
      }
    }
    return $candidate;
}

これで最下層のカテゴリが取れる。

別のツリーのカテゴリも選んでたらどうなるの

こういうパターン。あるある。

03.png

これも先ほどの関数を使って最下層のカテゴリを取得。

$category = get_lowest_category();

そうすると $category の中に、それぞれの最下層である 上野和食が入ります。

で、ここでまた問題発生
この場合、最終的にはどちらが出力されるのか。
これも結局WP次第。

ツリーに優先順位をつけてみる

こういう時用にツリーに優先順位をつけることにしました。
複数あった場合、国内 > ジャンル になるように。
なのでこの場合は最終的に 上野 がとれるのが正解。

なので今度は最上層のカテゴリ情報が必要になります。
function.phpにこちらもペッ。

function.php
/* 最上層のカテゴリ取得 */
function get_top_category ($sbjcat = '', $taxonomy = 'category') {
  if (empty($sbjcat) && is_category()) {
    $sbjcat = get_query_var('cat');
  } elseif (empty($sbjcat) && is_tax()) {
     $sbjcat = get_query_var('term_id');
    $taxonomy = get_query_var('taxonomy');
  } elseif (!is_numeric($sbjcat)) {
    $sbjcat = get_term_by('slug', $sbjcat, $taxonomy)->term_id;
  }
  if (!$sbjcat) return false;
  $ancestors = array_reverse(get_ancestors($sbjcat , $taxonomy));
  if(isset($ancestors[0])) $ancestor_id = $ancestors[0]; else $ancestor_id = $sbjcat;
  return get_term($ancestor_id , $taxonomy);
}

最下層カテゴリが複数あったら、国内 > ジャンル になるように並び替え。

$descends = get_lowest_category();
$cnt = count($descends);
$cate_ary = array();

if ($cnt > 1) {
  $order = [japan, genre]; // 左から優先度高
  foreach($descends as $descend) {
    $slug = $descend->slug;
    $ancestor = get_top_category($slug);
    $parent = $ancestor->slug;  // ツリーの最上層のカテゴリ
    $descend->group_parent = $parent;
    array_push($cate_ary, $descend);
  }
  usort($cate_ary, function($x, $y) use ($order){
    return array_search($x->group_parent, $order) > array_search($y->group_parent, $order);
  });
  $item = $cate_ary[0];
} else {
  foreach($descends as $descend) {
    $item = $descend;
  }
}

先頭のデータをとれば、ちょっと無理やり感あるけど 上野 がとれるようになりました。

まとめ

そもそも、この記事にはこのカテゴリ表示!みたいのがあるといいんだけど。
もっといいやり方ないかしら。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?