Posted on

Related Posts

Related posts are a popular feature, as it keeps the users engaged and offers them a new direction to continue to within your site, keeping the users on your site for a longer time.

Many plugins do related posts, but many have issues. Generating related posts can be a performance drain; the related posts may be irrelevant, and there may not be enough control over how the related posts are managed and kept up to date.

Relevanssi Premium offers related posts and takes care of all of these issues:

  1. Performance: Relevanssi uses transient caches to store the related posts for two weeks. The related posts are loaded from the transient cache very quickly, without any performance loss on the site. And don’t worry about the long cache periods: if a post is removed, Relevanssi will purge all related caches so that it will disappear from related posts right away.
  2. Relevance: Relevanssi uses the Relevanssi search index to look for related posts. This ensures the related posts are really related. Relevanssi can use titles, tags, categories and other taxonomy terms to match the related posts. You can also define custom keywords for each post, force particular posts to appear in the related posts and also block posts.
  3. Control: Relevanssi makes sure the caches are flushed whenever necessary. You can also manually flush all related posts caches and there’s also a WP CLI command for regenerating all related posts.

To get started, navigate to the Relevanssi settings (Settings > Relevanssi Premium) and go to the Related tab; check the “Enable related posts” checkbox to enable related posts in the first place.

To see related posts on your site, you can check the post types you want in the “Automatically add to these post types” settings to have Relevanssi automatically append the related posts to your posts. Relevanssi does this using the the_content filter hook, which should place the related posts at the bottom of the posts.

Enabling the related posts

The Keyword sources option will determine which content Relevanssi uses to find the related posts. The title is a good default option. You can also add taxonomies, like posts and categories. Using taxonomies requires that Relevanssi indexes the taxonomy; you can adjust that on the Relevanssi indexing settings page.

You can choose which post types Relevanssi uses for the related posts. “Matching post type” means that for posts, Relevanssi uses posts as related posts, and for pages, Relevanssi uses pages and so on. If you choose another post type, all posts will receive recommendations regardless of type.

You can also set the number of related posts shown and choose what happens if Relevanssi doesn’t find enough related posts: you can choose to use random posts or leave the related posts empty.

Choosing the related posts

If you don’t want to append the related posts to the posts automatically, you can use the relevanssi_the_related_posts() function in your templates. The function will print out the related posts. If used without a parameter, it will use the global $post (and thus only works within The Loop), but you can also specify the post ID as a parameter for the function.

You can also use the shortcode relevanssi_related_posts to print out the related posts. You can set the post ID as the parameter post_id or specify nothing to use the global post.

Relevanssi uses a template file to print out the related posts. You can find the default template in the /premium/templates/relevanssi-related.php file in the Relevanssi directory. If you use the default template, you can adjust the results from the settings page: you can choose whether Relevanssi displays the title, the thumbnail or the excerpt for the posts. Also, you can set up a default thumbnail for thumbnails if the post doesn’t have a thumbnail.

You can also set up the minimum width of the related posts. Relevanssi uses a simple CSS grid to lay out the related posts. This setting determines the minimum width of each element. Experiment with different values to see what works.

Style settings

If you want to style the related posts, Relevanssi wraps everything inside div#relevanssi_related, the header is in div.relevanssi_related_grid_header, and the grid itself is in div#relevanssi_related_grid. Each post is a div.relevanssi_related_post.

If you want to make more extensive modifications, you can create your template. Relevanssi will look for the relevanssi-related.php template inside the current theme templates directory, and if it finds one, it will use that instead of the default template. When creating your template, it’s best to start with the default template and make the changes you want while keeping the basic loop structure intact to ensure everything works as expected.

This template changes the related posts list to a simple bullet point list. Put this in a file relevanssi-related.php in the templates directory of your theme.

<?php
/**
 * Template for bullet list related posts.
 */

