Buscar por metadatos en WordPress usando el formulario de búsqueda.

WordPress permite buscar las entradas publicadas en nuestro sitio web a través de un formulario definido por nuestro tema. Así, dependiendo del tema y del contenido que queramos buscar, nuestro formulario de búsqueda será diferente en cada caso. Pero ninguno permite buscar por metadatos en WordPress, veamos cómo cambiar esto.

Formulario de búsqueda de la web keyplushomes.com
Este formulario consta del clásico cuadro de búsqueda más 6 selectores de opción y 10 checkbox.

Por defecto, cualquier formulario de WordPress buscará entradas por título y contenido. Si en nuestra entrada personalizada disponemos de información añadida como: precio, autor, fecha de alquiler, estado, etc… Necesitamos modificar el comportamiento de búsqueda que WordPress suministra por defecto.

WordPress siempre realiza las siguientes acciones a la hora de buscar entradas, o cualquier otro elemento: Custom post type, paginas, media, ….

  1. El formulario envía una petición de tipo GET o POST al servidor
  2. El servidor procesa esta petición, para ello, incluye los valores obtenidos en un objeto WP_Query, a través del método set.
  3. Justo después de crear el objeto WP_Query y antes de presentarlo por pantalla, ejecutamos el método set mediante el filtro pre_get_posts.
  4. El objeto devuelto es el resultado de nuestra búsqueda y se presenta por pantalla.
  5. El punto anterior finaliza el proceso de búsqueda si solo queremos buscar entradas por título o contenido. Para extender la capacidad de búsqueda del cuadro de búsqueda de WordPress, necesitamos aplicar el filtro posts_where, que recoge la documentación de WordPress.

Crear un formulario de búsqueda en WordPress

En la siguiente entrada, explico cómo crear un formulario de búsqueda en WordPress.

Construir objeto WP_Query de WordPress para mostrar el resultado de búsqueda

Al hacer búsquedas en WordPress, el responsable de mostrar los resultados en la pagina de búsqueda es el objeto WP_Query. Cuando usamos un formulario diferente al preestablecido, necesitamos capturar los datos que se envían desde el formulario y a partir de ahí, construimos el objeto WP_Query.

El método set permite modificar el objeto WP_Query a partir de los datos que se pasan desde el formulario. Para el propósito de este post, se puede aplicar el método set desde dos perspectivas:

  • Se configura el objeto WP_Query para que filtre las búsquedas por taxonomías. Para estos casos se usa: $query->set(‘tax_query’, $tax_query); donde $tax_query es un array compuesto por todas las taxonomías y términos que intervienen en el filtro.
  • Se configura el objeto WP_Query para que filtre las búsquedas por título, descripción, campo personalizado o meta datos de los post types. Para estos casos se usa: $query->set(‘meta-query’,$meta-query); donde $meta-query es un array compuesto por los diferentes tipos de datos que usamos para el filtrado.

Filtrado de datos por taxonomías

Punto de partida.

Disponemos de una web inmobiliaria que muestra inmuebles. Los inmuebles tienen las siguientes características:

Taxonomías:

  • Lista de características: Un ejemplo de característica puede ser ‘piscina’, ‘chimenea’, ‘Segunda mano’,…
  • Ciudad: Los inmuebles pertenecen a una ciudad como ‘Málaga’, ‘Chiclana’, ‘Algeciras’, ‘Cádiz’, etc…
  • Tipo de inmueble: Los inmuebles pueden ser ‘adosados’, ‘chalets’, ‘apartamento’, ‘oficina’, etc..
  • Tipo de oferta: Los inmuebles se pueden ‘vender’ o ‘alquilar’

Para definir una búsqueda por taxonomías ejecutamos el siguiente código:

$lista_de_caracteristicas=array();
$ciudad=array();
$tipo_de_inmueble=array();
$tipo_de_oferta=array();

//Creamos el array para el filtrado por taxonomías
$tax_query = array(
    'relation' => 'AND'
);

//Hay que asegurar que $cat_ids sea un array
$cat_ids = isset($_GET['caracteristicas']) ? $_GET['caracteristicas'] : array();
//Si el array no está vacío
if (count($cat_ids)!=0) {
    $lista_de_caracteristicas=array(
				'taxonomy' =>'caracteristica',
				'field' => 'slug',
				'terms' => $cat_ids,
				'operator' => 'IN',
			);
		array_push($tax_query, $lista_de_caracteristicas);
	}

//Hay que asegurar que $city_ids sea un array
$city_ids = isset($_GET['ciudad']) && $_GET['ciudad']!=='' ? array($_GET['ciudad']) : array();
//Si se ha seleccionado alguna ciudad construimos el array
if (count($city_ids)!=0) {
    $ciudad=array(
		'taxonomy' =>'ciudad',
		'field' => 'slug',
		'terms' => $city_ids,
		'operator' => 'IN',
		);
    array_push($tax_query, $ciudad);
}

