Jose J. Fernández Programador. Desarrollador web y SEO en León

Optimizar el header de nuestra web en WordPress

Jose J. Fernández

WordPress

Sabemos que uno de los factores que está tomando relevancia en el posicionamiento web es el tiempo de carga de un sitio, y también sabemos que cuanta menos información exponga un sistema, mayor seguridad tendrá éste.

Desde ambos puntos de vista, limpiar el cabecero de las páginas generadas mediante WordPress y reducirlo al mínimo es una buena idea.

Hoy vamos a ver cómo hacerlo y también veremos la diferencia entre un cabecero optimizado y un cabecero no demasiado optimizado, aunque los haya peores.

Cabecero de WordPress optimizado

Para el ejemplo de cabecero optimizado elegí el cabecero de mi blog :) que podéis ver aquí:

<!DOCTYPE html>
<html lang="es-ES">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		
		<title>Jose J. Fernández | Desarrollo, posicionamiento web y nuevas tecnologías</title>
		<link rel="pingback" href="http://josejfernandez.com/xmlrpc.php">
		
		<link href="http://josejfernandez.com/wp-content/themes/josejfernandez/css/bootstrap.min.css" rel="stylesheet">
		<link href="http://josejfernandez.com/wp-content/themes/josejfernandez/css/responsive.css" rel="stylesheet">
		<link href="http://josejfernandez.com/wp-content/themes/josejfernandez/css/style.css" rel="stylesheet">
		<!--[if lt IE 9]>
			<script src="http://josejfernandez.com/wp-content/themes/josejfernandez/js/html5shiv.js"></script>
			<script src="http://josejfernandez.com/wp-content/themes/josejfernandez/js/respond.min.js"></script>
		<![endif]-->
		
	</head>

A tener en cuenta que en el pie de página de mi blog se carga más JavaScript y CSS, como jQuery, Google Analytics, el JavaScript de Bootstrap y el de la barra de administración de WordPress, pero eso sucede cuando la web ya está cargada, no antes.

Hay varias cosas que se podrían mejorar, como por ejemplo elegir una build de Bootstrap ajustada a lo que utilizo y bajar peso de la hoja de estilos y del JavaScript del footer, pero como no lo necesito por ahora puedo ahorrármelo, que la web ya es muy ligera :D

Cabecero de WordPress NO optimizado

Como ejemplo de cabecero no demasiado optimizado he puesto el de otro blog. Como es un ejemplo de mal ejemplo, borro datos identificativos ;) y en realidad hay que pensar que no es el peor cabecero que hay, ya que existen otros muchísimo peores que éste. Igualmente, nos sirve de ejemplo para lo que queremos.

<!DOCTYPE html>
<html lang="es-ES">
<head>
<meta charset="UTF-8" />

<meta name="viewport" content="width=device-width, initial-scale=1" />

<!-- This site is optimized with the Yoast WordPress SEO plugin v1.5.2.6 - https://yoast.com/wordpress/plugins/seo/ -->
<title>x</title>
<meta name="robots" content="noydir"/>
<meta name="description" content="x"/>
<link rel="canonical" href="WEBSITE/" />
<link rel="publisher" href="x"/>
<!-- / Yoast WordPress SEO plugin. -->


            <script type="text/javascript">//<![CDATA[
            // Google Analytics for WordPress by Yoast v4.3.5 | http://yoast.com/wordpress/google-analytics/
            var _gaq = _gaq || [];
            _gaq.push(['_setAccount', 'x']);
				            _gaq.push(['_trackPageview']);
            (function () {
                var ga = document.createElement('script');
                ga.type = 'text/javascript';
                ga.async = true;
                ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

                var s = document.getElementsByTagName('script')[0];
                s.parentNode.insertBefore(ga, s);
            })();
            //]]></script>
			<!-- This site is powered by Shareaholic - https://shareaholic.com -->
<script type='text/javascript' data-cfasync='false'>
  //<![CDATA[
    (function() {
      var shr = document.createElement('script');
      shr.setAttribute('data-cfasync', 'false');
      shr.src = '//dsms0mj1bbhn4.cloudfront.net/assets/pub/shareaholic.js';
      shr.type = 'text/javascript'; shr.async = 'true';
      shr.onload = shr.onreadystatechange = function() {
        var rs = this.readyState;
        if (rs && rs != 'complete' && rs != 'loaded') return;
        var site_id = 'x';
        var page_config = {};
        try { Shareaholic.init(site_id, page_config); } catch (e) {}
      };
      var s = document.getElementsByTagName('script')[0];
      s.parentNode.insertBefore(shr, s);
    })();
  //]]>
</script>

