O Guia Avançado para Otimizar o Desempenho do WordPress

Publicados: 2022-03-11

Hoje, o WordPress alimenta mais de 30% da Internet. É fácil de usar, incrivelmente popular e não vai a lugar nenhum tão cedo.

Mas o WordPress pode ser lento. Então, como você o otimiza?

Existem muitos artigos sobre como ajustar e otimizar o WordPress. Na verdade, o próprio WordPress fornece um guia robusto sobre otimização do WordPress.

Na maioria das vezes, esses artigos e tutoriais cobrem conceitos bastante básicos, mas úteis, como o uso de plugins de cache, integração com redes de entrega de conteúdo (CDNs) e minimização de solicitações. Embora essas dicas sejam altamente eficazes e até necessárias, no final, elas não abordam o problema subjacente: a maioria dos sites WordPress lentos é resultado de código ruim ou ineficiente.

O Guia Avançado para Otimizar o Desempenho do WordPress

O WordPress pode ser lento, mas não precisa ser.
Tweet

Portanto, este artigo visa principalmente fornecer aos desenvolvedores e empresas de desenvolvimento do WordPress algumas diretrizes que podem ajudá-los a abordar as causas subjacentes de muitos problemas de desempenho do WordPress.

O WordPress fornece muitos recursos orientados ao desempenho que geralmente são ignorados pelos desenvolvedores. O código que não aproveita esses recursos pode retardar as tarefas mais simples, como buscar postagens. Este artigo detalha quatro soluções possíveis, que abordam alguns dos problemas subjacentes por trás do desempenho lento do WordPress.

Buscando postagens

O WordPress oferece a possibilidade de buscar qualquer tipo de postagem do banco de dados. Existem três formas básicas de fazer isso:

  • Usando a função query_posts() : Esta é uma abordagem muito direta, mas o problema é que ela substitui a consulta principal, o que pode levar a inconvenientes. Por exemplo, isso pode ser um problema se quisermos determinar, em algum momento depois de buscar as postagens (como dentro de footer.php ), com que tipo de página estamos lidando. De fato, a documentação oficial tem uma nota recomendando contra o uso desta função, pois você precisará chamar uma função adicional para restaurar a consulta original. Além disso, substituir a consulta principal afetará negativamente os tempos de carregamento da página.

  • Usando a função get_posts() : Isso funciona quase como query_posts() , mas não modifica a consulta principal. Por outro lado, get_posts() por padrão executa a consulta com o parâmetro suppress_filters definido como true . Isso pode levar a inconsistências, especialmente se usarmos filtros relacionados a consultas em nosso código, pois postagens que você não espera em uma página podem ser retornadas por essa função.

  • Usando a classe WP_Query : Na minha opinião, esta é a melhor maneira de recuperar posts do banco de dados. Ele não altera a consulta principal e é executado de maneira padrão, assim como qualquer outra consulta do WordPress.

Mas seja qual for o método que usamos para interagir com o banco de dados, há outras coisas que precisamos considerar.

Limitando a consulta

Devemos sempre especificar quantos posts nossa consulta deve buscar.

Para isso, usamos o parâmetro posts_per_page .

O WordPress nos permite indicar -1 como um valor possível para esse parâmetro, nesse caso o sistema tentará buscar todos os posts que atendam às condições definidas.

Esta não é uma boa prática, mesmo que tenhamos certeza de que obteremos apenas alguns resultados como resposta.

Por um lado, raramente podemos ter certeza de obter apenas alguns resultados de volta. E mesmo se pudermos, não definir nenhum limite exigirá que o mecanismo de banco de dados verifique todo o banco de dados em busca de correspondências.

Por outro lado, limitar os resultados geralmente permite que o mecanismo de banco de dados verifique apenas parcialmente os dados, o que se traduz em menos tempo de processamento e resposta mais rápida.

Outra coisa que o WordPress faz por padrão, que pode afetar negativamente o desempenho, é tentar trazer posts fixos e calcular quantas linhas foram encontradas na consulta.

Muitas vezes, porém, não precisamos realmente dessa informação. Adicionar esses dois parâmetros desativará esses recursos e acelerará nossa consulta:

 $query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );

Excluindo postagens da consulta

Wordpress Excluir postagens da consulta

Às vezes, queremos excluir determinados posts da consulta. O WordPress oferece uma maneira bastante direta de alcançá-lo: usando o parâmetro post__not_in . Por exemplo:

 $posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }

Mas, embora isso seja bastante simples, não é ideal porque internamente gera uma subconsulta. Especialmente em grandes instalações, isso pode levar a respostas lentas. É mais rápido deixar esse processamento ser feito pelo interpretador PHP com algumas modificações simples:

 $posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }

O que eu fiz lá?

Basicamente, tirei algum trabalho do mecanismo de banco de dados e o deixei para o mecanismo PHP, que faz a mesma coisa, mas na memória, que é muito mais rápido.

Quão?

Primeiro, removi o parâmetro post__not_in da consulta.

Como a consulta pode nos trazer alguns posts que não queremos como resultado, aumentei o parâmetro posts_per_page . Dessa forma eu garanto que, mesmo se eu tivesse alguns posts indesejados em minha resposta, eu teria pelo menos $posts_per_page posts desejados lá.

Então, quando eu faço um loop sobre os posts eu só processo aqueles que não estão dentro do array $posts_to_exclude .

Evitando parametrizações complexas

Todos esses métodos de consulta oferecem uma ampla variedade de possibilidades para buscar posts: por categorias, por meta chaves ou valores, por data, por autor, etc.

E embora essa flexibilidade seja um recurso poderoso, ela deve ser usada com cautela, pois essa parametrização pode se traduzir em junções de tabelas complexas e operações de banco de dados caras.

Na próxima seção, descreveremos uma maneira elegante de ainda obter funcionalidade semelhante sem comprometer o desempenho.

Aproveitando ao máximo as opções do WordPress

A API de opções do WordPress fornece uma série de ferramentas para carregar ou salvar dados facilmente. É útil para lidar com pequenas informações, para as quais outros mecanismos que o WordPress oferece (como postagens ou taxonomias) são excessivamente complexos.

Opções do WordPress otimizadas

Por exemplo, se quisermos armazenar uma chave de autenticação ou a cor de fundo do cabeçalho do nosso site, as opções são o que procuramos.

O WordPress não apenas nos fornece as funções para lidar com eles, mas também nos permite fazê-lo da maneira mais eficiente.

Algumas das opções são mesmo carregadas diretamente quando o sistema é iniciado, proporcionando assim um acesso mais rápido (ao criar uma nova opção, precisamos considerar se queremos carregá-la automaticamente ou não).

Considere, por exemplo, um site no qual temos um carrossel exibindo as últimas notícias especificadas no back-end. Nosso primeiro instinto seria usar uma meta-chave para isso da seguinte forma:

 // functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;

Como você pode ver, essa abordagem é muito simples, mas não é a ideal. Ele realizará uma consulta ao banco de dados tentando encontrar uma postagem com uma meta-chave específica. Poderíamos usar uma opção para obter um resultado semelhante:

 // functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;

A funcionalidade varia ligeiramente de um exemplo para outro.

Na primeira parte do código, sempre obteremos as últimas notícias de última hora, em termos da data de publicação do post.

Na segunda, toda vez que um novo post for definido como notícias de última hora, ele substituirá as notícias de última hora anteriores.

Mas como provavelmente queremos uma postagem de notícias de última hora por vez, isso não deve ser um problema.

E, no final, alteramos uma consulta de banco de dados pesada (usando WP_Query com meta-chaves) em uma consulta simples e direta (chamando get_post() ), que é uma abordagem melhor e com melhor desempenho.

Também poderíamos fazer uma pequena mudança e usar transientes em vez de opções.

Os transitórios funcionam de maneira semelhante, mas nos permitem especificar um tempo de expiração.

