Utilizando a busca do WordPress em termos de taxonomia

Imagine que em um site eu tenho uma taxonomia chamada “Tipo”, com os termos “Praia”, “mirante”, “restaurante” e “pousada”.
Quero fazer com que a busca do wordpress procure também nos nomes desses termos, ou seja, se eu digitar na busca a palavra “Praia” ele deve me retornar também os posts que estão associados a este termo (praia).

A busca padrão do WordPress tenta encontrar ocorrências dos termos pesquisados dentro dos campos título, conteúdo e resumo do post.

Podemos utilizar o mecanismo da busca padrão para encontrar ocorrências em outros campos também, neste caso, o nome dos termos de uma taxonomia associadas aos posts.

Minha primeira tentativa foi utilizar o hook  pre_get_posts para modificar os argumentos da query, incluindo um argumento tax_query.

function tax_na_busca($query) {
 if ( !$query->is_search ){
    
    //caso não seja busca retorna $query sem alteração
    return $query;
 }
 
 //caso é uma query de busca:

 //pega todos os termos da taxonomia "nome_taxonomia" que o tenham o nome igual ao valor digitado na busca
 $term = get_term_by('name', $query->query['s'], 'nome_taxonomia');
 
 
 //verifica se existe algum termo
 if ($term) {
   
   //pega a id do termo
   $id_termo = $term->term_id;
   
   //cria uma variavel com a tax_query que iremos inserir
   $tax_query = array(
   array(
     'taxonomy' => 'nome_taxonomia',
     'field' => 'id',
     'terms' => $id_termo,
     )
   );
 
   // modifica a query, adicionando a tax_query
   $query->set( 'tax_query', $tax_query );
 }

}
add_action( 'pre_get_posts', 'tax_na_busca' );

Não fiquei satisfeito com o resultado pois se existe o termo buscado na taxonomia a query irá trazer só os posts que tem esse termo de taxonomia ligado a ele.

Por exemplo, ao buscar pela palavra “praia” no site com os seguintes posts publicados:

Post 1:
título: Praia de Boiçucanga
conteudo: Lorem ipsum dolor sit amet
termos: praia, mirante
Post 2:
título: Camburi
conteudo: Praia Lorem ipsum dolor sit
termos: mirante
Post 3:
título: Toque toque pequeno
conteudo: Lorem ipsum dolor sit amet
termos: praia

em uma busca padrão ( sem a modificação ) teríamos como resultado os posts que se enquadram na seguinte regra lógica:
( (Tem praia no nome) OU (tem praia no conteúdo) OU (tem praia no resumo) )
ou seja, só os posts 1 e 2.

Na nossa busca modificada, como o termo “praia” existe na taxonomia “tipo”, temos como resultado os posts que se enquadram na seguinte regra lógica:
( (Tem praia no nome) OU (tem praia no conteúdo) OU (tem praia no resumo) ) E (é associado ao termo “praia” da taxonomia “tipo”)
ou seja, o post 1.

Para resolver o meu problema eu queria uma função que fizesse com que a busca retornasse esses três posts, seguindo a seguinte regra lógica:
( (Tem praia no nome) OU (tem praia no conteúdo) OU (tem praia no resumo) ) OU (é associado ao termo “praia” da taxonomia “tipo”)

Decidi então (após conselho do Matheus) utilizar o hook do wordpress posts_where para adicionar um filtro que altera a clausula WHERE do sql da query.

A minha nova função ficou assim:

function busca_tax( $where,&$wp_query ){
   	global $wpdb;
    global $wp_query;

		//verifica se a query é uma busca e se é main query
		if ($wp_query->is_main_query() AND $wp_query->is_search) {
			$busca = $_GET['s'];

			//Adiciona na clausula WHERE a busca por nome de termos mantendo o conteúdo anterior ( utilizando .= em vez de = ).
			$where .= "
				OR $wpdb->posts.ID
				IN (SELECT tr.object_id
					FROM $wpdb->term_relationships
					AS tr
					INNER JOIN $wpdb->term_taxonomy
					AS tt
					ON tr.term_taxonomy_id = tt.term_taxonomy_id
					WHERE tt.taxonomy = 'tipo'
					AND tt.term_id
					IN (SELECT t.term_id
						FROM $wpdb->terms
						AS t
						WHERE name
						LIKE '%$busca%'
					)
				)";
		return $where;
		}
return $where;
}
add_filter( 'posts_where', 'busca_tax', 10, 2 );

Em uma busca padrão pela palavra “praia” teriamos a seguinte clausula WHERE:

AND 
  (
    (
      (wp_posts.post_title LIKE '%praia%') 
      OR 
      (wp_posts.post_excerpt LIKE '%praia%') 
      OR 
      (wp_posts.post_content LIKE '%praia%')
    )
  )  
  AND 
  wp_posts.post_type IN ('post', 'page', 'attachment')
  AND 
  (
    wp_posts.post_status = 'publish' 
    OR 
    wp_posts.post_status = 'private'
  )

Na nossa nova busca com o filtro ativo temos a seguinte clausula WHERE:

AND 
(
  (
    (wp_posts.post_title LIKE '%praia%') 
    OR      
    (wp_posts.post_excerpt LIKE '%praia%') 
    OR 
    (wp_posts.post_content LIKE '%praia%')
  )
)  
AND 
wp_posts.post_type IN ('post', 'page', 'attachment') 
AND 
(
  wp_posts.post_status = 'publish' 
  OR 
  wp_posts.post_status = 'private'
)
OR   wp_posts.ID IN 
(
  SELECT tr.object_id
  FROM wp_term_relationships AS tr
  INNER JOIN wp_term_taxonomy AS tt
  ON tr.term_taxonomy_id = tt.term_taxonomy_id
  WHERE tt.taxonomy = 'tipo'
  AND tt.term_id
  IN 
  (
    SELECT t.term_id 
    FROM wp_terms AS t
    WHERE name
    LIKE '%praia%'         
   )
)

Você pode observar que até a linha 18 o código é o mesmo, a parte que adicionamos começa com um “OR”, para adicionar os resultados à busca padrão.
Dessa forma se o post contem a palavra “praia” no título mas não está relacionada com o termo “praia” da taxonomia ele também será retornado.

O novo código cria uma relação entre as tabelas wp_term_relashionships e wp_term_taxonomy da base de dados para limitar a busca dos termos que estejam incluídos na taxonomia “tipo”.

Durante esse processo utilizei a ferramenta Query Monitor, muito echo e print_r() para ver os parâmetros das querys e o conteúdo da variável $where.

 

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *