Picture of a man's shoes

We’re WordPress specialists. We offer an amazing service for improving your conversion optimization rate in WordPress, as well as a super effective, perfectly tailored migration-to-WordPress service for anyone who’s using other CMS platforms and is thinking of using WordPress instead. Today, I want to talk about a plugin we’ve developed for one of our most cherished customers: FBTrash.

FBTrash uses the Swiftype Search plugin. As the description of plugin states,

The Swiftype Search plugin replaces the standard WordPress search with a better, more relevant search engine. It also gives you detailed insight into what your users are searching for, so you know which keywords to target when customizing your search engine results.

I’ve had the chance to test this engine and I have to admit that it works like a charm. The plugin itself is very easy to use: you just install it, introduce your Swiftype credentials… and you’re done! The plugin will scan all your posts and send the information back to Swiftype’s platform. From now on, the search engine your WordPress uses will no longer be the default one, but Swiftype’s.

The search plugin is then complemented by Swiftype’s dashboard (which lets you manage search results with drag and drop in order to sort them and see the changes reflected instantly back in your WordPress) and powerful analytics. With such a powerful tool, wouldn’t it be great if the list of related posts was built using Swiftype’s engine?

Nelio A/B Testing

Native Tests for WordPress

Use your WordPress page editor to create variants and run powerful tests with just a few clicks. No coding skills required.

Nelio Related Posts

Yesterday we released Nelio Related Posts, our new plugin for WordPress. You’re probably thinking… “there’s thousands of related post plugins… yet you created another one?” Well, even though that’s true, this plugin is different from the others because of two reasons. On the one hand, given a certain post, users can define the search query string that will be used for determining the list of related posts. On the other hand, the search is performed using the Swiftype’s technology (provided that the Swiftype Search plugin is installed). That said, the plugin includes all the common features you can expect from this kind of plugins: you can specify the number of related posts, it uses a cache mechanism to reduce the load and improve the speed, …

Settings Page of the WordPress plugin Nelio Related Posts
Screenshot of our new plugin‘s Settings Page.

For those of you who are interested in the details, I’d like to sketch the main functions of the plugin so that you can get a better understanding of how it works. The first important file of our plugin is nelio-srp-main.php:

/*
 * This snippet is based on the NelioSRPMain class of our Nelio Related Posts
 * plugins, as defined in version 1.0.0.
 */
class NelioSRPMain {
   /**
    * This function creates the required hooks for adding
    * a list of related posts after a post's content.
    */
   public function __construct() {
      if ( !is_admin() ) {
         add_filter( "the_content", array( &$this, "append_related_posts" ) );
         /* ... */
      }
      else {
         /* ... */
      }
   }
   /**
    * This function is a hook to the the_content filter. It appends the list of related posts.
    */
   public function append_related_posts( $content ) {
      global $post;
      if ( $post->post_type != "post" || is_feed() )
         return $content;
      remove_filter( "the_content", array( &$this, "append_related_posts" ) );
      $related_posts = $this->get_related_posts();
      $num_of_posts  = min( count( $related_posts ), NelioSRPSettings::get_max_num_of_rel_posts() );
      // Prepare the div block with the related posts
      $res = "";
      if ( $num_of_posts > 0 ) {
         $res .= "<div id="neliosrp" class="neliosrp-widget" data-swiftype-index="false">";
         $res .= "<h2>";
         $res .= strtr( NelioSRPSettings::get_title(), array( "{post_title}" => $post->post_title ) );
         $res .= "</h2>";
         for ( $i = 0; $i < $num_of_posts; ++$i ) {
            // Render the related post
         }
         $res .= "</div>";
      }
      add_filter( "the_content", array( &$this ,"append_related_posts" ) );
      return $content . $res;
   }
   /**
    * This function returns the list of related posts and deals with the cache. If the cache has
    * a list of posts and it is not "too old", the list of related posts is obtained from it.
    * Otherwise, the cache is (re)built.
    *
    * In order to create a cache of related posts for each post we use two post meta options:
    * _neliosrp_last_update and _neliosrp_related_posts. The former contains the date in which
    * the cache was created (so that we can rebuilt it when it's too old), and the latter contains
    * the cached data (that is, the list of related posts).
    */
   public function get_related_posts() {
      global $post;
      $now = time();
      $interval = max( 1, NelioSRPSettings::get_refresh_cache_interval_in_days() ) * 86400;
      $last_update = get_post_meta( $post->ID, "_neliosrp_last_update", true );
      if ( !$last_update )
         $last_update = 0;
      if ( $last_update + $interval < $now ) {
         require_once( NELIOSRP_DIR . "/search.php" );
         $searcher = new NelioSRPSearch();
         $result   = $searcher->search( $this->get_search_string() );
         update_post_meta( $post->ID, "_neliosrp_last_update", $now );
         update_post_meta( $post->ID, "_neliosrp_related_posts", $result );
      }
      else {
         $result = get_post_meta( $post->ID, "_neliosrp_related_posts", true );
         if ( !$result )
            $result = array();
      }
      return $result;
   }
   /**
    * This function returns the search string. If the user defined one custom search string,
    * it is stored in the post meta option _neliosrp_search_query. If no custom search string
    * was provided, it uses one of its tags randomly. Otherwise, no search string is used, and
    * an empty search string is used (which means that the latest posts will be returned).
    */
   private function get_search_string() {
      global $post;
      // OPTION 1. The search query the user specified
      $str = get_post_meta( $post->ID, "_neliosrp_search_query", true );
      if ( $str )
         return $str;
      // OPTION 2. One of the tags
      $posttags = get_the_tags();
      if ( $posttags ) {
         $tag = $posttags[0]; // Pick one tag randomly and return it
         return $tag;
      }
      // OPTION 3. A search that doesn't matter at all, just
      // to return something
      return "";
   }
}