//Aseguramos que $tipo sea un array
$tipo = isset($_GET['tipo_de_propiedad']) && $_GET['tipo_de_propiedad']!=='' ?array($_GET['tipo_de_propiedad']) : array();
//Si se ha seleccionado el tipo de propiedad, construimos el array
if (count($tipo)!=0) {
    $tipo_de_inmueble=array(
		'taxonomy' =>'tipo_de_propiedad',
		'field' => 'slug',
		'terms' => $tipo,
		'operator' => 'IN',
		);
    array_push($tax_query, $tipo_de_inmueble);
}
//Aseguramos que la oferta seleccionada sea un array
$oferta = isset($_GET['tipo_de_oferta']) && $_GET['tipo_de_oferta']!=='' ?array($_GET['tipo_de_oferta']) : array();
//Si el usuario ha seleccionado alguna oferta
if (count($oferta)!=0) {
    $tipo_de_oferta=array(
		'taxonomy' =>'tipo_de_oferta',
		'field' => 'slug',
		'terms' => $oferta,
		'operator' => 'IN',
		);
    array_push($tax_query, $tipo_de_oferta);
}

En el código anterior construimos los diferentes arrays dependiendo de si el usuario ha seleccionado, o no, la información desde el formulario. Lo tenemos que hacer así, porque si incluimos todos los arrays al array $tax-query, con una relación lógica ‘AND‘, no podriamos llevar a cabo nuestra búsqueda.

Filtrado de datos por Metadatos

Punto de partida

Los inmuebles del sitio web se representan a través del CPT ‘propiedades‘ y constan de los siguientes custom fields, o metadatos

Metadatos

  • Precio
  • Camas
  • Número de REF

Para filtrar resultados de búsqueda por metadatos, escribimos el siguiente código:

$precio_min=null;
if (isset($_GET['precio_min']) && $_GET['precio_min']!='')	
	$precio_min=$_GET['precio_min'];

$array_precio_min='';
if ($precio_min!=null) {
	$array_precio_min=array(
			'key' => 'precio',
			'value' => $_GET['precio_min'],
			'compare' => '>',
			'type' => 'NUMERIC'
			);
} else {
	$array_precio_min=array(
			'key' => 'precio',
			'value' => '0',
			'compare' => '>',
			'type' => 'NUMERIC'
			);
}

$precio_max=null;
if (isset($_GET['precio_max']) && $_GET['precio_max']!='')	
	$precio_max=$_GET['precio_max'];

$array_precio_max='';
if ($precio_max!=null) {
	$array_precio_max=array(
			'key' => 'precio',
			'value' => $_GET['precio_max'],
			'compare' => '<=',
			'type' => 'NUMERIC'
			);
} else {
	$array_precio_max=array(
			'key' => 'precio',
			'value' => '1000000',
			'compare' => '<=',
			'type' => 'NUMERIC'
			);
}

$camas=null;
if ($_GET['habitaciones'])	
	$camas=$_GET['habitaciones'];

$array_camas='';
if ($camas!=null) {
	$array_camas=array(
			'key' => 'camas',
			'value' => $_GET['habitaciones'],
			'compare' => '<=',
			'type' => 'NUMERIC'
			);
}
	
$meta_query = array(
	    	'relation' => 'AND',
	    	array(
    		'relation' => 'OR',
        		array(
		          'key' => 'referencia',
		          'value' => $query->query_vars['s'],
		          'compare' => 'LIKE'
			    ),
                        array(
			  'title'=>'post_title',
			  'value'=>$_GET['s'],
			  'compare'=>'LIKE'
			    ),
		    ),		 
		$array_precio_min,
		$array_precio_max,
		$array_camas,		  
	);

Volvemos a construir los arrays a partir de los datos que el usuario rellena desde el formulario.

Las dos instrucciones de código anterior se ejecutan por seguridad en búsquedas y por usuarios que no son administradores.

if ( !is_admin() &amp;&amp; $query->is_search ) {
	$query->set('tax_query', $tax_query);
        $query->set('meta_query', $meta_query);
}

Por último, todo el código anterior debe ir dentro de una función que se ejecutará cuando se crea el objeto WP_Query, pero justo antes de presentarlo en pantalla.

add_filter( 'pre_get_posts', 'my_custom_search_query' );

Modificar la consulta WP_Query para que busque por metadatos

Para conseguir buscar por metadatos en WordPress usando el formulario de búsqueda, debemos crear la siguiente secuencia de código:

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

  if ( is_search() &amp;&amp; !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' );

El código anterior modifica la consulta SQL que utiliza WordPress internamente. El código anterior también viene disponible en el codex de WordPress.

Conclusión

Espero haber servido de referencia para modificar consultas de búsqueda en WordPress. Permitir a los formularios de búsqueda buscar por metadatos en WordPress, no es un tema sencillo, de hecho para resolver el problema tuve que preguntar en Stackoverflow, tanto en español, como en ingles y aún así no recibí respuesta. Así que espero haber servido de ayuda y hasta el próximo post. Happycoding!!

Deja un comentario

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