La guía avanzada para optimizar el rendimiento de WordPress

Publicado: 2022-03-11

Hoy, WordPress alimenta más del 30% de Internet. Es fácil de usar, increíblemente popular y no irá a ninguna parte en el corto plazo.

Pero WordPress puede ser lento. Entonces, ¿cómo lo optimizas?

Hay un montón de artículos sobre cómo ajustar y optimizar WordPress. De hecho, el propio WordPress proporciona una sólida guía sobre la optimización de WordPress.

En su mayor parte, estos artículos y tutoriales cubren conceptos bastante básicos pero útiles, como el uso de complementos de caché, la integración con redes de entrega de contenido (CDN) y la minimización de solicitudes. Si bien estos consejos son muy efectivos e incluso necesarios, al final, no abordan el problema subyacente: la mayoría de los sitios lentos de WordPress son el resultado de un código incorrecto o ineficiente.

La guía avanzada para optimizar el rendimiento de WordPress

WordPress puede ser lento, pero no tiene por qué serlo.
Pío

Por lo tanto, este artículo tiene como objetivo principal proporcionar a los desarrolladores y empresas de desarrollo de WordPress algunas pautas que pueden ayudarlos a abordar las causas subyacentes de muchos problemas de rendimiento de WordPress.

WordPress proporciona muchas funciones orientadas al rendimiento que los desarrolladores suelen pasar por alto. El código que no aprovecha estas funciones puede ralentizar las tareas más sencillas, como buscar publicaciones. Este artículo detalla cuatro posibles soluciones, que abordan algunos de los problemas subyacentes detrás del lento rendimiento de WordPress.

Obteniendo publicaciones

WordPress ofrece la posibilidad de obtener cualquier tipo de publicación de la base de datos. Hay tres formas básicas de hacerlo:

  • Uso de la función query_posts() : este es un enfoque muy directo, pero el problema es que anula la consulta principal, lo que podría generar inconvenientes. Por ejemplo, esto podría ser un problema si quisiéramos determinar, en algún momento después de obtener las publicaciones (como dentro de footer.php ), con qué tipo de página estamos tratando. De hecho, la documentación oficial tiene una nota que recomienda no usar esta función, ya que deberá llamar a una función adicional para restaurar la consulta original. Además, reemplazar la consulta principal tendrá un impacto negativo en los tiempos de carga de la página.

  • Usando la función get_posts() : Esto funciona casi como query_posts() , pero no modifica la consulta principal. Por otro lado, get_posts() por defecto realiza la consulta con el parámetro suppress_filters establecido en true . Esto podría generar inconsistencias, especialmente si usamos filtros relacionados con consultas en nuestro código, ya que esta función puede devolver publicaciones que no espera en una página.

  • Usando la clase WP_Query : en mi opinión, esta es la mejor manera de recuperar publicaciones de la base de datos. No altera la consulta principal y se ejecuta de forma estándar, como cualquier otra consulta de WordPress.

Pero cualquiera que sea el método que usemos para interactuar con la base de datos, hay otras cosas que debemos considerar.

Limitando la Consulta

Siempre debemos especificar cuántas publicaciones debe obtener nuestra consulta.

Para lograr eso, usamos el parámetro posts_per_page .

WordPress nos permite indicar -1 como posible valor para ese parámetro, en cuyo caso el sistema intentará recuperar todas las publicaciones que cumplan con las condiciones definidas.

Esta no es una buena práctica, incluso si estamos seguros de que solo obtendremos algunos resultados como respuesta.

Por un lado, rara vez podemos estar seguros de obtener solo algunos resultados. E incluso si podemos, establecer ningún límite requerirá que el motor de la base de datos escanee toda la base de datos en busca de coincidencias.

Por el contrario, limitar los resultados a menudo permite que el motor de la base de datos escanee solo parcialmente los datos, lo que se traduce en menos tiempo de procesamiento y una respuesta más rápida.

Otra cosa que WordPress hace de manera predeterminada, que puede afectar negativamente el rendimiento, es que intenta traer publicaciones fijas y calcular cuántas filas se encontraron en la consulta.

