Blog

Como usar a WP_Query da forma correta

Como-usar-a-WP_Query-da-forma-correta
Coding

Como usar a WP_Query da forma correta

Vou te mostrar nesse post como usar a WP_Query, que é uma classe super-útil do WordPress e pode poupar bastante nosso trabalho.

Aqui na agência, uma boa parte dos jobs que realizamos são mais avançados, personalizados, que exigem um pouco de codificação.

Então, quero compartilhar com você um pouco dessa experiência e os principais recursos que utilizamos para atender nossos clientes.

Um recurso muito útil é a classe WP_Query que ajuda a encontrar informações sem ter que lidar com tantas variáveis internas e globais.

Como usar a WP_Query

Segundo a própria documentação da classe, há dois principais cenários onde você pode usar a WP_Query:

O primeiro é descobrir com que tipo de requisição o WordPress está lidando no momento.

O segundo é usar em um Loop, onde a WP_Query vai fornecer diversas funções para tarefas comuns a ele.

Podemos fazer uso das propriedades $is_* (Ex: $is_single$is_page$is_archive$is_preview$is_date, etc) e também as Tags Condicionais para melhorar ainda mais nossos resultados.

Portanto, a WP_Query é um outro caminho para que possamos recuperar conteúdos, posts, páginas, etc, para critérios específicos do banco de dados do WordPress.

Vale lembrar que já compartilhei com você aqui uma série sobre manipulação de banco de dados e também ja falei sobre a classe wpdb.

A principal vantagem da WP_Query Class é não ter que lidar com consultas SQL e isso tem várias vantagens incluindo em relação à segurança.

Assim, vamos usar a classe declarando um Array e o objeto $query vai se responsabilizar por construir a consulta SQL que precisamos.

Antes de avançarmos, recomendo que você acesse a página da documentação oficial e dê, nem que seja, uma lida rápida nela.

Vai ser extremamente proveitoso se você tiver conhecimento dos métodos e variáveis disponíveis para usarmos com a classe `WP_Query`.

Um detalhe importante a dizer é que, mesmo que você tenha bom conhecimento de SQL, o WordPress é capaz de construir consultas muito otimizadas.

Desse modo, teremos consultas bem mais eficientes, sem falar do sistema de cache, além de reduzir os tempos de execução das consultas.

Primeiros Passos

Um outra dica interessante, é você instalar o plugin gratuito Query Monitor, que vai te mostrar informações úteis e importantes sobre as consultas entre outros recursos.

Se você quiser, também pode forçar o WordPress a armazenas suas consultas, usando a seguinte constante no seu arquivo wp-config.php:

define( 'SAVEQUERIES', true );

Quando você definir o SAVEQUERIES para true, o WordPress vai registrar suas consultas e informações relacionadas no array $wpdb->queries.

Novamente, já falamos sobre a classe wpdb e é interessante você se informar a respeito dela também.

Mas, voltando ao assunto, armazenando essas informações nesse Array, você poderá consultá-lo, fazendo listar as consultas memorizadas.

Para fazer isso, você pode usar o seguinte código:

if ( current_user_can( 'administrator' ) ) {
	global $wpdb;
	echo '<pre>';
	print_r( $wpdb->queries );
	echo '</pre>';
}

Uma breve explicação: Estou verificando se o usuário é administrador antes de mostrar as consultas e devo usar global $wpdb para usar o método queries.

Esse código pode ser adicionado em qualquer arquivo de template, por exemplo, no footer.php, ou você pode preferir até criar um shortcode.

Um exemplo de retorno desse Array seria algo como:

[4] => Array
(
	[0] => SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')  ORDER BY wp_posts.post_date DESC LIMIT 0, 10
	[1] => 0.0163011550903
	[2] => require('wp-blog-header.php'), wp, WP->main, WP->query_posts, WP_Query->query, WP_Query->get_posts, QM_DB->query
	[trace] => QM_Backtrace Object
		( ... )
	[result] => 10
)