<!-- Shareaholic Content Tags -->
<meta name='shareaholic:site_name' content='x' />
<meta name='shareaholic:language' content='es-ES' />
<meta name='shareaholic:site_id' content='x' />
<meta name='shareaholic:wp_version' content='7.3.0.0' />

<!-- Shareaholic Content Tags End -->
<link rel='stylesheet' id='metro-pro-theme-css'  href='WEBSITE/wp-content/themes/metro-pro/style.css?ver=2.0.0' type='text/css' media='all' />
<link rel='stylesheet' id='contact-form-7-css'  href='WEBSITE/wp-content/plugins/contact-form-7/includes/css/styles.css?ver=3.7.2' type='text/css' media='all' />
<link rel='stylesheet' id='cookielawinfo-style-css'  href='WEBSITE/wp-content/plugins/cookie-law-info/css/cli-style.css?ver=3.8.1' type='text/css' media='all' />
<link rel='stylesheet' id='wp-v-icons-css-css'  href='WEBSITE/wp-content/plugins/wp-visual-icon-fonts/css/wpvi-fa4.css?ver=3.8.1' type='text/css' media='all' />
<link rel='stylesheet' id='google-font-css'  href='//fonts.googleapis.com/css?family=Oswald%3A400&ver=2.0.0' type='text/css' media='all' />
<link rel='stylesheet' id='simple-social-icons-font-css'  href='WEBSITE/wp-content/plugins/simple-social-icons/css/style.css?ver=1.0.5' type='text/css' media='all' />
<script type='text/javascript' src='WEBSITE/wp-includes/js/jquery/jquery.js?ver=1.10.2'></script>
<script type='text/javascript' src='WEBSITE/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1'></script>
<script type='text/javascript' src='WEBSITE/wp-content/plugins/cookie-law-info/js/jquery.cookie.js?ver=3.8.1'></script>
<script type='text/javascript' src='WEBSITE/wp-content/plugins/cookie-law-info/js/cookielawinfo.js?ver=3.8.1'></script>
<script type='text/javascript' src='WEBSITE/wp-content/plugins/magic-action-box/assets/js/actionbox-helper.js?ver=3.8.1'></script>
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="WEBSITE/xmlrpc.php?rsd" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="WEBSITE/wp-includes/wlwmanifest.xml" /> 
<meta name="generator" content="WordPress 3.8.1" />
<style type="text/css"> .enews .screenread { display:none; } </style><link rel="Shortcut Icon" href="WEBSITE/wp-content/themes/metro-pro/images/favicon.ico" type="image/x-icon" />
<link rel="pingback" href="WEBSITE/xmlrpc.php" />
<style type="text/css">.site-title a { background: url(WEBSITE/wp-content/uploads/2014/03/x.jpg) no-repeat !important; }</style>
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<style type="text/css" media="screen"> .simple-social-icons ul li a, .simple-social-icons ul li a:hover { background-color: #f9f3f2 !important; border-radius: 3px; color: #db5741 !important; font-size: 18px; padding: 9px; }  .simple-social-icons ul li a:hover { background-color: #db5741 !important; color: #ffffff !important; }</style></head>

¿Se nota la diferencia? Y eso que los hay infinitamente peores. Veamos los puntos a mejorar:

  • Me indica que está utilizando WordPress 3.8.1. La última en estos momentos, pero esperemos que cuando salga alguna vulnerabilidad crítica actualice rápido, porque sabiendo la versión será inusitadamente sencillo encontrar algún agujero reportado y documentado y acribillar ese WordPress
  • Me indica que está utilizando el tema Metro Pro, que le costó $99 y que utiliza el Genesis Framework.
  • Me indica que está utilizando el plugin SEO de Yoast, el Shareaholic, el Cookie Law, el Contact Form 7 y alguno otro, junto además (grave) a sus versiones. Podría buscar vulnerabilidades de cada uno de ellos. Más puntos de entrada para ataques.
  • Multitud de elementos innecesarios en el cabecero, como EditURI, WLW Manifest, toneladas de JavaScript minimizable, mogollón de CSS que puede utilizarse o no…

Seguro que puedes encontrar webs con versiones antiguas de WordPress mediante un crawler muy sencillo de programar y buscar vulnerabilidades documentadas por Internet para esas versiones… Si no expusieras esa información no estaría tan a huevo automatizar ataques contra tu blog (recuerda, los ataques son automatizados).

Ah, y si eliminas la versión de WordPress del cabecero, no olvides tampoco borrar el readme.html del directorio donde instalaste WordPress, y del RSS, y de los scripts… ;)

El cabecero pesado y repleto de CSS y JS tiene también el problema añadido de que aumenta el tiempo de carga de la web, y eso como venimos diciendo afecta negativamente al posicionamiento.

Por todos esos motivos interesa reducirlo lo más posible. ¿Quieres saber cómo hacerlo?

Cómo optimizar WordPress para generar cabeceros limpios