A menudo, sin embargo, en realidad no necesitamos esa información. Agregar estos dos parámetros deshabilitará esas funciones y acelerará nuestra consulta:

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

Exclusión de publicaciones de la consulta

Wordpress Excluir publicaciones de la consulta

A veces queremos excluir ciertas publicaciones de la consulta. WordPress ofrece una forma bastante directa de lograrlo: usando el parámetro post__not_in . Por ejemplo:

 $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 ] }

Pero si bien esto es bastante simple, no es óptimo porque internamente genera una subconsulta. Especialmente en instalaciones grandes, esto puede dar lugar a respuestas lentas. Es más rápido dejar que el intérprete de PHP realice el procesamiento con algunas modificaciones 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 ] } }

¿Qué hice allí?

Básicamente, eliminé parte del trabajo del motor de la base de datos y lo dejé en el motor de PHP, que hace lo mismo pero en la memoria, que es mucho más rápido.

¿Cómo?

Primero, eliminé el parámetro post__not_in de la consulta.

Dado que la consulta puede traernos algunas publicaciones que no queremos como resultado, aumenté el parámetro posts_per_page . De esa manera me aseguro de que, incluso si hubiera tenido algunas publicaciones no deseadas en mi respuesta, tendría al menos $posts_per_page publicaciones deseadas allí.

Luego, cuando recorro las publicaciones, solo proceso aquellas que no están dentro de la matriz $posts_to_exclude .

Evitar la parametrización compleja

Todos estos métodos de consulta ofrecen una amplia variedad de posibilidades para obtener publicaciones: por categorías, por metaclaves o valores, por fecha, por autor, etc.

Y si bien esa flexibilidad es una característica poderosa, debe usarse con precaución porque esa parametrización podría traducirse en uniones de tablas complejas y costosas operaciones de base de datos.

En la siguiente sección, describiremos una forma elegante de lograr una funcionalidad similar sin comprometer el rendimiento.

Exprimir al máximo las opciones de WordPress

La API de opciones de WordPress proporciona una serie de herramientas para cargar o guardar datos fácilmente. Es útil para manejar pequeñas porciones de información, para lo cual otros mecanismos que ofrece WordPress (como publicaciones o taxonomías) son demasiado complejos.

Opciones de wordpress optimizadas

Por ejemplo, si queremos almacenar una clave de autenticación o el color de fondo del encabezado de nuestro sitio, las opciones son lo que estamos buscando.

WordPress no solo nos brinda las funciones para manejarlos, sino que también nos permite hacerlo de la manera más eficiente.

Algunas de las opciones incluso se cargan directamente cuando se inicia el sistema, lo que nos proporciona un acceso más rápido (al crear una nueva opción, debemos considerar si queremos autocargarla o no).

Considere, por ejemplo, un sitio en el que tenemos un carrusel que muestra las últimas noticias especificadas en el back-end. Nuestro primer instinto sería usar una clave meta para eso de la siguiente manera:

 // 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 puede ver, este enfoque es muy simple, pero no es óptimo. Realizará una consulta de la base de datos tratando de encontrar una publicación con una meta clave específica. Podríamos usar una opción para lograr un resultado similar:

 // 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;

La funcionalidad varía ligeramente de un ejemplo a otro.

En el primer fragmento de código, siempre obtendremos las últimas noticias, en términos de la fecha de publicación de la publicación.

En el segundo, cada vez que se establece una nueva publicación como noticia de última hora, se sobrescribirá la noticia de última hora anterior.

Pero debido a que probablemente queremos una publicación de noticias de última hora a la vez, no debería ser un problema.

Y, al final, cambiamos una consulta de base de datos pesada (usando WP_Query con claves meta) en una consulta simple y directa (llamando a get_post() ), que es un enfoque mejor y más eficaz.

También podríamos hacer un pequeño cambio y usar transitorios en lugar de opciones.

Los transitorios funcionan de manera similar pero nos permiten especificar un tiempo de vencimiento.

Por ejemplo, para las noticias de última hora, nos viene como anillo al dedo porque no queremos un post antiguo como noticia de última hora, y si dejamos la tarea de cambiar o eliminar esa noticia de última hora al administrador, podría olvidarse de hacer eso. Entonces, con dos cambios simples, agregamos una fecha de vencimiento:

 // 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;

