実現したい事
個別記事ページに表示させる関連記事を、
カテゴリに階層がある場合、同階層のカテゴリに属する記事のみを表示したい。

このようなカテゴリ階層の場合、「孫カテゴリ1-1-1」の記事の関連記事は「孫カテゴリ1-1-1」のカテゴリに属する記事のみにする。
「子カテゴリ1-1」の記事の関連記事に「孫カテゴリ1-1-1」の記事を含めるかはパラメータで選択できる。
コードサンプル
functions.phpに追加
<?php
/**
* 投稿についたタクソノミーの中から「最も深いタームID」を返す
*
* @param int $post_id
* @param string $taxonomy
* @return int|null 見つからなければ null
*/
function mytheme_get_deepest_term_id( $post_id, $taxonomy = 'category' ) {
$terms = get_the_terms( $post_id, $taxonomy );
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return null;
}
$deepest_id = null;
$deepest_depth = -1;
foreach ( $terms as $term ) {
$depth = count( get_ancestors( $term->term_id, $taxonomy ) );
if ( $depth > $deepest_depth ) {
$deepest_depth = $depth;
$deepest_id = (int) $term->term_id;
}
}
return $deepest_id ?: null;
}
/**
* 「最も深いターム」を基準に関連記事の WP_Query を返す
*
* @param array $args {
* @type int $post_id 基準投稿(省略時は現在の投稿)
* @type string $taxonomy タクソノミー名(例: 'category', 'blog-cat')
* @type string $post_type 投稿タイプ(例: 'post', 'blog')
* @type int $per_page 件数(既定: 4)
* @type bool $include_children 子孫タームも含めるか(既定: false)
* @type array $extra_query_args WP_Query へそのまま渡す追加引数(任意)
* }
* @return WP_Query|null 条件が作れない場合は null
*/
function mytheme_get_related_query_by_deepest_term( $args = array() ) {
$defaults = array(
'post_id' => get_the_ID(),
'taxonomy' => 'category',
'post_type' => 'post',
'per_page' => 4,
'include_children' => false,
'extra_query_args' => array(),
);
$args = wp_parse_args( $args, $defaults );
$post_id = (int) $args['post_id'];
$taxonomy = $args['taxonomy'];
$deepest_id = mytheme_get_deepest_term_id( $post_id, $taxonomy );
if ( ! $deepest_id ) {
return null; // タームが無い等
}
$q_args = array(
'post_type' => $args['post_type'],
'posts_per_page' => (int) $args['per_page'],
'post__not_in' => array( $post_id ),
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'orderby' => 'date',
'order' => 'DESC',
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => array( $deepest_id ),
'include_children' => (bool) $args['include_children'],
),
),
);
// 追加の WP_Query 引数で上書き/拡張したい場合
if ( ! empty( $args['extra_query_args'] ) && is_array( $args['extra_query_args'] ) ) {
$q_args = array_merge( $q_args, $args['extra_query_args'] );
}
return new WP_Query( $q_args );
}
投稿ページ(single.phpなど)にサブループとして追加
通常投稿記事の場合
例1)通常投稿 × category
<?php
$q = mytheme_get_related_query_by_deepest_term();
if ( $q && $q->have_posts() ) :
echo '<ul class="related-list">';
while ( $q->have_posts() ) : $q->the_post();
echo '<li><a href="' . esc_url( get_permalink() ) . '">';
the_title();
echo '</a></li>';
endwhile;
echo '</ul>';
wp_reset_postdata();
endif;
?>
カスタム投稿タイプの場合
例2)カスタム投稿 ‘blog’ × タクソノミー ‘blog-cat’、子タームも含める、6件、ランダム
<?php
$q = mytheme_get_related_query_by_deepest_term( array(
'post_type' => 'blog',
'taxonomy' => 'blog-cat',
'include_children' => true,
'per_page' => 6,
'extra_query_args' => array(
'orderby' => 'rand',
),
) );
if ( $q && $q->have_posts() ) :
while ( $q->have_posts() ) : $q->the_post();
// ここは自由にレイアウト
endwhile;
wp_reset_postdata();
endif;
?>
補足
- 階層が同じカテゴリが複数ある場合は、最初に見つかったタームを採用
- ターム名が見出しに必要なら、
$term = get_term( mytheme_get_deepest_term_id( get_the_ID(), 'blog-cat' ), 'blog-cat' );のように別途取得して表示