Agora, uma coisa importante também a dizer é que não é recomendável estar com a constante SAVEQUERIES ligada (true) em um ambiente de produção.

WP_Query na prática

Os posts são o coração do WordPress e você pode consultá-los no banco de dados usando a função get_posts, que retornará um Array.

Entretanto, podemos usar a classe WP_Query e um dos seus métodos para retornar nossos posts.

Portanto, vamos começar criando um Loop clássico, usado em muitos arquivos de templates de boa parte dos temas:

// A Query
$the_query = new WP_Query( $args );
// O Loop
if ( $the_query->have_posts() ) {
	while ( $the_query->have_posts() ) : $the_query->the_post(); 
		// Seu código vai aqui...
	endwhile;
} else {
		// nenhum post encontrado
}
/* Restaurar o Post Data original */
wp_reset_postdata();

Explicando rapidamente: $args é um conjunto e pares de chaves/valores, que chamamos de vars (variáveis) de consulta, e que afetam diretamente a consulta SQL.

Se você quiser fazer uma interceptação na Query usando um plugin, por exemplo, você pode usar o filtro pre_get_posts, da seguinte forma:

function meuplugin_pre_get_posts( $query ) {
  if ( is_admin() || ! $query->is_main_query() ){
	return;
  }
  $query->set( 'category_name', 'tutoriais' );
}
add_action( 'pre_get_posts', 'meuplugin_pre_get_posts', 1 );

Explicando rapidamente: O objeto $query é passado por referência e não por valor, ou seja, os argumentos afetarão apenas uma instância existente.

Veja também que usamos o método set que adiciona uma variável (query var) à consulta forçando o WordPress a recuperar, neste caso, posts da categoria tutoriais.

Assim, em nível de SQL, teríamos uma consulta do seguinte tipo no banco de dados MySQL:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts 
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1 
AND ( wp_term_relationships.term_taxonomy_id IN (12) )
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

Um detalhe sobre o LIMIT, é que essa Query vai respeitar o limite definido nas Configurações de Leitura:

Agora, se você quiser, também pode usar o parâmetro de paginação posts_per_page para criar uma consulta mais personalizada.

SQL_CALC_FOUND_ROWS

Muita gente sai fazendo consultas e não leva em consideração a otimização e tempo de execução, é um fato.

Talvez, quando se tem poucos posts e pouco tráfego você realmente não precise se preocupar tanto com isso porque não serão tantas queries.

Contudo, a medida que temos mais tráfego e já temos milhares de posts, cada milissegundo de diferença pode causar impactos significativos.

O modificador SQL_CALC_FOUND_ROWS força a consulta a contar o número de linhas encontradas na query e a função FOUND_ROWS() retorna o número, como a seguir:

SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
WHERE id > 100 LIMIT 10;

SELECT FOUND_ROWS();

O modificador SQL_CALC_FOUND_ROWS de consulta e a função FOUND_ROWS() função que o acompanha estão obsoletos a partir do MySQL 8.0.17; espere que eles sejam removidos em uma versão futura do MySQL. 

Para substituir esses dois elementos, poderíamos executar:

  1. Uma consulta com LIMIT
  2. Nova consulta usando COUNT(*) e sem LIMIT para determinar se há linhas adicionais

Seria algo assim:

SELECT * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM tbl_name WHERE id > 100;

Acredito que o modificador esteja se tornando obsoleto porque normalmente retarda significativamente o tempo de execução da consulta.

Claro que você pode seguir a recomendação oficial do MySQL e fazer como mostrei acima, mas o WordPress pode lidar com isso também usando a variável no_found_rows – vamos ver a seguir.

Cache do WordPress

O WordPress tem evoluído bastante com o passar dos anos e seu sistema de cache atual é realmente bom, especialmente para o banco de dados.

Embora a proposta do cache seja ajudar a melhorar a velocidade da página, isso pode fazer com que algumas consultas extras sejam feitas no banco de dados.

