WordPress Related Posts From the Same Category

WordPress related posts from the same category are the simplest “read next” list: other posts that share a category with the one being read. This snippet prints three of them under a single post as a plain list of links, without a related posts plugin.

It never lists the current post, skips sticky posts and prints nothing on content without categories, instead of falling back to random posts from the whole site.

The snippet

<?php
/**
 * Related posts: other posts from the current post's categories.
 * Scripts Organizer: Trigger location Conditions, Script location Shortcode.
 */
$dpc_count   = 3;       // How many posts.
$dpc_orderby = 'rand';  // 'rand' for a random pick, 'date' for the newest.

$dpc_current_id = is_singular() ? get_queried_object_id() : get_the_ID();
$dpc_cat_ids    = $dpc_current_id ? wp_get_post_categories( $dpc_current_id ) : array();

if ( $dpc_cat_ids ) {
	$dpc_related = new WP_Query(
		array(
			'post_type'           => 'post',
			'post_status'         => 'publish',
			'category__in'        => $dpc_cat_ids,
			'post__not_in'        => array( $dpc_current_id ),
			'posts_per_page'      => $dpc_count,
			'orderby'             => $dpc_orderby,
			'ignore_sticky_posts' => true,
			'no_found_rows'       => true,
		)
	);

	if ( $dpc_related->posts ) {
		echo '<ul class="dpc-related">';
		foreach ( $dpc_related->posts as $dpc_related_post ) {
			printf(
				'<li class="dpc-related__item"><a href="%1$s">%2$s</a></li>',
				esc_url( get_permalink( $dpc_related_post ) ),
				esc_html( get_the_title( $dpc_related_post ) )
			);
		}
		echo '</ul>';
	}
}

Add it with Scripts Organizer

In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Conditions, tick Shortcode under Script location (leave PHP unticked), paste the code into the PHP editor, keep Template on All and publish.

The block now shows its shortcode, for example [scorg_shortcode id="123"]. Paste it where the output should appear: a Shortcode block in the post or in a block theme template, or the shortcode element of your page builder’s single or archive template.

Put the shortcode in your single post template or at the end of the post. Setting Template to Post Type → Posts keeps it from printing on pages that happen to use the same template. Scripts Organizer includes this file every time the shortcode renders, inside its own function. That is why the code has no function declarations (a second shortcode on the same page would fatal with “Cannot redeclare”), uses get_the_ID() or get_queried_object_id() instead of a bare $post, and prefixes its variables with dpc_.

How it works

  • On a single post get_queried_object_id() is the post being viewed, even if your template ran another loop before the shortcode. Elsewhere it falls back to the post of the current loop.
  • wp_get_post_categories() returns the post’s category IDs. When there are none the query is skipped, because category__in with an empty list would match every post.
  • The WP_Query excludes the current post with post__not_in, ignores sticky posts and sets no_found_rows, since no pagination is needed.
  • The loop reads $dpc_related->posts directly instead of calling the_post(), so the global post of your template stays untouched and no wp_reset_postdata() is needed. Titles and links are escaped.

Customise it

  • More or fewer posts: change $dpc_count.
  • Newest first instead of random: set $dpc_orderby to 'date'.
  • Same tags instead of categories: replace wp_get_post_categories() with wp_get_post_tags( $dpc_current_id, array( 'fields' => 'ids' ) ) and category__in with tag__in.
  • Thumbnails: add get_the_post_thumbnail( $dpc_related_post, 'thumbnail' ) inside the link, like in Previous and next post links with thumbnails.

Gotchas

  • 'rand' makes the database sort every matching post on every page view. That is fine for a few thousand posts; on large sites use 'date' or cache the result in a transient.
  • Page caching freezes a random pick until the cache is cleared, which is usually fine for related posts.

In the Scripts Organizer library Import it with one click from Scripts Organizer.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.