if ( ! empty( $related_posts ) ) :
	?>
	<div id="relevanssi_related">
		<h3><?php esc_html_e( 'Related Posts', 'relevanssi' ); ?></h3>
		<ul>
	<?php

	array_walk(
		$related_posts,
		function( $related_post_id ) {
			?>
	<li class="relevanssi_related_post">
		<a href="<?php echo get_permalink( $related_post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>">
			<?php echo get_the_title( $related_post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
		</a>
	</li>
			<?php
		}
	);
	?>

		</ul>
	</div>

	<?php
endif;

Single post settings

There are also Related posts controls on post edit pages. You can disable the auto-append for the post – for example, if you have related posts automatically added to all pages, there are probably pages where you don’t want them, like the front page. You can also disable to post so that Relevanssi never uses it as a related post for another post.

You can also specify keywords that Relevanssi uses to fetch the related posts for that post. If you want a specific post to appear as a related post, you can list the post ID.

The widget will also show the current list of related posts. Changing the settings should refresh the list right away. If there’s a post you don’t want to see on the list, click “Not this” to remove it from the list.

Single post settings

Advanced topics

The rest of this page is not required to use the related posts feature but can be interesting from technical standpoints or solve problems.

Caching

Relevanssi caches the related posts for each post. The caches are stored in transients and are kept for two weeks before they expire. The cache includes the whole related posts element, so it’s lightning-fast to serve once it’s in the cache (especially with a setup that stores the transients in memory).

Relevanssi also stores the post IDs of the related posts in a custom field (_relevanssi_related_posts); Relevanssi uses this in the admin dashboard and can be used for other purposes as well.

If a post is made non-public, Relevanssi finds all caches where the post is included and flushes those caches. Flushing the caches like this makes it possible for Relevanssi to keep long expiry periods while making sure drafts and trashed posts don’t appear in the related posts.

You can flush all the caches from the Relevanssi related posts settings page.

Cache settings

If you have other plugins that use the_content to add things to the bottom of the posts – like social media share buttons – you can adjust the priority and thus the location of the related posts using the relevanssi_related_priority filter hook. The default priority is 99. To move the related posts later, you can do this:

add_filter( 'relevanssi_related_priority', function() { return 999; } );

If you want the related posts to appear earlier, do the same but adjust the priority to a smaller number.

Improving the performance

If your keyword sources are rich and your related posts are using lots of words (maybe closer to ten words), searching may become a bit too heavy. The heaviness is not a problem in general searches because very few users use this many search terms, but this can be a problem in Related posts searches.

One way to improve performance in these cases is setting the throttle to a much tighter setting for Related posts searches. It’s not such a big deal if some relevant posts go missing occasionally, but the performance boost from the tighter throttle can make a big difference.

Throttle – and any other Relevanssi options – can be adjusted with the help of pre_relevanssi_related and post_relevanssi_related actions, which run before and after the Related posts search. Change the options in the pre action and return them to normal in the post action. Here’s an example of how to adjust the throttle to 50 for Related posts searches and modify the weights so that tags get a heavier weight in Related posts searches.

add_action( 'pre_relevanssi_related', 'rlv_pre_related_posts' );
function rlv_pre_related_posts() {
	// Make sure throttle is enabled and set it to a low value to avoid memory
	// issues if there are lots of keywords in the related posts search. If you
	// have the throttle enabled otherwise, this part is not necessary.
	global $relevanssi_throttle_enabled;
	$relevanssi_throttle_enabled = get_option( 'relevanssi_throttle' );
	if ( empty( $relevanssi_throttle_enabled ) || 'off' === $relevanssi_throttle_enabled ) {
		update_option( 'relevanssi_throttle', 'on' );
	}

        // This doesn't need undoing, because we don't change the option, just use
	// the pre_option to change the value on the fly.
	add_filter( 'pre_option_relevanssi_throttle_limit', function() { return 50; } );

	// Adjust the weight for tags to 20 to make tag matches more important.
	global $relevanssi_post_type_weights;
	$relevanssi_post_type_weights = get_option( 'relevanssi_post_type_weights' );
	$new_weights                  = $relevanssi_post_type_weights;

	$new_weights['post_tagged_with_post_tag'] = 20;
	update_option( 'relevanssi_post_type_weights', $new_weights );
}

add_action( 'post_relevanssi_related', 'rlv_post_related_posts' );
function rlv_post_related_posts() {
	// Disable the throttle if it should be disabled by default.
	global $relevanssi_throttle_enabled;
	if ( empty( $relevanssi_throttle_enabled ) || 'off' === $relevanssi_throttle_enabled ) {
		update_option( 'relevanssi_throttle', 'off' );
	}

	// Set the weights back to normal.
	global $relevanssi_post_type_weights;
	update_option( 'relevanssi_post_type_weights', $relevanssi_post_type_weights );
}

Warning about relevanssi_hits_filter filter hooks

If you have a filtering function on relevanssi_hits_filter it may interfere with the related posts. Often these filter functions assume that the hits array has complete post objects and may check $hit->post_type to sort the results by post type. However, the hits array contains just post IDs and not full post objects with related posts.

If you want to use the filter function with the related posts, you need to build it to work both with post objects and post ids. Here’s a straightforward approach:

foreach ( $hits[0] as $hit ) {
    $post_object  = relevanssi_get_an_object( $hit )['object'];

Now the filter can use the complete post object in $post_object to examine and filter the post, and when you save the post in the results array, $hit is used instead of $post_object to make sure you use the correct format.

If the filter function is something you don’t need for the related posts, it’s easiest to disable it:

add_action( 'pre_relevanssi_related', function() { remove_filter( 'relevanssi_hits_filter', 'function_name' ); } );

This action hook runs before the related posts queries and can be used to disable unwanted filters.

Here’s an article about using phrases in Related posts searches to make the suggestions more precise.

Sometimes you might want to use two separate sets of related posts. For example, you may want to have a set of related posts and another from a different post type. Relevanssi, however, is designed to show a single set of related posts.

However, it’s possible to get around this restriction, but it requires some work. The trick is first to display a set of related posts based on the plugin settings, then adjust the settings on the fly and then generate another set. To get around the caching, you need to use different methods for each set: you can display one with the standard relevanssi_the_related_posts() function and the other with relevanssi_get_related_post_objects() which will create a separate cache.

Here’s one example of how to display two sets of related posts in a post template:

// First display a set of posts with the default settings.
relevanssi_the_related_posts( $post->ID );

// Then add a filter to adjust the settings on the fly.
add_filter( 'pre_option_relevanssi_related_settings', function( $value ) {
  if ( empty( $value ) ) {
    // $value is empty by default, so get the settings from the database.
    // We can't use get_option() here!
    global $wpdb;
    $value = unserialize( $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'relevanssi_related_settings'" ) );
  }
  // Adjust the settings as necessary.
  $value['post_types'] = 'page';
  return $value;
} );

// Get the post objects with the new settings.
$objects = relevanssi_get_related_post_objects( $post->ID );

// Display the related posts, here's a very plain example.
echo '<div><h3>Related Pages</h3><ul>';
foreach ( $objects as $object ) {
  $link = get_permalink( $object->ID );
  echo "<li><a href='$link'>$object->post_title</a></li>";
}
echo '</ul></div>';

Another way to deal with caching is to use the relevanssi_related_posts_cache_id filter hook introduced in 2.15.3:

// This goes in the template:

// First display a set of posts with the default settings.
relevanssi_the_related_posts( $post->ID );

global $doing_second_related_posts;
$doing_second_related_posts = true;

// Get the post objects with the new settings.
relevanssi_the_related_posts( $post->ID );

// This can be in theme functions.php:

// Add a filter to adjust the settings on the fly.
add_filter( 'pre_option_relevanssi_related_settings', function( $value ) {
  if ( empty( $value ) ) {
    // $value is empty by default, so get the settings from the database.
    // We can't use get_option() here!
    global $wpdb;
    $value = unserialize( $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'relevanssi_related_settings'" ) );
  }
  // Adjust the settings as necessary.
  $value['post_types'] = 'page';
  return $value;
} );

// Change the name of the cache transient
add_filter( 'relevanssi_related_posts_cache_id', function( $id ) {
  global $doing_second_related_posts;
  if ( $doing_second_related_posts ) {
    $id = str_replace( '_jo', '_2nd', $id );
  }
  return $id;
} );

Leave a Reply

Are you a Relevanssi Premium customer looking for support? Please use the Premium support form.

Your email address will not be published. Required fields are marked *