A opção que temos no WordPress, seria usar alguns parâmetros:

  • cache_results: Se deve guardar informações.
  • update_post_meta_cache: Se deve atualizar a meta cache posterior.
  • update_post_term_cache: Se deve atualizar a cache pós-termo.

O padrão deles é true.

Se você tiver usando Memcached, você não vai precisar se preocupar, porque o WordPress irá definir estes parâmetros como false.

Agora, se você não está usando um sistema de cache persistente, pode passar manualmente esses parâmetros para ter consultas mais eficientes:

function meuplugin_pre_get_posts( $query ) {
  if ( is_admin() || ! $query->is_main_query() ){
	return;
  }
  $query->set( 'category_name', 'tutoriais' );

  $query->set( 'no_found_rows', true );
  $query->set( 'update_post_meta_cache', false );
  $query->set( 'update_post_term_cache', false );
}
add_action( 'pre_get_posts', 'meuplugin_pre_get_posts', 1 );

Otimizando ainda mais

Deve ter percebido o quanto eu falo de otimização, certo? É porque é realmente muito importante e uma mindset vital para o desenvolvimento web.

Quando fazemos consultas ao banco de dados, é sempre recomendável limitar-se aos dados estritamente necessários, para ter uma consulta eficiente.

Por exemplo, muita gente usar SELECT * FROM tabela que traria todos os campos da tabela, mas na verdade só seria necessário alguns campos.

Então, deveríamos usar algo como SELECT nome, email FROM tabela quando precisamos apenas desses dois campos.

Em nível da classe WP_Query podemos restringir os campos também aos que são necessários apenas, usando a variável fields.

Quando, por exemplo, não precisamos de campos específicos, podemos limitar a ids e a variável aceita ids e id=>parent:

<?php
$args = array( 
	'no_found_rows' => true, 
	'update_post_meta_cache' => false, 
	'update_post_term_cache' => false, 
	'category_name' => 'cms', 
	'fields' => 'ids'
);
// A Query
$the_query = new WP_Query( $args );
$my_posts = $the_query->get_posts();

if( ! empty( $my_posts ) ){
    foreach ( $my_posts as $p ){
        // Seu código
    }
}
/* Restaurar Post Data */
wp_reset_postdata();
?>

O valor padrão, quando não definimos a variável fields, é todos os campos (*).

E aí, gostou? Deixe um comentário abaixo!

Espero que tenha te ajudado a melhorar a eficiência das suas consultas e nos vemos no próximo conteúdo…

Grande abraço,

Deixe seu comentário aqui...

O seu endereço de e-mail não será publicado.

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

Nosso site usa cookies e, portanto, coleta informações sobre sua visita para melhorar nosso site (por meio de análise), mostrar a você conteúdo de mídia social e anúncios relevantes. Por favor, consulte nossa página Termos & Políticas para mais detalhes ou concorde clicando no botão 'Aceitar'. OBS: Ao continuar a navegação, você, automaticamente, concorda.

Configurações de Cookies

Abaixo, você pode escolher os tipos de cookies que quer permitir neste site. Clique no botão "Salvar Configurações de Cookies" para aplicar sua escolha.

FuncionalNosso site usa cookies funcionais. Esses cookies são necessários para permitir que nosso site funcione.

AnalíticoNosso site usa cookies analíticos para permitir a análise de nosso site e a otimização para o propósito de a.o. a usabilidade.

Mídia SocialNosso site coloca cookies de mídia social para mostrar conteúdo de terceiros, como YouTube e Facebook. Esses cookies podem rastrear seus dados pessoais.

PublicidadeNosso site coloca cookies de publicidade para mostrar anúncios de terceiros com base em seus interesses. Esses cookies podem rastrear seus dados pessoais.

OutrosNosso site coloca cookies de terceiros de outros serviços que não são analíticos, mídia social ou publicidade.