Habilitar el almacenamiento en caché persistente

WordPress tiene de forma nativa un mecanismo de almacenamiento en caché de objetos.

Las opciones, por ejemplo, se almacenan en caché usando ese mecanismo.

Pero, de forma predeterminada, ese almacenamiento en caché no es persistente, lo que significa que solo vive durante la duración de una sola solicitud. Todos los datos se almacenan en caché en la memoria, para un acceso más rápido, pero solo están disponibles durante esa solicitud.

Ilustración del almacenamiento en caché persistente

La compatibilidad con el almacenamiento en caché persistente requiere la instalación de un complemento de caché persistente.

Algunos complementos de caché de página completa vienen con un complemento de caché persistente incluido (por ejemplo, W3 Total Cache), pero otros no, y debemos instalarlo por separado.

Dependerá de la arquitectura de nuestra plataforma, si usaremos archivos, Memcached o algún otro mecanismo para almacenar datos en caché, pero debemos aprovechar esta increíble característica.

Uno podría preguntarse: "Si esta es una característica tan buena, ¿por qué WordPress no la habilita de forma predeterminada"?

El principal motivo es que, dependiendo de la arquitectura de nuestra plataforma, algunas técnicas de caché funcionarán y otras no.

Si alojamos nuestro sitio en nuestro servidor distribuido, por ejemplo, deberíamos usar un sistema de caché externo (como un servidor Memcached), pero si nuestro sitio web reside en un solo servidor, podríamos ahorrar algo de dinero simplemente usando el sistema de archivos. almacenar en caché

Una cosa que debemos tener en cuenta es la caducidad de la memoria caché. Este es el escollo más común de trabajar con el almacenamiento en caché persistente.

Si no abordamos este problema correctamente, nuestros usuarios se quejarán de que no verán los cambios que han realizado o que los cambios tardaron demasiado en aplicarse.

A veces nos encontraremos haciendo concesiones entre rendimiento y dinamismo, pero incluso con esos obstáculos, el almacenamiento en caché persistente es algo que prácticamente todas las instalaciones de WordPress deberían aprovechar.

AJAXing de la manera más rápida

Si necesitamos comunicarnos vía AJAX con nuestro sitio web, WordPress ofrece cierta abstracción a la hora de procesar la solicitud del lado del servidor.

Aunque esas técnicas se pueden usar al programar herramientas de back-end o enviar formularios desde el front-end, deben evitarse si no es estrictamente necesario.

La razón de esto es que para usar esos mecanismos, estamos obligados a hacer una solicitud de publicación a algún archivo ubicado dentro de la carpeta wp-admin . La mayoría (si no todos) de los complementos de almacenamiento en caché de página completa de WordPress no almacenan en caché las solicitudes de publicación ni las llamadas a los archivos del administrador.

Por ejemplo, si cargamos dinámicamente más publicaciones cuando el usuario se desplaza por nuestra página de inicio, sería mejor llamar directamente a alguna otra página de inicio, que obtendrá los beneficios de estar en caché.

Luego podríamos analizar los resultados a través de JavaScript en el navegador.

Sí, estamos enviando más datos de los que necesitamos, pero estamos ganando en términos de velocidad de procesamiento y tiempo de respuesta.

Destruya la noción de que WordPress es simplemente lento

Estos son solo algunos consejos que los desarrolladores deben tener en cuenta al programar para WordPress.

A veces, olvidamos que nuestro complemento o tema puede necesitar vivir junto con otros complementos, o que nuestro sitio puede ser atendido por una empresa de alojamiento que sirve a cientos o miles de otros sitios con una base de datos común.

Solo nos enfocamos en cómo debería funcionar el complemento y no en cómo maneja esa funcionalidad, o cómo hacerlo de manera eficiente.

De lo anterior, está claro que las causas fundamentales del bajo rendimiento en WordPress son un código malo e ineficiente. Sin embargo, WordPress proporciona todas las funcionalidades necesarias a través de sus diversas API que pueden ayudarnos a crear complementos y temas mucho más eficaces sin comprometer la velocidad de la plataforma en general.