In order to append the list of related posts somewhere, we decided to hook to the post_content filter (line 13), and the function that appends the related posts as HTML code is append_related_posts. The interesting functions in this file are, however, get_related_posts and get_search_string.

  • The former uses a searcher (which we discuss below) to obtain the list of related posts using the search query string. Note how this function uses a couple of post meta options to store the list of related posts, thus implementing a cache.
  • The latter function, on the other hand, returns the search string we have to use to retrieve the list of related posts. In essence, this string can either be something the author of the post specified manually (which is stored in a post meta attribute), or one tag of the post.

The other file that, in my opinion, is worth discussing, is search.php. It contains the class NelioSRPSearch, which is the one responsible of performing the search. The search method tries to use Swiftype’s search capabilities. If Swiftype Search is not available or there was an error when querying Swiftype, the function uses WordPress‘ regular search mechanisms.

class NelioSRPSearch {
   public function search( $string ) {
      include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
      if ( is_plugin_active( 'swiftype-search/swiftype.php' ) ) {
         try {
            return $this->swiftype_search( $string );
         } catch ( Exception $e ) {}
      }
      return $this->wordpress_search( $string );
   }
   /**
    * The function returns a list of up to 20 related
    * posts. The related posts are obtained by searching
    * the given string.
    */
   public function wordpress_search( $string ) {
      global $post;
      $args = array(
         's'              => $string,
         'post__not_in'   => array( $post->ID ),
         'posts_per_page' => 20
      );  
      
      $my_query = new wp_query( $args );  
      
      $related_posts = array();
      while( $my_query->have_posts() ) {  
         $my_query->the_post();  
         array_push( $related_posts, $post );
      }
      return $related_posts;
   }
   /**
    * The function returns a list of up to 20 related
    * posts. The related posts are obtained by searching
    * the given string with swiftype.
    */
   public function swiftype_search( $string ) {
      global $post;
      $api_key     = get_option( 'swiftype_api_key' );
      $engine_slug = get_option( 'swiftype_engine_slug' );
      $client      = new SwiftypeClient();
      $client->set_api_key( $api_key );
   
      $swiftype_result = $client->search(
         $engine_slug, 'posts', $string, array( 'page' => '1' ) );
   
      $related_posts = array();
      foreach ( $swiftype_result['records']['posts'] as $rel ) {
         $id = $rel['external_id'];
         if ( $post->ID == $id ) continue;
         $rel_post = get_post( $id );
         if ( $rel_post )
            array_push( $related_posts, $rel_post );
      }
      return $related_posts;
   }
}

And that’s it! The plugin then contains some additional files for styling the results, configuring the plugin, and so on. If you are interested in learning how a plugin is created, just download its source code and take a look at it. As I said, the plugin is pretty simple, yet very powerful!

I hope you folks liked today’s post… and I also hope you download Swiftype Search plugin and use it in your sites!

Edit (January 13th, 2015): Translated to Serbian by Ogi Djuraskovic, from First Site Guide (thanks Ogi!).

Featured image by soelin.

Leave a Reply

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

I have read and agree to the Nelio Software Privacy Policy

Your personal data will be located on SiteGround and will be treated by Nelio Software with the sole purpose of publishing this comment here. The legitimation is carried out through your express consent. Contact us to access, rectify, limit, or delete your data.