Crea tu propio motor de búsqueda

Crea tu propio motor de búsqueda para WordPress

En este artículo vamos a ver cómo personalizar la búsqueda en WordPress, creando nuestro propio motor de búsqueda para adaptarlo a nuestras necesidades.

Por defecto el buscador de WordPress realiza las búsquedas en el título, extracto, y contenido de todas tus entradas y páginas, y también lo hará en tus Custom Post Types si al definirlos has marcado exclude_from_search = false.

Para cargar el formulario de búsqueda en tus plantillas basta con llamar a la función get_search_form() desde el template que quieras (p.e: sidebar.php). Lo que hace esta función es pintar el código que tengas en el archivo searchform.php de tu tema (si no lo tienes puedes crearlo). El ejemplo para un formulario de búsqueda básico es:

<form role="search" method="get" class="search-form" action="<?php echo home_url( '/' ); ?>">
  <label>
    <span class="screen-reader-text"><?php echo _x( 'Search for:', 'label' ) ?></span>
    <input type="search" class="search-field" placeholder="<?php echo esc_attr_x( 'Search …', 'placeholder' ) ?>" value="<?php echo get_search_query() ?>" name="s" title="<?php echo esc_attr_x( 'Search for:', 'label' ) ?>" />
  </label>

  <input type="submit" class="search-submit" value="<?php echo esc_attr_x( 'Search', 'submit button' ) ?>" />
</form>

Como vemos, es muy básico, un simple input y un botón para enviar el formulario. Vamos a ver como enriquecer esta búsqueda y poder filtrar por categorías, etiquetas, limitar la búsqueda a un tipo de contenido determinado e incluso extender la búsqueda a campos personalizados o custom fields.

Ampliando la búsqueda para filtrar por categorías y etiquetas

La búsqueda por defecto en WordPress puede resumirse en un formulario con un input, que al enviarse te lleva a una url del tipo https://midominio.es/?s=busqueda. Es decir, envía por $_GET el parámetro “s” con el valor de lo que hemos introducido en el campo buscar. Internamente genera una consulta (WP_Query) que devuelve los resultados de los posts, pages y CPTs que contengan esa palabra en el título o contenido.

El parámetro s es una variable de consulta o Query Var. Aquí tienes un listado con todas las Query Vars disponibles, vamos a montar un ejemplo con category_name y tag.

Simplemente añadimos dos campos de tipo select, a los que llamaremos category_name y tag, para que de este modo, cuando enviemos el formulario, nos pase por la url el parámetro correspondiente quedando algo tipo https://midominio.es/?s=busqueda&category_name=noticias

<form role="search" method="get" class="search-form" action="<?php echo home_url( '/' ); ?>">
  <label>
    <span class="screen-reader-text"><?php echo _x( 'Search for:', 'label' ) ?></span>
    <input type="search" class="search-field" placeholder="<?php echo esc_attr_x( 'Search …', 'placeholder' ) ?>" value="<?php echo get_search_query() ?>" name="s" title="<?php echo esc_attr_x( 'Search for:', 'label' ) ?>" />
  </label>

  <select id="category_name" name="category_name">
    <option value="">Todas</option>
    <?php $categories = get_categories();
    foreach ($categories as $key => $category) {?>
      <option value="<?php echo $category->slug;?>"><?php echo $category->name;?></option>
    <?php }?>
  </select>

  <select id="tag" name="tag">
    <option value="">Todas</option>
    <?php $tags = get_tags();
    foreach ($tags as $key => $tag) {?>
      <option value="<?php echo $tag->slug;?>"><?php echo $tag->name;?></option>
    <?php }?>
  </select>

  <input type="submit" class="search-submit" value="<?php echo esc_attr_x( 'Search', 'submit button' ) ?>" />
</form>

Podemos añadir más campos usando las Query Vars como por ejemplo:

  • category_name: slug de una categoría. Admite valores múltiples separados por coma (p.e. category_name=noticias,eventos)
  • cat: ID de la categoría. Admite valores múltiples separados por coma
  • p: ID de un post de cualquier tipo.
  • name: slug de un post de cualquier tipo.
  • author: ID de autor
  • author_name: user_nicename de autor
  • tag: slug de una etiqueta. Admite valores múltiples separados por coma
  • tag_ID: ID de la etiqueta. Admite valores múltiples separados por coma
  • post_type: slug del tipo de post. post_type=any para mostrar posts de cualquier tipo.
  • year: para filtrar por año
  • month: para filtrar por mes
  • day: para filtrar por día
  • orderby: Indica el campo por el cual ordenar los resultados. Por ejemplo title, name, date…
  • order: Indica el orden de los resultados. Puede ser ASC o DESC.

Limitar la búsqueda a un tipo de contenido determinado

