親子ターム(カテゴリ)別記事一覧の表示 / WP_Query

2018年4月10日に加筆・修正をしました。

製品やサービスの記事一覧の表示は、新着順ではなくカテゴリ別で表示するのが自然です。カテゴリに親子関係がある場合は、子カテゴリ別記事一覧ページのリンク階層が深くならないよう、工夫をすると記事全体の見通しが良くなります。今回はあるカスタム投稿に特定タクソノミーの親子タームを設定した場合を前提に、リスト形式で記事一覧を表示する方法について触れます。

アーカイブページの場合

archive-( タクソノミースラッグ ).phpに、ターム別記事一覧用の記述をします。

表示の条件

表示の条件は下記のようにしたとします。

  • タームごとに見出しをつける。子タームがある場合は親となるタームのすぐ下に見出しとして表示。
  • 子タームを持たないタームを設定した記事は、タームタイトルのすぐ下に表示させる(子タームを持つタームで、親タームにのみを設定した投稿も同様)。
  • 親・子タームを設定した記事は、子タームタイトルの下に表示させる(子タームのみを設定した場合も同様)。

実装の考え方

条件に基づいて下記の考え方で実装します。

  1. get_termsで特定タクソノミーのタームを取得してタームごとにforeach開始。
  2. 親タームタイトルを表示。
  3. タームごとに子ターム取得(孫ターム・投稿記事を持たないタームを除外)。
  4. 子タームがある場合の処理。
    • A. 投稿記事を持つ子タームスラッグを除外用配列に格納(foreach内)。
    • B. 子タームを持つタームで、親タームにのみを設定した投稿のループ、除外用配列を使用。
    • C. 子タームを設定した投稿のループ(foreach内)。
  5. 子タームがない場合の処理。
  6. $postをリセットしてforeach終了。

実際のコード

長くなるので、「実装の考え方」のリストに基づいて個別に記載します。

1. get_termsで特定タクソノミーのタームを取得してタームごとにforeach開始

子タームを除外してタームを取得後、foreachで回します。

<?php
    $target_post = '(投稿タイプのスラッグ)';
    $target_post_cat = '(タクソノミーのスラッグ)';
    $post_count = -1;
    $cat_args = array(
        'parent' => 0, //トップレベルのタームのみ
        'hierarchical' => 0 //子タームを含めない
    );
    $cats = get_terms($target_post_cat, $cat_args);
    foreach( $cats as $cat ):
?>

2. 親タームタイトルを表示

はじめにタームのスラッグと名前を変数に格納しておいて、名前をタームタイトルとして表示します。

<?php
    $target_cat_slug = esc_html($cat -> slug);
    $target_cat_name = esc_html($cat -> name);
?>
<h3><?php echo $target_cat_name; ?></h3>

3. タームごとに子ターム取得(孫ターム・投稿記事を持たないタームを除外)

<?php $child_cats = get_terms($target_post_cat,'hierarchical=0&hide_empty=1&parent='.$cat -> term_id); ?>

4. 子タームがある場合の処理

<?php if( $child_cats ) : ?>
4-A. 投稿記事を持つ子タームスラッグを除外用配列に格納(foreach内)
<?php
    foreach( $child_cats as $child_cat  ){
        $exclude[] =  esc_html($child_cat->slug);
    }
?>
4-B. 子タームを持つタームで、親タームにのみを設定した投稿のループ、除外用配列を使用
<?php
    $args = array(
        'post_type' => $target_post,
        'tax_query' => array( //ここからタクソノミーのパラメーター
            'relation' => 'AND',
            array(
                'taxonomy' => $target_post_cat, //カスタム分類(カスタムタクソノミー)
                'field' => 'slug', //タクソノミータームの種類をスラッグで指定する
                'terms' => $target_cat_slug //タームからスラッグ取得 
            ),
            array(
                'taxonomy' => $target_post_cat, //カスタム分類(カスタムタクソノミー)
                'field' => 'slug', //タクソノミータームの種類をスラッグで指定する
                'terms' => $exclude, //除外タームスラッグ取得 
                'operator' => 'NOT IN' //除外
            )
        ),
        'post_status' => 'publish',
        'posts_per_page' => $post_count, // 表示するページ数
        'orderby' => 'menu_order', // 必要な場合に指定
        'order' => 'DESC' // 並び順
    );
    $my_query = new WP_Query($args);
?>
<?php if( $my_query->have_posts() ) : ?>
<ul>
    <?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
    <?php endwhile; ?>
</ul>
<?php endif; ?>
4-C. 子タームを設定した投稿のループ(foreach内)
<?php foreach( $child_cats as $child_cat ): ?>
<?php
    $child_cat_name = esc_html($child_cat -> name);
    $target_cat_slug = esc_html($child_cat->slug);
?>
<h4><?php echo $child_cat_name; ?></h4>
<?php
    $args = array(
        'post_type' => array($target_post),
        'taxonomy' => $target_post_cat,
        'term' => $target_cat_slug,
        'post_status' => 'publish',
        'posts_per_page' => $post_count, // 表示するページ数
        'orderby' => 'menu_order',
        'order' => 'DESC' // 並び順
    );
    $my_query = new WP_Query($args);
?>
<?php if( $my_query->have_posts() ) : ?>
<ul>
    <?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
    <?php endwhile; ?>
</ul>
<?php endif; ?>
<?php endforeach; ?>

子タームがない場合の処理

<?php else: ?>
<?php
    $args = array(
        'post_type' => array($target_post),
        'taxonomy' => $target_post_cat,
        'term' => $target_cat_slug,
        'post_status' => 'publish',
        'posts_per_page' => $post_count, // 表示するページ数
        'orderby' => 'menu_order',
        'order' => 'DESC' // 並び順
    );
    $my_query = new WP_Query($args);
?>
<?php if( $my_query->have_posts() ) : ?>
<ul>
    <?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
    <?php endwhile; ?>
</ul>
<?php endif; ?>
<?php endif; ?>

6. $postをリセットしてforeach終了

<?php wp_reset_postdata(); ?>
<?php endforeach; ?>

タクソノミーページの場合

ご要望がありましたので追記しました。

taxonomy-( タクソノミースラッグ ).phpに、ターム別記事一覧用の記述をします。

表示の条件

表示の条件は下記のようにしたとします。

  • 親タームの場合は子タームごとの記事一覧をサブループで表示。
  • 子を持たないタームや子タームの場合は記事一覧をメインループで表示。

実装の考え方

条件に基づいて下記の考え方で実装します。

  1. タームタイトルの表示。
  2. 親ターム判定用の処理。
  3. 親タームの場合の処理。
    • A. タームごとに子ターム取得(孫ターム・投稿記事を持たないタームを除外)。
    • B. 子タームを設定した投稿をループ(foreach内)。
    • C. $postをリセットしてforeach終了。
  4. 子を持たないタームや子タームの場合の処理。

実際のコード

アーカイブと同様に、「実装の考え方」のリストに基づいて個別に記載します。

1. タームタイトルの表示

<h2><?php single_term_title(); ?></h2>

2. 親ターム判定用の処理

<?php
    $target_post_cat = '(タクソノミーのスラッグ)';
    // 親ターム判定
    $is_parent_term = get_term_children(get_queried_object_id(), $target_post_cat) ? true : false;
?>

使用関数:get term children

3. 親タームの場合の処理

<?php if($is_parent_term): ?>
3-A. タームごとに子ターム取得(孫ターム・投稿記事を持たないタームを除外)。
<?php
    // 現在のタームの子ターム取得
    $child_cats = get_terms($target_post_cat,'hierarchical=0&hide_empty=1&parent='.get_queried_object_id());
?>

使用関数:get terms

3-B. 子タームを設定した投稿をループ(foreach内)
<?php foreach( $child_cats as $child_cat ): ?>
<?php
    $target_post = '(投稿タイプのスラッグ)';
    $target_cat_name = esc_html($child_cat -> name);
    $target_cat_slug = esc_html($child_cat -> slug);
    $target_cat_url = esc_html(get_term_link( $child_cat ));
    $post_count = -1;
    $args = array(
        'post_type' => array($target_post),
        'taxonomy' => $target_post_cat,
        'term' => $target_cat_slug,
        'post_status' => 'publish',
        'posts_per_page' => $post_count,
        'orderby' => 'menu_order',
        'order' => 'ASC'
    );
    $my_query = new WP_Query($args);
?>
<?php if( $my_query->have_posts() ) : ?>
<h3><a href="<?php echo $target_cat_url; ?>"><?php echo $target_cat_name; ?></a></h3>
<ul>
    <?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
    <?php endwhile; ?>
</ul>
<?php endif; ?>
3-C. $postをリセットしてforeach終了
<?php wp_reset_postdata(); ?>
<?php endforeach; ?>

子を持たないタームや子タームの場合の処理

<?php else : ?>
<?php if( $wp_query->have_posts() ) : ?>
<ul>
    <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
    <?php endwhile; ?>
</ul>
<?php endif; ?>
<?php endif; ?>

リンク階層を浅くした一覧表示と期待される効果

  • 見る人が製品・サービスを見渡せるようになる。
  • 見る人が目的のページに辿り着きやすくなる。
  • 子カテゴリページと製品・サービス詳細ページのSEO効果の向上が見込める(現在のGoogleのアルゴリズムの場合)。

以上です。