Hoy en día, WordPress utiliza 25% del Internet. Es fácil de usar, muy popular, y no irá pronto a ninguna parte.

Pero Wordpress puede ser lento. Entonces ¿Cómo lo optimizas?

Hay un montón de artículos sobre cómo optimizar WordPress. De hecho, el mismo WordPress proporciona una robusta guía de como optimizarse.

En la mayoría de los casos, estos artículos y tutoriales cubren conceptos bastante básicos y sin embargo, útiles. Tal es el uso de plugins de caché, la integración con las redes de entrega de contenido (CDN) y la minimización de las solicitudes. Si bien estos consejos son altamente efectivos e incluso necesarios, no tratan el problema subyacente; la mayoría de sitios lentos de Wordpress son resultado de la mala o ineficiente codificación.

La Guía Avanzada Para Optimizar El Rendimiento De WordPress

Wordpress puede ser lento, pero no tiene que serlo.

Por lo tanto, este artículo está principalmente destinado a proporcionarle a los desarrolladores algunas pautas que puedan ayudarlos a abordar las causas subyacentes de muchos problemas de rendimiento de WordPress.

WordPress ofrece muchas características orientadas al rendimiento que a menudo son ignoradas por los desarrolladores. Código que no permita aprovechar estas características puede ralentizar la más sencilla de las tareas, tal como la obtención de puestos. Este artículo detalla cuatro posibles soluciones que abordan algunos de los problemas subyacentes detrás del lento desempeño de WordPress.

La Obtención De Puestos

WordPress ofrece la posibilidad de buscar cualquier tipo de puesto en la base de datos. Hay tres maneras básicas de hacerlo:

  • Usando el ‘query_posts()’ Función: Este es un enfoque muy directo, pero el problema es que anula la consulta principal que podría provocar inconvenientes. Por ejemplo, esto podría ser un problema si queremos determinar en algún momento después de la obtención de los puestos (como dentro de ‘footer.php’) con qué tipo de página estamos tratando. De hecho, la documentación oficial tiene una nota recomendada contra el uso de esta función como necesitará llamar a una función adicional para restaurar la consulta original. Además, la sustitución de la consulta principal tendrá un impacto negativo en los tiempos de carga de las páginas.

  • Usando la función ‘get_posts()’: Este funciona casi como ‘query_posts()’, pero no modifica la consulta principal. Por otro lado, ‘obtén_posts()’ por defecto realiza el query para ‘suprimir_archivos’, parámetro establecido en ‘verdadero’. Esto podría dar lugar a incoherencias, especialmente si utilizamos filtros relacionados con la consulta en nuestro código, ya que los puestos que no estás esperando en una página pueden ser devueltas por esta función.

  • Usando la clase ‘WP_query’: En mi opinión, esta es la mejor forma de recuperar los puestos de la base de datos. No altera la consulta principal y es ejecutado en su forma estándar, al igual que cualquier otra consulta de WordPress.

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

Limitando El Query

Siempre debemos especificar cuántos puestos nuestra consulta debe traer.

Para ello, utilizamos el parámetro ‘posts por página’.

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

Esto no es una buena práctica, incluso si estamos seguros de que vamos a obtener solamente pocos resultados como la respuesta.

Para uno, que rara vez puede ser cierto sólo obtener resultados de nuevo. E incluso si podemos establecer un límite requeriría el motor de base de datos para analizar toda la base de datos buscando coincidencias.

Por el contrario, limitando los resultados a menudo permite que el motor de base de datos analicé los datos sólo parcialmente, lo que se traduce en menos tiempo de procesamiento y una respuesta más rápida.

Otra cosa que hace WordPress por defecto es que puede repercutir negativamente en el rendimiento, ya que trata de traer puestos pegajosos y de calcular cuántas filas se encuentran en el query.

Sin embargo, realmente no necesitamos esa información muy a menudo. La adición de estos dos parámetros es desactivar estas características y acelerar nuestro query:

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

Excluyendo Los Posts Del Query

