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,

Psiu! Quer dominar completamente o WordPress?

Assinatura Premium é tudo que você precisa!

Obtenha acesso à Conteúdos Exclusivos, Séries e Cursos Completos, além de muito conteúdo para aprender sobre os Recursos Mais Tops do WorPress… Mesmo que seja um iniciante, do zero e sem saber programar!

Venha fazer parte dessa comunidade!

Não perca mais nenhuma atualização aqui!

Posts Relacionados

39 respostas

  1. Olá Asllan Maciel, boa tarde!
    Sei que não tem muito a ver com o seu post mas acho que você pode me dar uma ajuda.
    Estou com um problema no caso das postagens repetidas, adicionei a seguinte função para remover as repetidas pelo link.

    ————————————————-//
    add_filter(‘post_link’, ‘arposts__track_displayed_posts’); add_action(‘pre_get_posts’,’arposts__remove_already_displayed_posts’);

    $displayed_posts = [];

    function arposts__track_displayed_posts($url) {
    global $displayed_posts;
    $displayed_posts[] = get_the_ID();
    return $url; // don’t mess with the url
    }

    function arposts__remove_already_displayed_posts($query) {
    global $displayed_posts;
    $query->set(‘post__not_in’, $displayed_posts);
    }
    ————————————————-//

    Até aqui tudo blz, porem tem uma sessão que preciso duplicar e nessa duplicação preciso re exibir as posts repetidas, ja rodei a net e não achei uma solução será que vc teria uma dica?

    Agradeço desde já.

    Abraço

    Osires Junior

  2. Your enthusiasm for the subject matter shines through in every word of this article. It’s infectious! Your dedication to delivering valuable insights is greatly appreciated, and I’m looking forward to more of your captivating content. Keep up the excellent work!

  3. Hi,

    wp24horas.com.br is only listed in a 8/10,000+ Directories

    We have a black friday deal going on at the moment to get your website listed in all 10k+ for $19.95

    Visit us on DirectoryBump.com

  4. Your dedication to sharing knowledge is unmistakable, and your writing style is captivating. Your articles are a pleasure to read, and I consistently come away feeling enriched. Thank you for being a dependable source of inspiration and information.

  5. Your blog has rapidly become my trusted source of inspiration and knowledge. I genuinely appreciate the effort you invest in crafting each article. Your dedication to delivering high-quality content is apparent, and I eagerly await every new post.

  6. In a world where trustworthy information is more crucial than ever, your dedication to research and the provision of reliable content is truly commendable. Your commitment to accuracy and transparency shines through in every post. Thank you for being a beacon of reliability in the online realm.

  7. Your passion and dedication to your craft radiate through every article. Your positive energy is infectious, and it’s evident that you genuinely care about your readers’ experience. Your blog brightens my day!

  8. Your positivity and enthusiasm are truly infectious! This article brightened my day and left me feeling inspired. Thank you for sharing your uplifting message and spreading positivity to your readers.

Deixe um comentário

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

Não perca mais nenhuma atualização aqui!

Tabela de Conteúdo
PUBLICIDADE
Últimos Posts