Hay un tema de WordPress que hace un excelente trabajo a la hora de limpiar y optimizar varios aspectos del CMS y que casi nadie tiene en cuenta: WP-Bones. Muchas cosas de Bones son mejorables, pero en general es un excelente punto de partida para desarrollar en WordPress como debe ser.

Bones incluye un montón de funciones para optimizar WordPress y por defecto deja el cabecero prácticamente como el de mi blog. Hay varios aspectos que he modificado a partir del buen trabajo realizado en Bones, pero en principio con lo que éste último ofrece es suficiente en la mayoría de casos.

Aquí te dejo algunas de las funciones que utilizo en mi blog. Provienen como digo de Bones pero han sido modificadas en algunos casos por mi. Debes incluirlas en el fichero functions.php de tu tema.

/**
 * Header cleanup
 */
function theme_cleanup() {
	remove_action('wp_head', 'wp_generator');
	remove_action('wp_head', 'feed_links', 2);
	remove_action('wp_head', 'feed_links_extra', 3);
	remove_action('wp_head', 'rsd_link');
	remove_action('wp_head', 'wlwmanifest_link');
	remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0);
	remove_action('wp_head', 'index_rel_link');
	remove_action('wp_head', 'parent_post_rel_link', 10, 0);
	remove_action('wp_head', 'start_post_rel_link', 10, 0);
	remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0);
}
add_action('after_setup_theme', 'theme_cleanup', 16);
/**
 * Removes WordPress version from scripts
 */
function theme_remove_version_code($src) {
	if (strpos($src, 'ver=') !== false) {
		$src = remove_query_arg('ver', $src);
	}
	return $src;
}
add_filter('style_loader_src', 'theme_remove_version_code', 99);
add_filter('script_loader_src', 'theme_remove_version_code', 99);
/**
 * Removes WordPress version from RSS
 */
function theme_rss_version() {
	return '';
}
add_filter('the_generator', 'theme_rss_version');
/**
 * Removes injected CSS from recent comments widget
 */
function theme_remove_wp_widget_recent_comments_style() {
	if (has_filter('wp_head', 'wp_widget_recent_comments_style')) {
		remove_filter('wp_head', 'wp_widget_recent_comments_style');
	}
}
add_filter('wp_head', 'theme_remove_wp_widget_recent_comments_style', 1);
/**
 * Removes injected CSS from gallery
 */
function theme_gallery_style($css) {
	return preg_replace("!!s", '', $css);
}
add_filter('gallery_style', 'theme_gallery_style');

¿Serías capaz de encontrar la versión de WordPress en algún sitio en mi blog? ;)

Mi tema de base tiene unas cuantas modificaciones más que iré publicando próximamente. ¡Manténte alerta!

Minipunk 2014-04-08 - 18:20

Mucho código jajaja por poner la puntilla comentar que te faltaría meter los metadatos de la web, que irían ahí.
Y si quisieramos meter los dinámicos de twitter o facebook también irian en esta cabecera y el humans.txt tan de moda ;)

Jose J. Fernández 2014-04-08 - 19:47

Pues el humans.txt ya existe, pero dudo que lo veamos por la cabecera. Lo de los metatags ya he pasado de ponerlos directamente. En teoría sirve, pero quiero demostrarlo poniéndolos cuando tenga algo de tráfico desde buscadores a ver en qué cambia ;)

Lo de Facebook y Twitter, ¿cuáles son? ¿El OpenGraph de Facebook, dices? Está pendiente, sí :O

saul ramirez 2015-03-09 - 21:03

Hola un excelente tema, debo felicitarte me ilustraste bastante ya entiendo un poco mejor lo que afectaba el tiempo de carga de mi sitio y a los riesgo que me exponía mostrando mi versión de wordpress, tengo una duda como eliminarias el mensaje que deja el plugin SEO de Yoast? es bastante molesto y dice muchos detalles que no me gustaría mostrar. Muchas gracias saludos

Jose J. Fernández 2015-03-09 - 22:06

Hola Saúl.

Me imagino que te refieres al comentario donde indica “This site is powered by YOAST 1.2.3” o algo así, ¿verdad? Para hacerlo bastaría con modificar los ficheros del plugin donde lo imprime. He analizado por encima el código del plugin y está muy bien organizado. Creo recordar que tiene un apartado de plantillas donde se imprime dicho mensaje…

Sí, sé que me dirás que cuando actualices el plugin eso se perderá, pues entonces deberás hacerlo con hooks/filtros :)

El plugin de YOAST estará metiendo ese mensaje en la función wp_head() con un hook (el hook wp_head, de hecho). Entonces tú tienes que enganchar una función en ese mismo hook después de que YOAST escriba el cabecero, y reemplazar el mensaje de la versión por una cadena de caracteres vacía. Para ello, yo utilizaría preg_replace(). La función debería ir en functions.php, y sería algo así:

add_filter('wp_head', function($header) {
	// Tu función que reemplaza el mensaje de versión de YOAST
}, 999);

Dejo la implementación de tu mano, aunque es un buen ejercicio para aprender sobre el tema, quizá realice un tutorial/guía al respecto próximamente :)

saul ramirez 2015-03-10 - 14:20

Muchas gracias, ya tengo una idea mas clara donde empezar :D ese plugin es muy bueno pero esos comentarios en el head es mi única queja muchas gracias por tus consejos. Suerte :)

Luis 2015-05-11 - 20:30

Hola Jose, excelente post, era justo lo que andaba buscando. Acabo de colgar mi web y al ir a echar un vistazo al head me he encontrado que es peor que el que tu muestras y al buscar como limpiarlo he acabado en tu blog.
Como trabajo con un childtheme he creado el archivo functions.php allí (limpio) y he insertado los códigos que pones… y no me ha funcionado. ¿Deberia ponerlo en el original a riesgo de perderlo con las actualizaciones de tema?.
Muchas Gracias. Un saludo.

Jose J. Fernández 2015-05-13 - 18:28

Buenas Luis.

¿Qué es lo que no te ha funcionado? Puede que el theme que utilizas -o los plugins- estén insertando ellos por otro lado más cosas. Además, el functions.php del child theme se ejecuta antes que el del tema padre, por lo que el tema padre -o los plugins- puede volver a añadir lo que tú has eliminado en el tema hijo.

Una solución podría ser modificar la prioridad de los filtros y acciones que se añaden, échale un ojo a la documentación de add_filter().

Si te fijas, el tercer parámetro corresponde con la prioridad, siendo que una número menor se ejecuta antes (prioridad 1 se ejecutaría antes que prioridad 2). Esto es así tanto en add_filter() como en add_action().

Te interesa que el código que comparto en el artículo se ejecute después que el functions del tema padre, por lo que si utilizas un número elevado como prioridad para las acciones/filtros, tu función se ejecutará más tarde, sobreescribiendo lo que pueda añadir el theme original, o algunos plugins.

Se ejecutarán después si indicas una prioridad mayor aunque el functions.php del tema hijo cargue antes, ya que lo que importa para definir el orden de ejecución es la prioridad, no cuándo se añadió la acción o el filtro. Vamos, que en lugar de esto:

add_filter('wp_head', 'theme_remove_wp_widget_recent_comments_style', 1);

Puedes probar con esto:

add_filter('wp_head', 'theme_remove_wp_widget_recent_comments_style', 9999);

Si haciendo eso aún sigues teniendo un cabecero muy pesado, pienso que puede deberse a que tienes otros plugins instalados que siguen añadiendo sus cosas. Piensa que la optimización que publico no reduce en absoluto lo que añade el plugin SEO de Yoast, por ejemplo, entre otros muchos. Sólo optimiza un WordPress por defecto ;)

Por cierto, si tu web es la que has indicado al comentar, he echado un ojo al cabecero y veo que ya has optimizado un poco el código (no aparecen muchas cosas que por defecto en WordPress sí salen). Temo que todo lo demás que ves lo inserta tu theme y algún plugin que estás utilizando.

Espero que te haya sido de utilidad. Cualquier cosa, comenta por aquí.
Un saludo.

Luis 2015-05-21 - 10:45

Hola Jose, gracias por tu respuesta y por haber echado un ojo al head de la web. No entiendo mucho de programación y lo de add_action y add_filter me viene un poco grande. He estado viendo otros head, de otros blogs que se suponen que lo tienen optimizado, y veo que le salen muchas cosas parecidas a las mías y creo, que como bien dices, los plugins que tengo instalados y mi theme introducen mucho código en la cabecera.

Si lo tengo un poco optimizado es gracias a tu código que lo puse en el functions. ;)

¡Gracias de nuevo por tu interés!

Un saludo.

Ikichpan 2015-07-08 - 21:10

Super tu post, ya agregue todo a mi functions, pero aun me aparece la super lista de todos los js y css que jalan los plugins. Se que igual sea otro tema pero como puedo hacer para que me los cargue al final?

Muchas gracias y felicidades

Javi 2016-07-08 - 11:30

Buenos días, estoy haciendo una web con varios idiomas con el Tema Bridge y el plugin qTranslate para traducir. El problema es que al hacer clic en el idioma, el contenido se recarga y se traduce, pero se ve que el tema tiene algo para que el header no se actualice, y por tanto el menú no se traduce. Tienes alguna idea de como puedo solucionar eso? Un saludo, Javier.

No se mostrará públicamente.

Un enlace a tu blog o página web.