A veces queremos excluir determinados posts del query. WordPress ofrece una bonita forma directa de lograrlo: con el parámetro ‘post__no_en’. 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 mientras esto es bastante simple, no es óptimo porque genera internamente un subquery. Especialmente en las grandes instalaciones, esto puede conducir a una respuesta lenta. Es más rápido para permitir que el tratamiento sea realizado por el intérprete de PHP con algunas modificaciones sencillas:

$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 aquí?

Básicamente, quité algunos trabajos en el motor de base de datos y lo dejé en su lugar para el motor de PHP que hace las mismas cosas pero en la memoria, lo cual es mucho más rápido.

¿Cómo?

En primer lugar, he eliminado el ‘post__no_en” el parámetro del query.

Ya que el query puede traernos algunos puestos que no queremos como resultado, he aumentado el parámetro de “posts_por_página De esa manera puedo asegurar que, incluso si hubiera tenido algunos puestos no deseados en mi respuesta, me gustaría tener al menos ‘$posts_por_página deseado’ puestos allí.

Entonces, cuando busco los puestos y solo proceso aquellos que no están dentro de la matriz ‘$posts_para_excluir.’

Evitar La Parametrización Compleja

Todos estos métodos query ofrecen una amplia variedad de posibilidades para la obtención de puestos: por categorías, por meta claves o valores, por fecha, por autor, etc.

La flexibilidad es una característica muy eficaz, por lo que debe utilizarse con precaución ya que se podría traducir en la parametrización de combinaciones de tablas complejas y costosas operaciones de base de datos.

En la siguiente sección esbozaré de una manera elegante cómo lograr una funcionalidad similar sin comprometer el rendimiento.

Exprimiendo Al Máximo Las Opciones Wordpress.

Las opciones de WordPress WordPress API proporcionan una serie de herramientas para cargar fácilmente o guardar datos. Son útiles para el manejo de pequeñas piezas de información, ya que otros mecanismos que ofrece WordPress (como postes o taxonomías) son demasiado complejos.

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

WordPress no sólo nos da las funciones para su manejo pero también nos permite hacerlo de la manera más eficiente.

Algunas de las opciones son incluso cargar directamente cuando el sistema empieza proporcionando así un acceso más rápido (al crear una nueva opción, debemos considerar si queremos autoload o no).

Considera, por ejemplo, un sitio en el que tenemos un carrusel mostrando noticias especificado en el back-end. Nuestro primer instinto sería usar una meta clave como sigue:

// 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 puedes ver, este método es muy sencillo pero no es óptimo. Se realizará una consulta a la base de datos tratando de encontrar un post con una determinada tecla meta. Podríamos utilizar una opción para obtener 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 la primera parte del código, siempre vamos a obtener las últimas noticias, en términos de la fecha de publicación del post.

En la segunda, cada vez que un nuevo post se establece como noticia de última hora, se sobrescribirá sobre la noticia anterior.

Pero debido a que probablemente queramos una noticia de último momento por vez, esto no será problema.

Y al final hemos cambiado una pesada consulta de base de datos (utilizando ‘WP_QUERY’ con meta keys) en una consulta simple y directa (la llamada ‘obtén_post()’), que es un enfoque mejor y más eficiente.

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

Los transitorios funcionan de modo similar pero nos permiten especificar un tiempo de caducidad.

Por ejemplo, en el caso de las noticias que se adaptan a la perfección, porque no queremos un antiguo post como noticia de última hora y si dejamos la tarea de cambiar o eliminar esa noticia al administrador, [él] podría olvidarse de hacerlo. Así, con dos simples cambios, podemos añadir una fecha de caducidad:

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

Activar Un Caché Persistente

WordPress nativamente tiene un mecanismo de almacenamiento en caché objeto.

Las opciones, por ejemplo, se almacenan en la memoria caché mediante ese mecanismo.

Pero, por defecto, el caché no es persistente, es decir que sólo vive para la duración de una única solicitud. Todos los datos se guardan en la memoria caché, para que el acceso sea más rápido, pero sólo está disponible durante esa solicitud.

