Related Posts with SearchWP

We use SearchWP on almost all the websites we build. It provides search results based on relevancy rather than recency; indexes more attributes like categories, tags, and custom fields; and includes detailed reporting for on-site searches.

It’s also a great tool for related posts. Instead of showing recent posts in the same category or tag and hoping they are related to the current post, you can ask SearchWP for content that is actually related.

The Related Content extension adds a metabox for controlling the keywords used. By default it uses the current post’s title as the keyword, but you can modify it to include any keywords you like. It also displays live search results based on those keywords:

This metabox appears on all post types by default, but you can use searchwp_related_excluded_post_types to exclude, or include it on specific post types.

Displaying Related Posts

There are a few different ways to display the related posts:

  1. SearchWP can auto-append them to the bottom of your posts using their template.
  2. SearchWP can auto-append them to the bottom of your posts using your template, defined in your-theme/searchwp-related/related.php. Here’s more information on building your own template for their template loader.
  3. You define where they appear in your theme and use their template loader, either with their template or your custom template. Here’s a code example.
  4. You define where they appear in your theme and use your own custom query. This gives you the most flexibility over the query and display.

My Approach

I like to use #4 and then add a fallback in case SearchWP is ever disabled, or if the keyword search delivers less results than we want displayed.

I created a be_get_related_posts() function that queries for related using SearchWP Related. If we need more posts, we then query for recent posts in the same primary category using ea_first_term().

/**
 * Get Related Posts
 * @link https://www.billerickson.net/related-posts-with-searchwp/
 * 
 */
function ea_get_related_posts( $related_to_show = false ) {
	$related_to_show = !empty( $related_to_show ) ? intval( $related_to_show ) : get_option( 'posts_per_page' );
	$related = array();

	// Use SearchWP
	if( class_exists( 'SearchWP_Related' ) && count( $related ) < $related_to_show ) {

		// Instantiate SearchWP Related
		$searchwp_related = new SearchWP_Related();

		// Use the keywords as defined in the SearchWP Related meta box
		$keywords = get_post_meta( get_the_ID(), $searchwp_related->meta_key, true );
		if( empty( $keywords ) )
			$keywords = get_the_title();

		$args = array(
			's'			=> $keywords,  // The stored keywords to use
			'engine'		=> 'default',  // the SearchWP engine to use
			'posts_per_page'	=> $related_to_show - count( $related ),
			'post__not_in'		=> array( get_the_ID() ),
			'fields'		=> 'ids',
		);

		// Retrieve Related content for the current post
		$swp_related = $searchwp_related->get( $args );
		if( !empty( $swp_related ) ) {
			$related = array_merge( $related, $swp_related );
		}
	}

	// Fallback, use primary category
	if( count( $related ) < $related_to_show ) {
		
		$loop = new WP_Query( array(
			'posts_per_page'	=> $related_to_show - count( $related ),
			'category_name'		=> ea_first_term( 'category', 'slug' ),
			'post__not_in'		=> array_merge( $related, array( get_the_ID() ) ),
			'fields' 		=> 'ids',
		));
		if( ! is_wp_error( $loop ) && !empty( $loop->posts ) )
			$related = array_merge( $related, $loop->posts );
	}

	return $related;
}

Then I create a function to display the related posts. We use template parts for reusable blocks of code like post summaries. This allows us to use the same format for listings on archive pages, post listings on landing pages, and related posts on single posts.

/**
 * Related Posts 
 * @link https://www.billerickson.net/related-posts-with-searchwp/
 *
 */
function be_related_posts() {
	$related = ea_get_related_posts( 3 );
	if( empty( $related ) )
		return;
    
	$loop = new WP_Query( array(
		'post__in'  => $related,
		'orderby'   => 'post__in',
	) );
  
	if( $loop->have_posts() ):

		echo '<section class="related-posts">';
		echo '<h3>Related Posts</h3>';
		while( $loop->have_posts() ): $loop->the_post();
			get_template_part( 'partials/archive', 'related' );
		endwhile;
		echo '</section>';
	endif; 
	wp_reset_postdata();
}
add_action( 'genesis_after_entry', 'be_related_posts' );

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Hans Schuijff says

    Thanks Bill. I didn’t yet know the plugin and will certainly try it out.

    Small error: the link on “template parts” above doesn’t work (it contains 2 URLs concatenated).

    Cheers,
    Hans