Display Related Posts for Custom Post Based On Category

Quick Summary
- Get the current post's first term in the custom taxonomy with get_the_terms() and query three other posts of that type sharing it.
- Replace the example's item post type and item-category taxonomy with your own slugs, and place the code in that type's single template.
- Delete the RELATED POST TITLE line, which prints as text, and swap deprecated caller_get_posts for ignore_sticky_posts.
On the single page of a custom post type, a related posts block usually means other posts from the same category. Custom post types normally use a custom taxonomy for their categories, so WordPress’s built-in category functions don’t help here. This snippet takes the first term of the current post and lists three other posts that share it.
The example uses a custom post type called item with a custom taxonomy called item-category. Place the code in the single template for that post type, for example single-item.php, below the main content.
<?php
$tags = get_the_terms($post->ID, 'item-category');
if ($tags) {
$first_tag = $tags[0]->slug;
$args=array(
//'tag__in' => array($first_tag),
'post__not_in' => array($post->ID),
'posts_per_page'=>3,
'caller_get_posts'=>1,
'post_type' => 'item',
'item-category' => $first_tag,
);
$my_query = new WP_Query($args);
if( $my_query->have_posts() ) {
while ($my_query->have_posts()) : $my_query->the_post(); ?>
//RELATED POST TITLE
<h3><?php the_title( ); ?></h3>
<?php
endwhile;
}
wp_reset_query();
}
?>How it works
get_the_terms()gets the current post’s terms initem-category, and$tags[0]->slugkeeps the slug of the first one.- The
WP_Queryarguments ask for posts of typeitemin that term ('item-category' => $first_tag), skip the current post withpost__not_in, and limit the list to 3 withposts_per_page. - The loop prints each related post’s title. Add
the_permalink(), a thumbnail or an excerpt as your design needs. - If the current post has no terms, nothing is printed.
Replace item and item-category with your own post type and taxonomy slugs. The //RELATED POST TITLE line sits outside the PHP tags, so it prints as plain text on the page; delete it when you use the snippet.
Two small clean-ups are worth making: caller_get_posts is the old, deprecated name of ignore_sticky_posts, and after a custom WP_Query loop, wp_reset_postdata() is the usual way to restore the global post.
Related articles
- tag-based related posts for regular posts: the same query built on the first tag
- hand-picked related posts with ACF: when editors should choose the posts
- a link to the first term’s archive: a see-all link for the same term