Por exemplo, para notícias de última hora, cabe como uma luva porque não queremos um post antigo como notícia de última hora, e se deixarmos a tarefa de alterar ou eliminar essa notícia de última hora para o administrador, ele pode esquecer de fazer isto. Então, com duas mudanças simples, adicionamos uma data de validade:

 // functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;

Ativar cache persistente

O WordPress tem nativamente um mecanismo de cache de objetos.

As opções, por exemplo, são armazenadas em cache usando esse mecanismo.

Mas, por padrão, esse cache não é persistente, o que significa que ele dura apenas a duração de uma única solicitação. Todos os dados são armazenados em cache na memória, para acesso mais rápido, mas estão disponíveis apenas durante essa solicitação.

Ilustração de cache persistente

O suporte ao cache persistente requer a instalação de um plug-in de cache persistente.

Alguns plug-ins de cache de página inteira vêm com um plug-in de cache persistente incluído (por exemplo, W3 Total Cache), mas outros não, e precisamos instalá-lo separadamente.

Vai depender da arquitetura da nossa plataforma, se vamos usar arquivos, Memcached ou algum outro mecanismo para armazenar dados em cache, mas devemos aproveitar esse recurso incrível.

Alguém pode perguntar: “Se esse é um recurso tão bom, por que o WordPress não o habilita por padrão”?

A principal razão é que, dependendo da arquitetura da nossa plataforma, algumas técnicas de cache funcionarão e outras não.

Se hospedarmos nosso site em nosso servidor distribuído, por exemplo, devemos usar um sistema de cache externo (como um servidor Memcached), mas se nosso site residir em um único servidor, poderíamos economizar dinheiro simplesmente usando o sistema de arquivos para cache.

Uma coisa que precisamos levar em conta é a expiração do cache. Essa é a armadilha mais comum de trabalhar com cache persistente.

Se não resolvermos esse problema corretamente, nossos usuários reclamarão que não verão as alterações feitas ou que as alterações demoraram muito para serem aplicadas.

Às vezes, vamos nos encontrar fazendo trocas entre desempenho e dinamismo, mas mesmo com esses obstáculos, o cache persistente é algo que praticamente todas as instalações do WordPress devem aproveitar.

AJAX da maneira mais rápida

Se precisarmos nos comunicar via AJAX com nosso site, o WordPress oferece alguma abstração na hora de processar a solicitação no lado do servidor.

Mesmo que essas técnicas possam ser usadas ao programar ferramentas de back-end ou envios de formulários a partir do front-end, elas devem ser evitadas se não forem estritamente necessárias.

A razão para isso é que, para usar esses mecanismos, somos obrigados a fazer uma solicitação de postagem para algum arquivo localizado dentro da pasta wp-admin . A maioria (se não todos) dos plugins de cache de página inteira do WordPress nem solicitações de postagem de cache nem chamadas para arquivos de administrador.

Por exemplo, se carregarmos dinamicamente mais postagens quando o usuário estiver rolando nossa página inicial, seria melhor chamar diretamente para alguma outra página de front-end, que terá os benefícios de ser armazenada em cache.

Poderíamos então analisar os resultados via JavaScript no navegador.

Sim, estamos enviando mais dados do que precisamos, mas estamos ganhando em termos de velocidade de processamento e tempo de resposta.

Destrua a noção de que o WordPress é apenas lento

Estes são apenas alguns conselhos que os desenvolvedores devem considerar ao codificar para o WordPress.

Às vezes, esquecemos que nosso plugin ou tema pode precisar conviver com outros plugins, ou que nosso site pode ser servido por uma empresa de hospedagem que atende centenas ou milhares de outros sites com um banco de dados comum.

Nós nos concentramos apenas em como o plugin deve funcionar e não em como ele lida com essa funcionalidade, ou como fazê-lo de maneira eficiente.

Pelo exposto, fica claro que as causas do mau desempenho no WordPress são códigos ruins e ineficientes. No entanto, o WordPress fornece todas as funcionalidades necessárias por meio de suas várias APIs que podem nos ajudar a criar plugins e temas com muito mais desempenho sem comprometer a velocidade da plataforma geral.