Una de las fortalezas que tiene WordPress son los plugins, una de las maneras más sencillas de ampliar o extender las funcionalidades que tiene el propio WordPress para adaptarlo a nuestro proyecto y hacerlo más potente y competitivo, ya que existen miles de ellos disponibles, sólo en el repositorio oficial más de 54.000, y con múltiples características. ¡Vivan los plugins!
Pero los plugins no son sólo alegrías, siempre que cumplan su función para la que fueron diseñados, también tienen un problema importante, y es que siempre están activos, es decir, nuestro sistema WordPress siempre realiza la carga de todos los plugins activos en la instalación en cada llamada a la misma, lo que puede generar un problema de rendimiento en nuestro servidor si en esa llamada concreta, algún plugin no es necesario. ¡No vivan los plugins! Tampoco es eso, que vivan, pero cuando nosotros decidamos. Este es el concepto de la carga condicional: gestionar qué plugins cargar.
Índice de contenidos
Qué es la carga condicional de plugins
A modo de definición básica, la carga condicional de plugins es otra estrategia WPO por la cual decidimos si es necesario cargar un plugin o no, en función de ciertos factores que nosotros decidamos:
- Qué URL se está llamando.
- Quién realiza la llamada.
- En qué momento.
- En qué entorno.
- …..e incluso, combinaciones de varios factores.
En resumen, tener un control total sobre la carga de los plugins activos en todo momento.
Ejemplo: Carga condicional de formularios
Un ejemplo sencillo y habitual lo encontramos en los plugins de creación de formularios, que normalmente utilizamos en nuestras páginas de contacto, es decir, en una sola página de todo nuestro sitio, pero que es cargado en todas y cada una de las URL aunque no se necesite de dicho formulario.
Normalmente se puede apreciar en el front-end por que incluye una llamada a un fichero JS y un fichero CSS propios del plugin, aunque también consume carga en el servidor, en el back-end, que es donde queremos incidir todavía más con esta estrategia, no cargando plugins no necesarios.
En este caso tendríamos una mejora apreciable incluso en el front-end, aunque también veremos ejemplos incluso más sencillos, para no cargar plugins que sólo son necesarios en el administrador de WordPress.
Esta estrategia es complementaria a todas vuestras actuales estrategias de WPO que ya estés utilizando en tus proyectos con WordPress, como caché, HTTP/2, carga diferida, compresión, y un largo etcétera; y como te decía, tiene un objetivo doble: reducir el tiempo de carga en el servidor al no cargar ciertos plugins si no son necesarios, mejorando el TTFB y por tanto el tiempo de carga global, y reducir el tiempo de carga en el cliente, al no requerir la llamada de ciertos recursos que no se vayan a utilizar en la página, de nuevo menor tiempo de carga global y mejor UX. Y como toda buena estrategia de WPO, por ende, reducir los recursos necesarios en nuestro servidor.
Todo esto está muy bien y ahora seguro que te estás preguntando cómo se llama el maravilloso plugin que hace todo esto o donde está el código que habitualmente Fernando Tellado te prepara con cariño para que pegues de una manera sencilla.
Lamento deciros que este no es el caso. Al tratarse de una técnica «a medida» de cada proyecto, es necesario entenderla y desarrollarla a medida, debemos crear las condiciones programáticas para cada caso concreto que deseemos controlar, aunque observareis muy pronto que los patrones se repiten en casi todos los proyectos y podéis reutilizar mucho del código que habéis generado. Recordad, no hay dos proyectos iguales pero sí muchas partes recurrentes.
Pero tranquilo, que voy a ponerte unos cuantos ejemplos de uso sencillos para despertar tu cabeza de «optimizador de proyecto» y que seguramente podrás implementar por similitud en todos tus sitios.
Lo primero explicar cómo se aplica esta técnica, que es un concepto muy sencillo y que se basa en estos dos pilares:
- El filtro
option_active_plugins
, que nos permite controlar qué plugins se cargarán de entre todos los activos. La idea es decirle a WordPress que plugins se van a cargar, como si entráramos en cada petición en el administrador y desactivásemos momentáneamente uno o varios plugins. - Un MU-Plugin, que es donde colocaremos nuestro código, ya que estos se ejecutan antes que los plugins activos, permitiéndonos un control total sobre ellos.
Y dos notas antes de empezar con los ejemplos:
- Es una técnica MUY peligrosa, es necesario conocer en detalle el sitio y el funcionamiento de los plugins.
- Utilizar normalmente sólo para el front-end, ya que en el back-end los plugins aparecerían desactivados o pueden provocar errores.
Vamos al lío. Empezamos con la estructura básica de nuestro MU-Plugin, que será de este estilo, muy sencillo, con la llamada del filtro option_active_plugins
a nuestra función ayudawp_option_active_plugins
donde modificaremos el array de plugins activos ($plugin_list
), quedando tal que así:
<?php // Ejecutar el filtro solo para front-end if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //Aqui irán las condiciones //Y aquí devolvemos a WordPress el listado de plugins que queremos cargar return $plugin_list; } ?>
Ahora vamos con un ejemplo para entender cómo WordPress tiene referenciados los plugins internamente, que es la manera que utilizaremos para quitarlos del array.
Como podrás ver por el resultado de la ejecución, los plugins están referenciados por el nombre del directorio y el nombre del archivo PHP que lo ejecuta:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //Mostrar el listado de plugins print_r($plugin_list); exit; //No continuar con la ejecución } ?>
Nota: no utilizar el ejemplo anterior en un entorno de producción, ya que sólo ejecuta esa función y generará error al usuario.
Basándonos en el mismo concepto y en el primer ejemplo que pusimos, cómo haríamos la carga condicional del plugin Contact Form 7 sólo en la página donde tenemos nuestro formulario de contacto:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ $request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //Miramos cuando es necesario el plugin por la URL $is_cf7_needed = ($request_uri === '/contacto/' || strpos( $request_uri, '/wp-json/contact-form-7/v1/contact-forms/') !== false); //Lo quitamos cuando no es necesario if (!$is_cf7_needed) unset( $plugin_list[array_search( 'contact-form-7/wp-contact-form-7.php', $plugin_list)]); return $plugin_list; } ?>
Nota: la única complejidad es manejar las dos URL que necesita el plugin, la de la página donde lo hemos incrustado, normalmente mediante un shortcode, y la que necesita el plugin internamente para recoger los datos.
Ahora un ejemplo de uso para plugins que sabemos que sólo se ejecutan en el back-end, como Classic Editor o Duplicate Post, y que no necesitamos de su carga en el front-end:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //No cargar en el front-end los plugins que son sólo de uso en el back-end unset( $plugin_list[array_search( 'broken-link-checker/broken-link-checker.php', $plugin_list)]); unset( $plugin_list[array_search( 'classic-editor/classic-editor.php', $plugin_list)]); unset( $plugin_list[array_search( 'duplicate-post/duplicate-post.php', $plugin_list)]); unset( $plugin_list[array_search( 'updraftplus/updraftplus.php', $plugin_list)]); unset( $plugin_list[array_search( 'wp-smushit/wp-smush.php', $plugin_list)]); return $plugin_list; } ?>
Otro ejemplo de uso donde podemos implementar esta estrategia de carga condicional de plugins es cuando estamos utilizando un entorno de desarrollo, donde necesitamos menos plugins o no son necesarios y queremos ahorrarnos tiempo, y uno de producción, sin necesidad de realizar cambios, compartiendo el código:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //Carga condicional de plugins por entorno de ejecución if( $_SERVER['HTTP_HOST'] === 'localhost' ) { $plugins_to_disable = array( 'updraftplus/updraftplus.php', 'wordpress-seo/wp-seo.php', 'wp-smushit/wp-smush.php', 'wps-hide-login/wps-hide-login.php'); $plugin_list = array_diff( $plugin_list, $plugins_to_disable ); } return $plugin_list; } ?>
También podemos aplicar una condición programática de carga para usuarios conectados, por ejemplo no cargando el plugin habitual de condiciones legales para ese caso concreto:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //Carga condicional de plugin para usuarios conectados require (ABSPATH . WPINC . '/pluggable.php'); //Para usuarios logados if ( is_user_logged_in() ) unset( $plugin_list[array_search( 'cookie-law-info/cookie-law-info.php', $plugin_list)]); return $plugin_list; } ?>
Y por último, dos trucos que te van a encantar y que te permitirán medir de una manera muy sencilla la velocidad de carga, que se que te encanta, de tu web sin plugins o sin un plugin concreto, sin necesidad de modificar tu instalación ni molestar al usuario.
Para el primer caso:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //Uso: medir el impacto de una URL sin ningún plugin activo //http://example.com/url-2-test/?sinplugins if(isset($_GET['sinplugins'])) return array(); else return $plugin_list; } ?>
Y si quiero medirlo sólo sin un plugin concreto, tan sencillo como esto:
<?php if(!is_admin()) add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1); function ayudawp_option_active_plugins ( $plugin_list ){ //Uso: medir el impacto de una URL sin un plugin concreto (según el índice del listado de activos) //http://example.com/url-2-test/?sinplugins=1 if(isset($_GET['sinplugins'])) unset( $plugin_list[$_GET['sinplugins']] ); return $plugin_list; } ?>
¡Una maravilla para medir el impacto de los plugins de una manera rápida!
Fácil, ¿no? Ahora sólo tienes que empezar a combinar y aplicar esta técnica en base a los ejemplos que aquí he recogido y las particularidades que tenga tu proyecto.
Espero que esta técnica te haya despertado las ganas de optimizar todavía más vuestros proyectos.
¡Quiero más!
¿Ganas de más? En breve, si el responsable de esta web me lo permite, avanzaremos con nuevos ejemplos sobre la base de esta estrategia para mejorar todavía más la carga, por ejemplo, dentro del administrador de WordPress o aplicar test A/B de plugins o cargar plugins sin necesidad de activarlos en el back-end o en las integraciones con otros servicios.
Nos vemos o nos leemos.
¿Te gustó este artículo? ¡Ni te imaginas lo que te estás perdiendo en YouTube!
Bravo. Ovación cerrada puesto en pie. Muchas gracias por compartirlo, Fernando. Echaba en falta una versión escrita de tu charla en Zaragoza y ya soy feliz 🙂
Estoy de acuerdo contigo, Pablo. Yo vi la charla en Internet y me faltaba ver el código para entender mejor lo que explicaba Fernando.
Gracias por compartirlo 🙂
Hola Fernando,
Hace un tiempo usé en una instalación de WordPress un plugin que hacía esta función, pero confieso que nunca aprendí a llevar a cabo las configuraciones necesarias para tal fin. Ahora ni recuerdo como se llamaba ese plugin…
muy bueno, muchas gracias
Excelente entrada Fernando, muy útil y potente.
Ya lo comentamos por twitter, pero magnífico el post (y la charla), Fernando.
Solo una ligera sugerencia que igual solo tiene sentido si eres un cazurro como yo. Añadiría una comprobación de que el plugin está en la lista antes de hacer el unset con el array_search.
¿Por qué? En mi caso, un plugin que no estaba instalado ya pero yo tenía el unset plantado me estaba provocando que se desactivara akismet, que era el primero de la lista. Array_search devolvía un false, el unset lo interpretaba como 0… y ya te imaginas el resto jajaja.
También podría pasar lo mismo si enlazas varios if y la url cumple varios casos. Se quita un plugin en una y al intentar quitarse otra vez… se lleva el primer plugin por delante.
1 día me he tirado buscando el fallo. Igual solo me pasa a mi por manazas pero… ahí lo dejo.
Gracias de nuevo por el post, ahora me tiene enganchadísimo esto 😉
Nos vemos en la #WCMAD!
Excelente! Me gustaría saber cual es la expresión necesaria si queremos que en lugar de una página específica como indica en el ejemplo sean todas las demás paginas menos esa.
<?php
if(!is_admin())
add_filter( 'option_active_plugins', 'ayudawp_option_active_plugins', 1);
function ayudawp_option_active_plugins ( $plugin_list ){
$request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
//Miramos cuando es necesario el plugin por la URL
$is_cf7_needed = ($request_uri === ‘/contacto/’ || strpos( $request_uri, ‘/wp-json/contact-form-7/v1/contact-forms/’) !== false);
//Lo quitamos cuando no es necesario
if (!$is_cf7_needed)
unset( $plugin_list[array_search( ‘contact-form-7/wp-contact-form-7.php’, $plugin_list)]);
return $plugin_list;
}
?>
Hola Frenando y si necesitamos que funcione los formularios en dos o mas paginas, ejemplo pagina /contacto/ y /suscribirte/, ¿es posible?
Contact Form 7 sólo en la página donde tenemos nuestro formulario de contacto:
saludos, Luis
buen trabajo como siempre
Hola, excelente aporte!, pero tengo una duda 🙁
Supongamos que tengo dos plugins de avisos, pero me cargan en la web en el orden incorrecto, quiero que primero cargue en la web un plugin de aviso1, y que luego aparezca el otro aviso2, pero me aparece siempre el aviso2 en primer lugar, ¿qué puedo hacer en este caso?, gracias y saluduos!