El caché persistente de apoyo requiere la instalación de un plugin de caché persistente.

Algunos plugins de caché de página completa vienen con un plugin de caché persistente incluido (por ejemplo el W3 Total Cache), pero otros no, y tenemos que instalarlo por separado.

Dependerá de la arquitectura de nuestra plataforma si vamos a usar archivos tal como el Memcache o algún otro mecanismo para almacenar datos en caché, debemos aprovechar esta característica sorprendente.

Podrías preguntarte: “Si esto es una gran característica de WordPress, ¿por qué no se habilita por defecto?”

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

Si queremos acoger en nuestro sitio un servidor distribuido, por ejemplo, debemos usar un sistema de caché externo (como un servidor Memcached), pero si nuestro sitio web reside en un único servidor, podríamos ahorrar dinero y simplemente usar el sistema de archivos de caché.

Una cosa que debemos tener en cuenta es la caducidad de la caché. Esta es la trampa más común de trabajar con caché persistente.

Si no abordamos este tema correctamente, nuestros usuarios se quejarán de que no podrán ver los cambios que han hecho o que sus cambios se tardaron demasiado en aplicar.

A veces nos vamos a encontrar haciendo equilibrio entre rendimiento y dinamismo, pero incluso con estos obstáculos, el almacenamiento en caché persistente es algo que virtualmente cada instalación de WordPress debe aprovechar.

AJAXing La Manera Más Rápida

Si necesitamos comunicar a través de AJAX con nuestro sitio web, WordPress ofrece cierta abstracción a la hora de tramitar la solicitud en el servidor.

Aunque estas técnicas puedan utilizarse con la programación de herramientas back-end o envíos de formularios desde el front-end, estas deben evitarse si no son estrictamente necesarias.

La razón de esto es que para poder utilizar esos mecanismos, estamos obligados a hacer una petición post a algún archivo ubicado dentro de la carpeta “wp-admin”. La mayoría (si no todos) de plugins de Wordpress de caché de página completa ni la caché de peticiones post ni llamadas al administrador de archivos.

Por ejemplo, si queremos más puestos de carga dinámica cuando el usuario se desplaza a nuestra homepage, sería mejor llamar directamente a alguna otra página de front-end, que recibirá los beneficios de ser almacenado en caché.

Entonces 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 el tiempo de respuesta.

Destruir La Noción De Que WordPress Es Lento

Estos son sólo algunos consejos que los desarrolladores deben tener en cuenta a la hora de codificar para WordPress.

A veces nos olvidamos de que nuestro plugin o tema que se necesite para vivir juntos con otros plugins, o que nuestro sitio web puede ser servido por una compañía de hosting que sirve a cientos o miles de otros sitios con una base de datos común.

Acabamos de centrarnos en la forma en que el plugin debe funcionar y no en cómo se trata con esa funcionalidad, o cómo hacerlo de una forma eficaz.

Debido a lo que expuse con anterioridad, es evidente que las causas del bajo rendimiento de WordPress son malas y de código ineficiente. Sin embargo, WordPress ofrece todas las funcionalidades necesarias a través de sus diversas API que pueden ayudarnos a construir muchos más plugins de desarrollo y temas sin comprometer la velocidad global de la plataforma.

About the author

Martín Di Felice, Argentina
member since January 17, 2016
Martin considers himself a full-stack developer who's currently working on back-end development projects. For the last 5 years, Martín has been working on WordPress sites including themes and plugins hosted at the WordPress VIP platform. He's looking for all sorts of projects as long as the work provides a challenge. [click to continue...]
Hiring? Meet the Top 10 Freelance WordPress Developers for Hire in August 2017

Comments

comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant Technologies
About the author
Martín Di Felice
JavaScript Developer
Martin considers himself a full-stack developer who's currently working on back-end development projects. For the last 5 years, Martín has been working on WordPress sites including themes and plugins hosted at the WordPress VIP platform. He's looking for all sorts of projects as long as the work provides a challenge.