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.

[php]
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’ );[/php]

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:

[zilla_one_third]Post 1:
título: Praia de Boiçucanga
conteudo: Lorem ipsum dolor sit amet
termos: praia, mirante [/zilla_one_third][zilla_one_third]Post 2:
título: Camburi
conteudo: Praia Lorem ipsum dolor sit
termos: mirante[/zilla_one_third] [zilla_one_third_last]Post 3:
título: Toque toque pequeno
conteudo: Lorem ipsum dolor sit amet
termos: praia [/zilla_one_third_last]
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:

[php]
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 );

[/php]

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

[sql]
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’
)
[/sql]

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

[sql]
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%’
)
)

[/sql]

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 um comentário

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