get_terms でタームが表示されない原因|hide_empty の落とし穴

結論

get_terms() で「作ったはずのタームが返ってこない」場合、最初に疑うのは hide_empty です。既定では、投稿が1件も紐づいていないターム(空のターム)は結果から除外されます。全件を取りたいときは 'hide_empty' => false を指定します。

それでも出ない場合は、taxonomy の指定ミス、parent / child_of による絞り込み、number の上限、そして「その投稿が公開済みでない」ことを順に確認します。

原因・仕組み

公式リファレンスにあるとおり、get_terms() は WP_Term_Query の引数(orderby、parent、child_of、hierarchical、fields、number など)を受け取ります。また WordPress 4.5.0 以降は、taxonomy を第1引数ではなく引数配列の中に書く形が標準です。旧式の get_terms( 'category', $args ) は後方互換のために残っていますが、新しいコードでは配列に統一します。

hide_empty が true のとき、WordPress は、ターム自身の count(公開済み投稿の件数)が0のものを除外します。階層型タクソノミーでは、hierarchical(既定 true)の影響で、子タームに投稿があれば親も空扱いにならないのが特徴です。

手順(サンプルコード)

// 全タームを名前順で(空のタームも含める)
$terms = get_terms( array(
    'taxonomy'   => 'genre',
    'hide_empty' => false,
    'orderby'    => 'name',
    'order'      => 'ASC',
) );

if ( is_wp_error( $terms ) ) {
    return; // タクソノミー未登録など
}
foreach ( $terms as $term ) {
    printf( '<li><a href="%s">%s</a> (%d)</li>',
        esc_url( get_term_link( $term ) ),
        esc_html( $term->name ),
        (int) $term->count
    );
}

用途別によく使う引数です。

// IDだけ欲しい
get_terms( array( 'taxonomy' => 'genre', 'fields' => 'ids' ) );
// ID => 名前 の連想配列(セレクトボックス用)
get_terms( array( 'taxonomy' => 'genre', 'hide_empty' => false, 'fields' => 'id=>name' ) );
// 最上位のターム(親が0)だけ
get_terms( array( 'taxonomy' => 'genre', 'parent' => 0, 'hide_empty' => false ) );

動作確認(検証環境と結果)

WordPress 7.1.2(ja)/PHP 8.2.12/MariaDB 10.4.32。階層タクソノミー genre に music > rock > punk と、最上位の empty-top を作り、punk にだけ公開済み投稿を1件紐づけて実行しました(tests フォルダの p4.php)。

default (hide_empty=true): music,punk,rock
hide_empty=false: empty-top,music,punk,rock
fields=ids: {"1":4,"2":6,"3":5}
fields=id=>name: {"7":"empty-top","4":"music","6":"punk","5":"rock"}
hierarchical=false hide_empty: punk
count rock: 0 / punk: 1
  • 既定では、投稿のない empty-top だけが除外されました。
  • 子(punk)にだけ投稿があるとき、親の music と rock は、既定の hierarchical => true により結果に含まれました。hierarchical => false を指定すると punk だけになりました。
  • rock 自身の count は0で、親の件数には子の分が合算されません。

get_terms でタームが表示されない原因の注意点

  • get_terms() は失敗時に WP_Error を返します。foreach の前に is_wp_error() で確認します。
  • count は公開済み投稿が対象です。下書き・非公開のみのタームは、空として扱われます。
  • number を指定していないと全件取得になり、タームが数千件あるサイトでは重くなります。
  • orderby の指定が name / count / term_order など、使える値かどうかを公式で確認します。

get_terms でタームが表示されない原因でよくあるミス

  • 配列の中に taxonomy を書かず、旧式の引数順で呼び、WordPress の版数によって挙動が変わる。
  • 投稿タイプが post 以外の場合に、そのタームの投稿が公開済みか確認していない。
  • get_terms の結果を、そのまま echo してしまい、配列の「Array」だけが出る。
  • hide_empty を false にしたまま、一覧にリンクを出し、中身が空のアーカイブが並ぶ。

get_terms でタームが表示されない原因のチェックリスト

  • [ ] taxonomy を引数配列の中で指定している
  • [ ] 空のタームも出したいなら hide_empty => false
  • [ ] is_wp_error() で戻り値を確認している
  • [ ] fields で必要な形(ids / id=>name など)を選んでいる
  • [ ] 件数が多い場合は number を指定した

get_terms でタームが表示されない原因のFAQ(よくある質問)

Q. get_the_terms との違いは。
A. get_the_terms は1つの投稿に付いたタームを取ります。get_terms は、投稿に関係なくタクソノミー全体のタームを取ります。

Q. 子タームだけ欲しいときは。
A. 直下の子なら parent に親IDを、孫以下も含めるなら child_of を使います。

Q. 並び順を手動にしたい。
A. term_order を持つプラグインか、ターム meta に順序を保存し、meta_key / orderby を使います。

筆者の見解(get_terms でタームが表示されない原因)

get_terms は引数が多く、最初は戸惑うと考えています。私見では、「taxonomy と hide_empty だけは必ず明示する」というルールにしておくと、取得漏れのトラブルがかなり減ります。表示用と管理用で hide_empty の意味が違う点も、コメントに残しておくと後から読み返しやすくなります。

get_terms でタームが表示されない原因の関連項目

出典(一次情報)

タイトルとURLをコピーしました