Plugin para Entradas Relacionadas basado en Swiftype Search

Publicada en WordPress.

Hoy me gustaría hablaros del plugin que el equipo de Nelio hemos desarrollado para uno de nuestros clientes, FBTrash, y el cual está disponible para todos vostros. Pero, antes, permitidme que os sitúe un poco. FBTrash utiliza el plugin Swiftype Search. Tal y como podemos leer en la descripción del plugin:

Swiftype Search reemplaza la búsqueda estándard de WordPress por un motor de búsqueda mejor y que ofrece resultados más relevantes. Además, ofrece información detallada sobre qué están buscando vuestros usuarios, para que así sepáis qué palabras clave debéis usar para mejorar vuestras búsquedas.

Personalmente, he tenido la oportunidad de utilizar este motor y debo reconocer que funciona muy bien. Este plugin de búsqueda es muy sencillo de usar: instalar, poner credenciales de Swiftype y listo. Una vez está en marcha, el plugin escaneará todas vuestras entradas y enviará la información a la plataforma de Swiftype. A partir de este instante, cuando alguien realice una búsqueda en vuestro blog, ésta será procesada por Swiftype. El plugin se complementa con el dashboard de Swiftype (el cual os permite gestionar qué resultados se devuelven -y en qué orden- dada una búsqueda)
e información estadística.

Así pues, siendo conscientes de la potente herramienta que tenemos, ¿no sería genial poder usar su motor de búsqueda para obtener la lista de entradas relacionadas?

Nelio Related Posts

El lunes de esta semana publicamos Nelio Related Posts en el directorio oficial de plugins de WordPress. Si estáis un poco metidos en el tema, sabréis que hay muchísimos plugins de este tipo… así que, ¿por qué crear uno nuevo?

Nelio Related Posts Plugin
Captura de la ventana de configuración de nuestro nuevo plugin de entradas relacionadas

Nuestro plugin difiere de otros por dos motivos. Por un lado, Nelio Related Posts os permite definir, dado una cierta entrada, qué cadena de búsquedase usará para encontrar y listar las entradas relacionadas. Por otro lado, si el plugin Swiftype Search está instalado, entonces la búsqueda se realiza utilizando, precisamente, el motor de Swiftype.

Por otro lado, nuestro plugin incluye las características habituales que podéis esperar de un plugin así: configuración del número de entradas relacionadas, utilización de una cache para funcionar eficientemente, …

Pero mi intención hoy no es hacer (únicamente) promoción de nuestro plugin, sino utilizarlo como base para enseñaros algunas ideas sobre cómo implementar un plugin para WordPress. Los componentes más importantes de un plugin que busque las entradas relacionadas son, básicamente, dos: la parte que se encarga de buscar esas entradas relacionadas, y la parte que se encarga de dibujarlas.

Veamos la clase que se encarga de añadir las entradas relacionadas en el código HTML de nuestros posts (fichero 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 "";
   }
}

Como podemos ver, lo «único» que tenemos que hacer para añadir las entradas relacionadas es poner un hook al filtro de WordPress post_content (línea 13). Las entradas relacionadas las obtenemos, como ya hemos insinuado, a través de la segunda parte importante de nuestro plugin: el buscador. Antes, sin embargo, quisiera comentaros las otras dos funciones relevantes del código anterior: get_related_posts and get_search_string.

  • La primera es la que invoca al buscador de posts que, como veremos, se basa en Swiftype. La función utiliza un par de opciones de la tabla postmeta para almacenar la lista de entradas relacionadas. Si nunca hemos hecho ninguna búsqueda o hace ya mucho tiempo que hicimos la última, ésta se vuelve a realizar y los resultados se almacenan en una de esas opciones. Sino, devolvemos directamente el valor de esa opción (tenemos una cache para mejorar la eficiencia, vaya).
  • La segunda función devuelve la cadena de texto que se utilizará para realizar la búsqueda. Este texto puede haber sido especificado por el autor de la entrada (y se almacena en un meta atributo) o puede ser cualquiera de las etiquetas de la entrada.

Por otro lado tenemos el fichero search.php. Éste contiene la clase NelioSRPSearch, la cual es la responsable de llevar a cabo la búsqueda (si lo que hubiera en la cache fuera demasiado viejo). Fijaos en cómo el método search intenta, en primer lugar, usar las funcionalidades de Swiftype. Si éste falla o no está disponible, el plugin sigue funcionando, pues realiza una búsqueda utilizando las funciones propias de WordPress.

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;
   }
}

¡Y eso es todo! Sé que estoy siendo un poco escueto, pero creo que el código es bastante más explicativo que todo lo que yo os puedo decir. Además, me gustaría que si tenéis dudas o queréis profundizar más en algún punto, abriéramos un debate en los comentarios 😉

Así que ya sabéis, chicos, es hora de descargarse el plugin, cotillear el código, aprender con él… y, ¿por qué no?, ¡usarlo en vuestras webs!

Imagen destacada de Clem Onojeghuo en Unsplash.

FlojaNo está malBienMuy bien¡Impecable! (Ninguna valoración todavía)
Cargando…

2 comentarios en «Plugin para Entradas Relacionadas basado en Swiftype Search»

Deja un comentario

No publicaremos tu correo electrónico. Los campos obligatorios están marcados con: •

He leído y acepto la Política de privacidad de Nelio Software

Al marcar la casilla de aceptación estás dando tu legítimo consentimiento para que tu información personal se almacene en SiteGround y sea usada por Nelio Software con el propósito único de publicar aquí este comentario. Contáctanos para corregir, limitar, eliminar o acceder a tu información.