Si queremos limitar la búsqueda a un tipo de contenido determinado, por ejemplo que sólo busque en las entradas (descartando pages y CPTs), podemos hacerlo de dos maneras. La primera es añadiendo un input de tipo hidden a nuestro formulario de búsqueda llamado post_type y asignándole el valor post. De este modo pasará el parámetro post_type a la búsqueda:

<input type="hidden" name="post_type" value="post" />

La segunda opción es añadiendo un filtro a pre_get_posts en nuestro archivo functions.php:

<?php

function my_custom_searchengine($query) {
  if ($query->is_search && !is_admin()) {
    $query->set('post_type', array('post'));
  }
  return $query;
}
add_filter( 'pre_get_posts', 'my_custom_searchengine' );

Como vemos en este ejemplo, en éste filtro preguntamos si estamos haciendo una búsqueda y fuera del admin, en caso de que se cumpla esta condición establecemos que busque sólo en posts.

Ampliar la búsqueda a campos personalizados

Ésta parte tiene un poco más de miga ya que WordPress te permite extender al búsqueda a campos personalizados o custom fields a través de meta_query, pero con el operador lógico AND. Es decir, podrías construir una búsqueda para que encuentre resultados que coincidan en el título, o en el extracto, o en el contenido…y además también en el custom field que indiquemos:

<?php

function my_custom_search_query( $query ) {
  if ( !is_admin() && $query->is_search ) {
    $query->set('meta_query', array(
      array(
        'key' => 'prueba',
        'value' => $query->query_vars['s'],
        'compare' => 'LIKE'
      )
    ));
  };
}
add_filter( 'pre_get_posts', 'my_custom_search_query' );

De esta forma nuestra búsqueda quedaría: (título Ó extracto Ó contenido) Y (campo personalizado). Ésto puede resultar restrictivo porque lo que nos interesa es que nos devuelva todos los posts que contengan donde sea al menos una coincidencia con lo que estoy buscando.

Para ésto necesitamos tirar de ingenio. Lo que podemos hacer es a través del filtro posts_where un reemplazo del mismo donde hacemos el like al post_title, lo reemplazaremos por el like al post title más «o en el campo personalizado»:

<?php

function my_custom_search_where( $where ) {
  global $pagenow, $wpdb;

  if ( is_search() && !is_admin() ) {
    $where = preg_replace("/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/", "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
  }

  return $where;
}
add_filter( 'posts_where', 'my_custom_search_where' );

De esta manera podemos extender la funcionalidad de búsqueda por defecto y adaptarla a nuestras necesidades, creando un formulario de búsqueda avanzada que mejorará la experiencia de usuario.

¿Te ha resultado útil esta información? 🍺

Si este post te ha resuelto un problema, invítame a un café o a una cerveza. Con este pequeño gesto me animas a seguir escribiendo.

Comentarios

7 comentarios en Crea tu propio motor de búsqueda para WordPress

  1. Hola, muy bueno el post, quisiera hacer uno igual, pero para buscar productos de woocommerce, y filtral por categorias y etiquetas/taxonomias. seria posible usar el mismo ejemplo? Gracias de ante mano.

    1. Hola Luis. Si, sería posible. Si sigues este ejemplo tendrías que limitar al post_type de producto de WooCommerce, que es «product» y las categorías/etiquetas «product_cat» y «product_tag»

  2. Hola, me fue de gran ayuda tu post.

    He usado este código en mi archivo functions.php

    is_search && !is_admin()) {
    $query->set(‘post_type’, array(‘post’));
    }
    return $query;
    }
    add_filter( ‘pre_get_posts’, ‘my_custom_searchengine’ );

    Cómo tengo que poner para que sólo haga la búsqueda por etiquetas de las entradas?

    Gracias de antemano

  3. Muy util tu post!!
    Estoy desarrollando un buscador «avanzado» donde lo que necesito es filtrar por categorías.
    En mi formulario tengo el campo de búsqueda y los checkbox con las categorías. Lo que necesito es que si marco 2 categorías ( o más) la búsqueda se haga solo en las entradas que tienen esas 2 categorías asignadas. Ahora la búsqueda la hace en todas las entradas con la categoría A y la categoría B, lo que necesito es que busque solo en las entradas que tengan la categoría A y B.
    En una query fuera normal puedo usar el argumento category__in’ y logro el resultado que necesito, por ejemplo: ‘category__in’ => ‘9+11’

    Desde ya muchas gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *:

  • El fin del tratamiento es únicamente la moderación de comentarios para evitar spam
  • La legitimación es tu consentimiento al comentar
  • No se comunicará ningún dato a terceros salvo por obligación legal
  • Tienes derecho al acceso, rectificación y eliminación de los comentarios