Related Posts Recipes

This page is part of the plugin documentation for the Related Posts by Taxonomy plugin.

Here you’ll find some custom ways of using this plugin.

Setting your own defaults for the shortcode.

By setting your own defaults you don’t need to type in shortcode attributes anymore. For example, you allways want to show related medium thumbnails with the shortcode. Normally you would need to type this for the shortcode every time you use it:

[related_posts_by_tax format="thumbnails" image_size="medium"]

As you see we used the attributes “format” and “image_size”. Lets add the defaults for these attributes ourselves by using this filter.
Put this code in your (child) theme’s functions.php.

add_filter( 'related_posts_by_taxonomy_shortcode_defaults', 'my_related_post_shortcode_defaults' );
function my_related_post_shortcode_defaults( $defaults ) {
    $defaults['format']     = 'thumbnails';
    $defaults['image_size'] = 'medium';
    return $defaults;

After using this in your your theme all you need to type for the shortcode is this.


Now the thumbnails will display instead of the default “links” format. See more examples for the usage of the filter.

Styling the shortcode and widget.

All styling for the widget and shortcode is provided by your theme. Add your own styles to your (child) theme’s stylesheet to style them differently.

Styling the thumbnails
To style the thumbnails see the the thumbnails section.

Styling the shortcode
Since 1.0 the shortcode title is a '<h3>' heading and the shortcode itself is wrapped in a div with a class “rpbt_shortcode”. You can change the '<h3>' heading tags with the before_title and after_title attributes. Or set a default for it.

Style the shortcode like this in your (child) theme’s stylesheet:

// shortcode container
.rpbt_shortcode {
	/* your styles here */

// title
.rpbt_shortcode h3 {
	/* your styles here */

Including and excluding terms.

The logic behind including and excluding terms is a bit tricky. Read below how the plugin fetches related posts when including or excluding terms.

Including terms

With the terms and include_terms attributes you can display related posts by specific terms.

The terms attribute lets you use any term, but they have to be in the taxonomies used to get the related posts. The include_terms attribute lets you only use the terms in common with the current post.

By setting the related parameter to false you can include any term with the terms and include_terms attributes regardless of taxonomies or post terms.

Let’s say a post has term IDs 1,2,3 assigned and this is our shortcode:

[related_posts_by_tax terms="1,2,9" taxonomies="all"]

It will display related posts with with terms 1,2,9 in common ordered by most terms in common.

Let’s change the shortcode to include the same terms with the include_terms attribute

[related_posts_by_tax include_terms="1,2,9" taxonomies="all"]

Now it will only display related posts with term ID’s 1 and 2 because they are the terms in common with the current post.

When we now set related to false related post with term ID’s 1,2,9 are displayed.

[related_posts_by_tax include_terms="1,2,9" related="false" taxonomies="all"]

Excluding terms
You can exclude terms with the exclude_terms parameter.

By default the plugin gets the current post terms and removes the exclude terms from the terms found. Then it searches for related posts within the remaining terms and orders them by relatedness. The found posts however can still have one or more of the excluded terms. It’s a mind bender 🙂

If you need to totally exclude posts that have the excluded terms you’ll need the following code snippet in your (child) theme’s functions.php.

add_filter( 'related_posts_by_taxonomy_widget_args', 'rpbt_related_posts_exclude_terms' );
add_filter( 'related_posts_by_taxonomy_shortcode_atts', 'rpbt_related_posts_exclude_terms' );

function rpbt_related_posts_exclude_terms( $args ) {
	if ( $args['exclude_terms'] ) {
		$args['exclude_terms_strict'] = $args['posts_per_page'];
		$args['posts_per_page'] = -1;

	return $args;

add_filter( 'related_posts_by_taxonomy', 'related_posts_exclude_terms_strict', 10, 4 );

 * This function queries for all posts that have terms from the exclude_terms parameter.
 * And excludes them from the results.
function related_posts_exclude_terms_strict(  $related_posts, $post_id, $taxonomies, $args ) {
	global $wpdb;

	if ( empty( $related_posts ) || empty( $args['exclude_terms'] )  ) {
		return $related_posts;

	if ( ! isset( $args['exclude_terms_strict'] ) ) {
		return $related_posts;

	if ( ! ( empty( $args['fields'] ) || ( 'ids' === $args['fields'] ) ) ) {
		return $related_posts;

	// Escape ids for use in query
	$exclude_terms = array_map( 'esc_sql',  $args['exclude_terms'] );
	$term_ids_sql = "tt.term_id IN (" . implode( ', ', $exclude_terms ) . ")";

	// Query for posts (ids) with the excluded terms assigned.
	$query = "
        SELECT p.ID FROM $wpdb->posts p
        LEFT JOIN $wpdb->term_relationships t ON (p.ID = t.object_id)
        WHERE EXISTS (
            SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy tt
            WHERE tt.term_taxonomy_id = t.term_taxonomy_id
            AND {$term_ids_sql}
        ) GROUP BY p.ID

	$results = $wpdb->get_col( $query );
	if ( ! $results ) {
		return $related_posts;

	$include_posts = array();
	foreach ( $related_posts as $key => $related_post ) {
		$id = isset( $related_post->ID ) ? $related_post->ID :  $related_post;
		if ( ! in_array( $id, $results ) ) {
			// Add posts that don't have the excluded terms
			$include_posts[] = $related_post;

	$related_posts = array_values( $include_posts );
	if ( -1 !== (int) $args['exclude_terms_strict'] ) {
		$posts_per_page = absint( $args['exclude_terms_strict'] );
		$posts_per_page = ( $posts_per_page ) ? $posts_per_page : 5;
		$related_posts  = array_slice( $related_posts, 0, $posts_per_page );

	return $related_posts;

Use a post thumbnail fallback image

By default only posts with post thumbnails are found if you use the format thumbnails. But what if you wanted to search for all posts and use a fallback image if a post doesn’t have a post thumbnail.

Use the code below in your (child) theme’s functions.php to use a new “images” format in the widget and shortcode.
Screen Shot 2015-06-07 at 16.27.59

This is how you use it in the shortcode.

[related_posts_by_tax format="images"]

The code below will display images in this order:

  • If there is a post thumbnail, it will show it like it already does.
  • If there is no post thumbnail, it shows the first attached image if there is one.
  • Optional, If no attached image is found, you can set your own fallback image in the code below where it says Use your own fallback image here.
// Adds the 'Post Images' format to the widget
// after the plugin's defaults are set (priority 11).
add_action( 'wp_loaded', 'rpbt_add_post_images_format_widget', 11 );

function rpbt_add_post_images_format_widget() {

	if ( !class_exists( 'Related_Posts_By_Taxonomy_Defaults' ) ) {

	$defaults = Related_Posts_By_Taxonomy_Defaults::get_instance();

	// Add the new format.
	$defaults->formats['images'] = __( 'Post Images' );

// Sets the format to thumbnails if the Post Images format is used.
// Adds filters to remove the sql used to only find posts with post thumbnails.
add_filter( 'related_posts_by_taxonomy_shortcode_atts', 'rpbt_post_images_format' );
add_filter( 'related_posts_by_taxonomy_widget_args', 'rpbt_post_images_format' );

function rpbt_post_images_format( $args ) {

	// Check if the new images format is used.
	if ( 'images' === $args['format'] ) {

		// Set format to thumbnails if Post Images format is used.
		$args['format'] = 'thumbnails';

		// Removes the sql to search for posts with post thumbnails only.
		add_filter( 'get_meta_sql', '__return_empty_string', 23 );

		// Removes the filter after related posts are retrieved.
		add_filter( 'related_posts_by_taxonomy', 'rpbt_remove_meta_sql_filter' );

		// Removes the filter if no related posts were found.
		add_action( 'related_posts_by_taxonomy_after_display', 'rpbt_remove_meta_sql_filter' );

	return $args;

// Remove the filter
function rpbt_remove_meta_sql_filter( $results ) {
	remove_filter( 'get_meta_sql', '__return_empty_string', 23 );
	return $results;

// Use a fallback image if a post has no post thumbnail.
add_filter( 'related_posts_by_taxonomy_post_thumbnail_link', 'rpbt_related_post_fallback_image', 10, 4 );

function rpbt_related_post_fallback_image( $image, $attr, $related, $args ) {

	if ( !empty( $image ) ) {
		// Post thumbnail found.
		return $image;

	$image_args = array(
		'numberposts' => 1,
		'order' => 'ASC',
		'post_mime_type' => 'image',
		'post_parent' => $related->ID,
		'post_status' => null,
		'post_type' => 'attachment',

	$attachments = get_children( $image_args );

	if ( !empty( $attachments ) ) {
		// Post attachment image found.
		$attachments = array_values( $attachments );
		$attachment_id = (int) $attachments[0]->ID;

		// Use the first attachment image.
		$image = wp_get_attachment_image( $attachment_id , $args['size'], false, $attr['describedby'] );
	} else {
		 * Use your own fallback image here.
		 * Example of an image uploaded with the media editor.
		 * Change the attachment ID (123) below to your uploaded fallback image ID.
		 * And remove the two foreward slashes at the beginning.
		// $image = wp_get_attachment_image( 123, $args['size'], false, $attr['describedby'] );

	$image = $image ? "<a href='{$attr['permalink']}' title='{$attr['title_attr']}'>{$image}</a>" : '';

	return $image;

Here is a simple fallback image you can use:

See the url how you can change the text and dimensions. Right click and save the image.

Query by meta

You can limit the search for related posts by using a meta query. Let’s say we wanted to query related posts with a meta key ‘price’ and meta value that is less than 20.

With the shortcode you can use the meta attributes.

[related_posts_by_tax meta_key="price" meta_value="20" meta_compare="<" meta_type="NUMERIC"]

For the widget or complex queries you can use a meta query filter. The next example queries for related posts with the meta key ‘price’ and meta value between 20 and 30.

add_filter( 'related_posts_by_taxonomy_posts_meta_query', 'rpbt_meta_query_price_range' , 10, 4 );

function rpbt_meta_query_price_range( $meta_query, $post_id, $taxonomies, $args ) {
	 * The $meta_query variable is an array.
	 * If not empty it could be the meta query for post_thumbnails ( _thumbnail_id )
	 * or some other meta query (from the shortcode?). Check the $args for meta arguments used.
	 * Important Note: meta_query takes an array of meta query arguments arrays
	 * (it takes an array of arrays)
	 * The default relation of meta queries is 'AND'

	// Add the query for price between 20 and 30

	$meta_query[] = array(
		'key'     => 'price',
		'value'   => array( 20, 30 ),
		'type'    => 'numeric',
		'compare' => 'BETWEEN',

	return $meta_query;

Get better random posts.

By default if you use the ‘RAND’ order attribute this plugin will get the related posts and randomize the results. This can lead to seeing the same 5 randomized related posts on every related posts page. By using this in your (child) theme’s functions.php the posts are randomized from a larger group of related posts (set by the ‘posts_per_page’ attribute).

add_filter( 'related_posts_by_taxonomy', 'related_posts_by_taxonomy_randomize', 10, 4 );

function related_posts_by_taxonomy_randomize( $related_posts, $post_id, $taxonomies, $args ) {

	// Randomize the related posts.
	shuffle( $related_posts );

	// Get the first five randomized posts.
	// change 5 to how many related posts you want to show
	$related_posts = array_slice( (array) $related_posts, 0, 5 );

	return $related_posts;

Make sure you don’t set the ‘order’ value to ‘RAND’ but instead set the ‘posts_per_page’ attribute to an amount larger than 5 (or whatever amount you want to show) to randomize the found posts.

Sort posts alphabetically

With this in your (child) theme’s functions.php the posts will be sorted alphabetically.

add_filter( 'related_posts_by_taxonomy', 'related_posts_by_taxonomy_orderby_title', 10, 4 );

function related_posts_by_taxonomy_orderby_title( $results, $post_id, $taxonomies, $args ) {
	usort( $results, 'km_rpbt_sort_by_title' );
	return $results;

function km_rpbt_sort_by_title( $a, $b ) {
	return strcasecmp( $a->post_title, $b->post_title );

Remove captions from post thumbnails

Add this to your (child) theme’s functions.php file.

add_filter('related_posts_by_taxonomy_caption', '__return_empty_string');

Use the link_caption attribute.

Display title and spinner when using the lazy loading feature

To display the title and a spinner when loading the related posts with the lazy loading feature you can use the related_posts_by_taxonomy_lazy_loading_html filter. Put this code in your (child) theme’s functions.php file.

// Add the title and a spinner when loading posts with the lazy loading feature.
add_filter( 'related_posts_by_taxonomy_lazy_loading_html', 'rpbt_related_posts_add_spinner_lazy_loading', 10, 2 );

function rpbt_related_posts_add_title_and_spinner_lazy_loading( $html, $args ) {
	$title = '';
	if ( isset( $args['title'] ) && $args['title'] ) {
		$title = trim( $args['before_title'] . $args['title'] . $args['after_title'] );

	$before = "before_{$args['type']}";
	$after  = "after_{$args['type']}";

	// Accessibility for screen readers.
	$content = "<span class='rpbt-screen-reader-text'>";
	$content .= __( 'Loading related posts', 'your-theme-text-domain' );
	$content .= "</span>\n";

	// HTML.
	$html =  isset( $args[ $before ] ) ? $args[ $before ]  . "\n" : '';
	$html .= "<div class='rpbt-lazy-loading-title'>\n";
	$html .= $title . "\n";
	$html .= "</div>\n";
	$html .= "<div class='rpbt-lazy-loading-content'>\n";
	$html .= $content;
	$html .= "</div>\n";
	$html .=  isset( $args[ $after ] ) ? $args[ $after ]  . "\n" : '';

	return $html;

And this CSS in the Customizer Additional CSS module:

.rpbt-lazy-loading-content:after {
  border-radius: 50%;
  width: 24px;
  height: 24px;
.rpbt-lazy-loading-content {
  margin: 60px auto;
  font-size: 10px;
  position: relative;
  border-top: 3px solid rgba(0,0,0, 0.2);
  border-right: 3px solid rgba(0,0,0, 0.2);
  border-bottom: 3px solid rgba(0,0,0, 0.2);
  border-left: 3px solid #000000;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
  -webkit-animation: load8 1.1s infinite linear;
  animation: load8 1.1s infinite linear;
@-webkit-keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
@keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);

You should now see a spinner when the related posts are not loaded yet.

Widget support for post type Page

Note: The widget should detect if the post type Page has taxonomies since version 2.6.0.

If you can’t select the Page post type in the widget it is because Pages don’t have taxonomy support by default. If you’ve added taxonomy support for Pages (in your theme or with a plugin) you have to tell the related posts widget it supports taxonomies.

Add this to your (child) theme’s functions.php file to add a post type Page checkbox to the widget.

// Add the 'page' post type just after the plugin's defaults are set (priority 11).
add_action( 'wp_loaded', 'add_widget_related_post_type_page', 11 );

function add_widget_related_post_type_page() {

	if ( !class_exists( 'Related_Posts_By_Taxonomy_Defaults' ) ) {

	$defaults = Related_Posts_By_Taxonomy_Defaults::get_instance();
	$defaults->post_types['page'] = __( 'Pages' );