WordPress es una potencia, pero sus valores predeterminados de “talla única” significan que a menudo viene con equipaje que la mayoría de los proyectos modernos no necesitan. A lo largo de los años, he refinado un conjunto específico de snippets para eliminar el exceso sin comprometer la experiencia central.
Esta guía no es simplemente una lista de cosas para eliminar; es un enfoque estratégico hacia el rendimiento. Está inspirada en la excelente lista de Terence Eden, que he combinado con mis propias soluciones probadas en producción. Cada nombre de hook que aparece abajo se ha comprobado contra el código fuente de WordPress 7.1.3 (la versión vigente el 12 de octubre de 2026, según la comprobación de versión de api.wordpress.org), y los snippets que resultaron obsoletos, erróneos o dañinos están marcados como tales. Si prefieres delegar el trabajo, consulta nuestros servicios de desarrollo WordPress.
Por qué aligerar WordPress
¿Por qué molestarse con estos pequeños scripts? Porque se acumulan. Cada línea innecesaria es un potencial conflicto, un pequeño retraso de renderizado o un byte desperdiciado.
Lo que buscamos reducir:
- Tamaño del DOM: eliminar estilos inline que no se usan.
- Sobrecarga HTTP: desencolar scripts que no deberían estar ahí.
- Superficie de seguridad: desactivar protocolos heredados como XML-RPC.
- Core Web Vitals: impacto directo en LCP y CLS al eliminar elementos que bloquean el renderizado.
[!IMPORTANT] Usa precaución: No toda “hinchazón” es inútil. Si dependes del estilo específico del editor clásico o de emojis integrados para navegadores antiguos, algunas de estas correcciones pueden no ser para ti. Prueba en staging primero.
Cómo usar un script completo para aligerar WordPress
Agrega lo siguiente al archivo functions.php de tu tema o, mejor aún, a un mu-plugin (consulta la última sección) para que el código sobreviva a un cambio de tema. Cada sección está comentada con explicaciones y enlaces a fuentes.
1. Eliminar estilos de tema clásico
WordPress añade “classic-theme-styles” a los temas que no tienen archivo theme.json. El núcleo solo lo encola cuando wp_theme_has_theme_json() devuelve false, así que un tema de bloques o un tema clásico con theme.json nunca lo carga. Si el tuyo lo carga, elimínalo:
// Eliminar tema clásico obligatorio.
function disable_classic_theme_styles() {
wp_deregister_style( "classic-theme-styles" );
wp_dequeue_style( "classic-theme-styles" );
}
add_action( "wp_enqueue_scripts", "disable_classic_theme_styles" );2. Eliminar soporte de emojis
WordPress imprime un pequeño script de detección y, solo cuando el navegador no puede mostrar emojis actuales, carga un script más grande que sustituye los caracteres emoji por imágenes SVG. Si tus visitantes usan navegadores actuales, esto es innecesario:
// Eliminar WP Emoji.
// https://www.denisbouquet.com/remove-wordpress-emoji-code/
remove_action( "wp_head", "print_emoji_detection_script", 7 );
remove_action( "wp_print_styles", "print_emoji_styles" );
remove_action( "admin_print_scripts", "print_emoji_detection_script" );
remove_action( "admin_print_styles", "print_emoji_styles" );
// Vaciar la URL base de SVG que se pasa a los ajustes de emoji.
add_filter( "emoji_svg_url", "__return_false" );
// Detener el reemplazo de emojis por imágenes en feeds RSS / Atom
// https://danq.me/2023/09/04/wordpress-stop-emoji-images/
remove_filter( "the_content_feed", "wp_staticize_emoji" );
remove_filter( "comment_text_rss", "wp_staticize_emoji" );3. Deshabilitar formato automático de texto
WordPress “texturiza” tu contenido: las comillas rectas pasan a tipográficas, y los ASCII -- / --- se convierten en caracteres de guion medio y raya (U+2013 / U+2014). Eso rompe ejemplos de código y choca con una política editorial de guion ASCII (- o --, sin glifos de raya en el origen). Desactívalo en contenido técnico:
// Eliminar formato automático.
// https://css-tricks.com/snippets/wordpress/disable-automatic-formatting/
remove_filter( "the_content", "wptexturize" );
remove_filter( "the_excerpt", "wptexturize" );
remove_filter( "comment_text", "wptexturize" );
remove_filter( "the_title", "wptexturize" );
// Más filtros de formato.
add_action("init", function() {
remove_filter( "the_content", "convert_smilies", 20 );
foreach ( array( "the_content", "the_title", "wp_title", "document_title" ) as $filter ) {
remove_filter( $filter, "capital_P_dangit", 11 );
}
remove_filter( "comment_text", "capital_P_dangit", 31 );
// SOLO para sitios con editor clásico: esta línea detiene todo el renderizado de bloques.
remove_filter( "the_content", "do_blocks", 9 );
}, 11);Nota: El filtro
capital_P_dangites la forma que tiene WordPress de autocorregirWordpress(con p minúscula) aWordPress. Es agresivo y a veces no se desea.
[!WARNING] Quitar
do_blocksdethe_contentsignifica que el marcado de bloques deja de interpretarse. Los bloques dinámicos (bucle de consulta, últimas entradas, navegación) no muestran nada. Conserva esa línea solo en un sitio cuyas entradas se hayan escrito todas con el editor clásico.
4. Eliminar estilos y scripts Gutenberg
Si usas un tema personalizado y no dependes de los estilos frontend de Gutenberg, elimínalos. En un tema de bloques no lo hagas: los estilos globales contienen todo el diseño definido en theme.json.
// Eliminar estilos Gutenberg.
// https://wordpress.org/support/topic/how-to-disable-inline-styling-style-idglobal-styles-inline-css/
remove_action( "wp_enqueue_scripts", "wp_enqueue_global_styles" );
// En temas clásicos el núcleo también lo engancha a wp_footer con prioridad 1.
remove_action( "wp_footer", "wp_enqueue_global_styles", 1 );
// Eliminar widgets de edición Gutenberg.
// De https://wordpress.org/plugins/classic-widgets/
// Impide que el editor de bloques gestione los widgets en el plugin Gutenberg.
add_filter( "gutenberg_use_widgets_block_editor", "__return_false" );
// Impide que el editor de bloques gestione los widgets.
add_filter( "use_widgets_block_editor", "__return_false" );
// Eliminar CSS de Block Library de Gutenberg del frontend.
// https://smartwp.com/remove-gutenberg-css/
function remove_wp_block_library_css() {
wp_dequeue_style( "wp-block-library" );
wp_dequeue_style( "wp-block-library-theme" );
}
add_action( "wp_enqueue_scripts", "remove_wp_block_library_css", 100 );5. Eliminar meta tags del header
Limpia tu sección <head> eliminando meta tags innecesarios:
// Eliminar shortlink.
// https://stackoverflow.com/questions/42444063/disable-wordpress-short-links
remove_action( "wp_head", "wp_shortlink_wp_head" );
// Eliminar RSD.
// https://wpengineer.com/1438/wordpress-header/
remove_action( "wp_head", "rsd_link" );
// Eliminar feed links extra.
// https://developer.wordpress.org/reference/functions/feed_links/
add_filter( "feed_links_show_comments_feed", "__return_false" );
add_filter( "feed_links_show_posts_feed", "__return_false" );
// Eliminar enlace api.w.org.
// https://wordpress.stackexchange.com/questions/211467/remove-json-api-links-in-header-html
remove_action( "wp_head", "rest_output_link_wp_head" );
// https://wordpress.stackexchange.com/questions/211817/how-to-remove-rest-api-link-in-http-headers
// https://developer.wordpress.org/reference/functions/rest_output_link_header/
remove_action( "template_redirect", "rest_output_link_header", 11, 0 );6. Eliminar mejoras de imagen
WordPress añade a las imágenes los atributos srcset, sizes, loading, decoding y fetchpriority. Si los gestionas tú mismo, elimínalos, pero lee antes la sección sobre imágenes más abajo, porque estos atributos protegen el LCP y el CLS:
// Eliminar tamaño de imagen forzado por WordPress
// https://core.trac.wordpress.org/ticket/62413#comment:40
add_filter( "wp_img_tag_add_auto_sizes", "__return_false" );
// Eliminar mejoras de <img>
// https://developer.wordpress.org/reference/functions/wp_filter_content_tags/
remove_filter( "the_content", "wp_filter_content_tags", 12 );
// Dejar de reescribir URLs http:// para el dominio principal.
// https://developer.wordpress.org/reference/hooks/wp_should_replace_insecure_home_url/
remove_filter( "the_content", "wp_replace_insecure_home_url", 10 );
// Eliminar lo relacionado con adjuntos
// https://developer.wordpress.org/news/2024/01/building-dynamic-block-based-attachment-templates-in-themes/
remove_filter( "the_content", "prepend_attachment" );
// Eliminar el filtro de bloques
remove_filter( "the_content", "apply_block_hooks_to_content_from_post_object", 8 );7. Eliminar verificación de navegador y otras funciones admin
// Eliminar verificación de navegador del dashboard de Admin.
// https://core.trac.wordpress.org/attachment/ticket/27626/disable-wp-check-browser-version.0.2.php
if ( !empty( $_SERVER["HTTP_USER_AGENT"] ) ) {
add_filter( "pre_site_transient_browser_" . md5( $_SERVER["HTTP_USER_AGENT"] ), "__return_null" );
}
// Eliminar hovercards en enlaces de comentarios en el área de administración.
// https://wordpress.org/support/topic/how-to-disable-mshots-service/#post-12946617
add_filter( "akismet_enable_mshots", "__return_false" );Qué más desactivar en WordPress
Más allá de las técnicas anteriores, aquí están mis propias soluciones para optimización adicional:
8. Deshabilitar XML-RPC
Si no usas apps externas para publicar en WordPress, desactiva los métodos XML-RPC que requieren inicio de sesión y, con ellos, los métodos de pingback. El filtro xmlrpc_enabled por sí solo no apaga el endpoint (detalles más abajo):
// Deshabilitar los métodos XML-RPC que requieren autenticación
add_filter( 'xmlrpc_enabled', '__return_false' );
// Eliminar los métodos de pingback, que de lo contrario siguen abiertos
add_filter( 'xmlrpc_methods', function( $methods ) {
unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
// Eliminar enlace XML-RPC del head
remove_action( 'wp_head', 'rsd_link' );9. Eliminar jQuery Migrate
Los temas y plugins modernos de WordPress raramente necesitan jQuery Migrate. Si tu sitio funciona sin él, elimínalo:
function remove_jquery_migrate( $scripts ) {
if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
$script = $scripts->registered['jquery'];
if ( $script->deps ) {
$script->deps = array_diff( $script->deps, array( 'jquery-migrate' ) );
}
}
}
add_action( 'wp_default_scripts', 'remove_jquery_migrate' );10. Deshabilitar oEmbed
Si ningún otro sitio necesita incrustar tus entradas, desactiva la parte de proveedor de oEmbed. Los vídeos de YouTube y de otros proveedores registrados que incrustes en tus propias entradas siguen funcionando, porque WordPress solo ejecuta el descubrimiento para URLs que no están en su lista interna de proveedores:
// Eliminar enlaces de descubrimiento oEmbed
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
// Eliminar endpoint REST API de oEmbed
remove_action( 'rest_api_init', 'wp_oembed_register_route' );
// Deshabilitar auto descubrimiento oEmbed
add_filter( 'embed_oembed_discover', '__return_false' );11. Diferir la carga de JavaScript
Agrega defer a scripts no críticos para mejor rendimiento. El filtro de abajo es el método antiguo e ignora las reglas de dependencias que el núcleo aplica desde WordPress 6.3; la sección sobre estrategias de carga, más abajo, muestra la forma admitida:
function add_defer_attribute( $tag, $handle ) {
// Scripts que NO deben diferirse
$scripts_to_not_defer = array( 'jquery-core' );
if ( in_array( $handle, $scripts_to_not_defer ) || str_contains( $tag, ' defer' ) ) {
return $tag;
}
return str_replace( ' src', ' defer src', $tag );
}
add_filter( 'script_loader_tag', 'add_defer_attribute', 10, 2 );Cómo medir el impacto de aligerar WordPress
Después de implementar estos cambios, prueba tu sitio usando:
- Google PageSpeed Insights: verifica tus Core Web Vitals
- GTmetrix: análisis detallado de cascada
- WebPageTest: múltiples ubicaciones de prueba y velocidades de conexión
Deberías ver:
- Peso de página reducido (menos bytes CSS/JS)
- Menos solicitudes HTTP
- Mejor Largest Contentful Paint (LCP) cuando un recurso eliminado bloqueaba el renderizado
El tiempo de respuesta del servidor (TTFB) apenas cambia, porque ninguno de estos snippets modifica la forma en que PHP construye la página. Lo que mueve el TTFB es una capa de caché.
Qué carga una instalación predeterminada de WordPress 7.1
Antes de quitar nada, conviene saber cuánto cuesta cada función. Los tamaños de abajo se midieron sobre los archivos del wordpress-7.1.3.zip oficial: bytes en bruto en disco y tamaño tras gzip con nivel 9, que se acerca a lo que un servidor envía por la red.
| Recurso | Archivo | En bruto | Gzip | Cuándo se carga |
|---|---|---|---|---|
| Cargador de emojis (inline, pie) | wp-emoji-loader.min.js | 2,977 B | 1,290 B | En todas las páginas del frontend |
| Script de reemplazo de emojis | wp-emoji-release.min.js | 22,752 B | 5,310 B | Solo cuando el navegador no supera la prueba de emojis |
| Estilos de tema clásico | classic-themes.min.css | 291 B | 233 B | Temas sin theme.json |
| Biblioteca de bloques combinada | block-library/style.min.css | 140,829 B | 18,938 B | Solo cuando la carga de estilos de bloque bajo demanda está desactivada |
| Estilos de tema de la biblioteca de bloques | block-library/theme.min.css | 2,752 B | 751 B | Temas que declaran wp-block-styles, con la carga bajo demanda desactivada |
| jQuery | jquery.min.js | 87,553 B | 30,356 B | Cuando el tema o un plugin lo encola |
| jQuery Migrate | jquery-migrate.min.js | 13,577 B | 4,891 B | Junto con el handle jquery |
| Dashicons | dashicons.min.css | 59,004 B | 35,693 B | Barra de administración para usuarios conectados, o un plugin |
| Script anfitrión de entradas incrustadas | wp-embed.min.js | 1,251 B | 710 B | Solo en páginas que incrustan una entrada de WordPress |
| Heartbeat | heartbeat.min.js | 5,947 B | 2,058 B | Pantallas de administración; en el frontend solo si lo pide un plugin |
| Respuesta a comentarios | comment-reply.min.js | 2,950 B | 1,371 B | Cuando el tema o el bloque Comentarios lo encola |
Dos cifras destacan. jQuery más Migrate es lo más pesado que suele cargar un tema clásico, así que eliminar jQuery del código de tu propio tema ahorra más que todos los ajustes de etiquetas del head juntos. Y la hoja de 140 KB de la biblioteca de bloques ya no se carga entera en una instalación predeterminada: los temas de bloques cargan solo los estilos de los bloques presentes en la página desde WordPress 5.9, y desde la 6.9 el núcleo activa esa misma carga bajo demanda para los temas clásicos mediante wp_load_classic_theme_block_styles_on_demand(), siempre que el búfer de salida de plantillas esté activo. Un tema puede desactivarlo devolviendo false en los filtros should_load_separate_core_block_assets y should_load_block_assets_on_demand.
Para ver lo que carga realmente una página concreta, usa el navegador. En Chrome DevTools abre la pestaña Network, recarga con la caché desactivada, filtra por tu propio dominio y ordena por tamaño. Lighthouse, en el mismo panel de DevTools, enumera el CSS y el JavaScript sin usar por archivo. WP-CLI no sirve aquí: una llamada a wp eval nunca renderiza una plantilla, así que las colas de scripts y estilos que muestra están vacías. Lo que sí funciona es un hook en el pie que registre los datos:
// Registrar cada handle encolado en las páginas del frontend (solo en staging).
add_action( 'wp_footer', function () {
if ( is_admin() ) {
return;
}
foreach ( wp_scripts()->queue as $handle ) {
error_log( 'script: ' . $handle . ' ' . wp_scripts()->registered[ $handle ]->src );
}
foreach ( wp_styles()->queue as $handle ) {
error_log( 'style: ' . $handle . ' ' . wp_styles()->registered[ $handle ]->src );
}
}, 999 );Qué funciones de WordPress desactivar, una por una
El script anterior es la versión rápida. A continuación, cada función recibe el contexto necesario para decidir si tiene sitio en tu web.
Qué son los estilos de tema clásico y cuánto pesan
WordPress 6.1 añadió una pequeña hoja de estilos que da a los temas clásicos valores razonables para el marcado de bloques, como el espaciado de los bloques de botón y de archivo. Pesa 291 bytes y la encola wp_enqueue_classic_theme_styles() solo cuando el tema activo no tiene theme.json. Elimínala en un tema clásico que tenga su propio CSS de bloques. Déjala en los temas clásicos que confían en que el marcado de bloques del núcleo se vea bien sin trabajo extra, y no te preocupes por ella en los temas de bloques, donde nunca se carga.
Por qué WordPress carga un script de emojis
La función de emojis hace dos trabajos: comprueba si el navegador puede dibujar emojis recientes y, si no puede, carga wp-emoji-release.min.js para sustituir los caracteres por imágenes de s.w.org. En WordPress 7.1.3 la prueba es un script inline type="module" impreso en el pie, así que ya no bloquea el renderizado, y los resultados se guardan en sessionStorage. Lo acompaña una pequeña hoja de estilos inline para img.emoji. Quitar la acción wp_print_styles sigue funcionando: wp_enqueue_emoji_styles() comprueba esa acción y omite el CSS inline cuando ya no está.
El filtro emoji_svg_url ahora solo fija la URL base de los SVG en los ajustes de emoji. Las guías antiguas lo usaban para quitar un DNS prefetch a s.w.org; wp_resource_hints() en la 7.1.3 ya no añade esa sugerencia, así que la línea es inofensiva pero ya no ahorra ninguna consulta. Mantén el soporte de emojis si hay visitantes que escriben en comentarios o foros desde dispositivos antiguos cuyas fuentes no incluyen emojis recientes. La versión completa cubre también el correo electrónico y el editor clásico:
function disable_emojis_completely() {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
remove_action( 'embed_head', 'print_emoji_detection_script' );
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
add_filter( 'tiny_mce_plugins', function ( $plugins ) {
return array_diff( $plugins, array( 'wpemoji' ) );
} );
}
add_action( 'init', 'disable_emojis_completely' );Qué cambia wptexturize en tu contenido
wptexturize() convierte las comillas rectas en tipográficas, -- y --- en guion medio y raya, y tres puntos en un carácter de puntos suspensivos. En contenido técnico corrompe shortcodes y fragmentos de HTML y PHP que los lectores copian. Toda la función se puede desactivar con un solo filtro en lugar de quitarla de cada hook:
add_filter( 'run_wptexturize', '__return_false' );Consérvala solo en sitios editoriales que quieran comillas tipográficas y nunca publiquen código.
Qué hace el filtro capital_P_dangit
capital_P_dangit() sustituye Wordpress por WordPress. En los títulos reemplaza todas las apariciones; en el contenido y los comentarios, solo después de un espacio, unas comillas, > o (. No toca las URLs, porque una barra delante de la palabra no coincide con el patrón. El riesgo real está en el código: un ejemplo que contenga Wordpress después de un espacio se modifica sin avisar.
Qué estilos y scripts añade el editor de bloques
En el frontend, el editor de bloques aporta wp-block-library (el CSS de los bloques), wp-block-library-theme (estilos de tema con criterio propio) y el global-styles inline generado a partir de theme.json. wp-components pertenece a las pantallas del editor, así que desencolarlo en el frontend no hace nada. Los snippets antiguos también quitan wp_global_styles_render_svg_filters de wp_body_open; esa función quedó obsoleta en la 6.3.0 y ya no está enganchada. Elimina el CSS de bloques solo en sitios que no rendericen bloques en el frontend. En un tema de bloques, quitar los estilos globales elimina el diseño del tema.
Qué etiquetas añade WordPress al head y cuáles quitar
Un wp_head predeterminado en la 7.1.3 imprime, entre otras:
<meta name="generator" content="WordPress 7.1.3" />
<link rel="shortlink" href="https://example.com/?p=123" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://example.com/xmlrpc.php?rsd" />
<link rel="https://api.w.org/" href="https://example.com/wp-json/" />
<link rel="alternate" type="application/json" href="https://example.com/wp-json/wp/v2/posts/123" />| Etiqueta | Riesgo | Recomendación |
|---|---|---|
| generator | Bajo, la versión también aparece como ?ver= en los recursos del núcleo | Quítala si quieres, oculta poco |
| shortlink | Ninguno | Quitar |
| RSD (EditURI) | Dirige a los clientes a xmlrpc.php | Quitar junto con XML-RPC |
| Enlaces de la REST API | Bajo | Mantener si algo descubre tu API |
Dos eliminaciones que todavía aparecen en muchas guías no hacen nada en las versiones actuales: wlwmanifest_link quedó obsoleto en la 6.3.0 y ya no se imprime, y el núcleo no usa adjacent_posts_rel_link_wp_head desde la 5.6.0. Una limpieza actual es más corta:
add_action( 'init', function () {
remove_action( 'wp_head', 'wp_generator' );
remove_action( 'wp_head', 'wp_shortlink_wp_head' );
remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
remove_action( 'wp_head', 'rsd_link' );
} );Qué añade WordPress a las imágenes
wp_filter_content_tags() añade srcset y sizes, width y height cuando faltan, loading="lazy" en las imágenes por debajo del pliegue, decoding="async" y fetchpriority="high" en la imagen que probablemente sea el LCP. El filtro wp_img_tag_add_auto_sizes llegó en la 6.7.0, no antes. Eliminar estas funciones suele empeorar el CLS y el LCP, justo lo contrario de lo que se busca, así que hazlo solo cuando una CDN o tu propio marcado los establezca todos. Para desactivar solo la carga diferida:
add_filter( 'wp_lazy_loading_enabled', '__return_false' );Cómo funciona la comprobación del navegador en el escritorio
wp_check_browser_version() pregunta a api.wordpress.org si el navegador del administrador está desactualizado y guarda la respuesta como transient de sitio durante una semana, con una clave basada en un MD5 del user agent. Es una petición remota por navegador y semana, no una por cada vista de página del administrador. La comprobación de la versión de PHP funciona igual, pero la clave del transient es php_check_ más un MD5 de PHP_VERSION, no del user agent, así que los snippets que filtran pre_site_transient_phpcompat_ no hacen nada:
add_filter( 'pre_site_transient_php_check_' . md5( PHP_VERSION ), '__return_null' );Mantén esa comprobación salvo que otra persona vigile la versión de PHP, porque es el aviso que indica a los propietarios del sitio que su PHP ya no tiene soporte.
Qué desactiva de verdad el filtro xmlrpc_enabled
XML-RPC es el protocolo de publicación remota que usan los clientes móviles antiguos, los editores de escritorio y los pingbacks. El nombre del filtro sugiere un interruptor general, pero el código fuente de WordPress 7.1.3 dice otra cosa en el docblock de wp_xmlrpc_server::set_is_enabled():
“Contrariamente a lo que sugiere su nombre, este filtro no controla si XML-RPC está habilitado por completo, sino solo si están habilitados los métodos de XML-RPC que requieren autenticación, como los que sirven para publicar.”
WordPress 7.1.3, docblock de
wp_xmlrpc_server::set_is_enabled()en class-wp-xmlrpc-server.php (traducción propia)
Así que, después de add_filter( 'xmlrpc_enabled', '__return_false' ), xmlrpc.php sigue respondiendo y pingback.ping sigue funcionando. Los pingbacks son la parte de la que se abusa para generar tráfico reflejado, y system.multicall permite que una sola petición lleve muchos intentos de inicio de sesión, cosa que el filtro sí detiene porque esos métodos requieren autenticación. El snippet de la sección 8 también elimina los métodos de pingback mediante xmlrpc_methods. La cabecera HTTP X-Pingback solo se envía en entradas individuales que admiten pings, así que cerrar los pings (secciones siguientes) también la elimina. Para quitar el endpoint por completo, bloquea xmlrpc.php en el servidor web; después revisa cualquier plugin o app que publique de forma remota, porque dejará de funcionar.
Para qué sirve jQuery Migrate
jQuery Migrate restaura las APIs de jQuery que se eliminaron en versiones posteriores y registra avisos cuando el código antiguo las llama. WordPress registra el handle jquery como alias de jquery-core más jquery-migrate, y por eso el snippet de la sección 9 edita la lista de dependencias en lugar de desencolar un archivo. Antes de quitarlo en producción, carga el sitio en staging con define( 'SCRIPT_DEBUG', true );, que hace que WordPress sirva el jquery-migrate.js sin minificar que el núcleo conserva para depuración, y busca en la consola los avisos JQMIGRATE sobre llamadas obsoletas. No llames a wp_deregister_script( 'jquery-migrate' ) en el frontend; cualquier plugin que declare jquery-migrate como dependencia perdería entonces su propio script, porque WordPress no imprime un script cuya dependencia falta.
Cómo funciona oEmbed en WordPress
oEmbed tiene dos caras. Como consumidor, WordPress convierte un enlace pegado de YouTube o Vimeo en un reproductor usando su lista interna de proveedores; eso sigue funcionando después del snippet de la sección 10. Como proveedor, tu sitio imprime enlaces de descubrimiento y sirve /wp-json/oembed/1.0/embed para que otros sitios WordPress puedan incrustar tus entradas. El script wp-embed (710 bytes con gzip) solo se encola en páginas que contienen una entrada incrustada de ese tipo. Hay dos líneas del código antiguo para “desactivar embeds” que no conviene copiar: quitar wp_filter_oembed_result de oembed_dataparse desactiva el saneamiento que el núcleo aplica al HTML de proveedores que no están en la lista de confianza, y el plugin wpembed de TinyMCE ya no existe, así que filtrarlo de tiny_mce_plugins no hace nada.
Cómo restringir la REST API sin romper el editor de bloques
La REST API responde en /wp-json/ y es lo que usan el editor de bloques, el editor del sitio y muchos plugins. El manual oficial de la REST API es explícito en sus preguntas frecuentes:
“No deberías desactivar la REST API; hacerlo romperá las funciones de la administración de WordPress que dependen de que la API esté activa.”
WordPress REST API Handbook, Frequently Asked Questions (traducción propia)
Lo que propone el manual a cambio es exigir autenticación mediante el filtro rest_authentication_errors. Los editores con sesión iniciada siguen trabajando y las peticiones anónimas reciben un 401:
add_filter( 'rest_authentication_errors', function( $result ) {
// Si ya se aplicó una comprobación de autenticación previa,
// devolver ese resultado sin modificarlo.
if ( true === $result || is_wp_error( $result ) ) {
return $result;
}
// Todavía no se ha realizado ninguna autenticación.
// Devolver un error si el usuario no ha iniciado sesión.
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_not_logged_in',
__( 'You are not currently logged in.' ),
array( 'status' => 401 )
);
}
// Nuestra comprobación de autenticación personalizada no debe afectar
// a las peticiones con sesión iniciada
return $result;
});Esto rompe todas las funciones del frontend que llaman a /wp-json/ para visitantes anónimos: formularios que se envían a través de REST, widgets de búsqueda o filtrado que obtienen JSON, un frontend headless y otros sitios que incrustan tus entradas a través del endpoint de oEmbed. Una opción más acotada es ocultar rutas concretas con el filtro rest_endpoints, por ejemplo el endpoint de usuarios que enumera los slugs de los autores. Después del cambio, prueba todos los formularios y bloques interactivos sin haber iniciado sesión.
Cómo ajustar la Heartbeat API de WordPress
Heartbeat es un bucle de sondeo en heartbeat.js que envía una petición a admin-ajax.php a intervalos fijos. Se encarga del bloqueo de entradas (el aviso de que otra persona está editando), de los datos de autoguardado en el editor clásico y de la comprobación de caducidad de sesión que muestra el diálogo para volver a iniciar sesión. En WordPress 7.1.3 el mainInterval predeterminado es de 60 segundos, el rango permitido va de 1 a 3,600 segundos, el bucle puede acelerarse temporalmente hasta 5 segundos y se ralentiza a 120 segundos cuando la pestaña está oculta. Por tanto, fijar el intervalo en 60 no cambia nada; un intervalo más lento es el ajuste útil con equipos de administración numerosos o con un alojamiento débil:
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 120;
return $settings;
} );En el frontend, el núcleo no carga Heartbeat para los visitantes; solo aparece cuando un plugin lo encola. Quitar su registro ahí es seguro si después compruebas la función de ese plugin. Nunca lo hagas en la administración: los bloqueos de entradas y los avisos de caducidad de sesión dependen de él.
Cómo limitar las revisiones con WP_POST_REVISIONS
Las revisiones no ralentizan el frontend, porque nunca se consultan en las páginas públicas. Hacen crecer la tabla wp_posts y ralentizan las copias de seguridad y las exportaciones. El control es una constante en wp-config.php, que lee wp_revisions_to_keep():
define( 'WP_POST_REVISIONS', 10 ); // conservar las 10 revisiones más recientes por entrada
// define( 'WP_POST_REVISIONS', false ); // ninguna revisiónEl valor predeterminado es true, que significa ilimitadas. false o 0 desactiva las revisiones; un número positivo conserva esa cantidad. El filtro wp_revisions_to_keep tiene prioridad sobre la constante y, desde WordPress 5.8, el filtro wp_{$post_type}_revisions_to_keep fija un límite por tipo de contenido. El límite se aplica la próxima vez que se guarda una entrada, así que las revisiones sobrantes existentes se mantienen hasta entonces. Desactivar las revisiones quita la red de seguridad a los editores, por lo que un número pequeño suele ser mejor compromiso.
El autoguardado tiene su propia constante. En el núcleo no existe ningún filtro autosave_interval, así que el código que lo añade no hace nada; fija el intervalo en segundos en wp-config.php:
define( 'AUTOSAVE_INTERVAL', 120 ); // el valor predeterminado es 60Cómo desactivar los comentarios en todo el sitio
Un sitio sin comentarios sigue mostrando formularios de comentarios donde el tema los pide, mantiene el enlace al feed de comentarios en el head y conserva el mecanismo de pingbacks. Cerrar comentarios y pings mediante filtros cubre todos los tipos de contenido sin editar entradas en la base de datos:
add_filter( 'comments_open', '__return_false', 20, 2 );
add_filter( 'pings_open', '__return_false', 20, 2 );
add_filter( 'feed_links_show_comments_feed', '__return_false' );
add_action( 'admin_menu', function () {
remove_menu_page( 'edit-comments.php' );
} );
add_action( 'init', function () {
remove_post_type_support( 'post', 'comments' );
remove_post_type_support( 'page', 'comments' );
} );Cerrar los pings también elimina la cabecera X-Pingback, ya que el núcleo solo la envía cuando pings_open() es verdadero. Los comentarios existentes siguen en la base de datos y pueden seguir mostrándose si el tema los imprime sin tener en cuenta comments_open(). El script comment-reply no merece un trabajo aparte: el núcleo lo registra con la estrategia async y baja prioridad de descarga, y ocupa 1,371 bytes con gzip.
Cómo diferir scripts con la API de estrategias de carga
Desde WordPress 6.3, wp_register_script() y wp_enqueue_script() aceptan un argumento strategy con los valores defer o async. Después, el núcleo revisa el árbol de dependencias antes de imprimir el atributo: un script con un script inline adjunto en la posición after nunca se retrasa, y un script defer vuelve a ser bloqueante cuando un script dependiente necesita que se ejecute antes. Esa lógica está en WP_Scripts::get_eligible_loading_strategy(). El filtro script_loader_tag de la sección 11 se salta todo esto, y así es como los scripts diferidos acaban ejecutándose después del código inline que los llama.
// Tu propio script.
wp_enqueue_script( 'site-main', get_theme_file_uri( 'js/main.js' ), array(), '1.4.0', array(
'in_footer' => true,
'strategy' => 'defer',
) );
// Un script registrado por un plugin.
add_action( 'wp_enqueue_scripts', function () {
wp_script_add_data( 'some-plugin-handle', 'strategy', 'defer' );
}, 20 );Revisa después el código fuente de la página: si el núcleo decidió que un handle no puede diferirse, el atributo simplemente no aparece.
Cómo probar el rendimiento de WordPress antes y después de aligerarlo
Una sola ejecución de PageSpeed Insights no es una medición, porque las puntuaciones de laboratorio varían entre ejecuciones. Un procedimiento que da cifras comparables:
- Preparación: vacía la caché de página, usa el mismo alojamiento y el mismo conjunto de URLs en ambas rondas, y anota las versiones de WordPress, del tema y de los plugins.
- Línea base: ejecuta PageSpeed Insights o Lighthouse tres veces por URL y quédate con la mediana; después anota los bytes transferidos y el número de peticiones desde la pestaña Network de DevTools con la caché desactivada.
- Despliega el código de aligeramiento en staging y vuelve a vaciar la caché.
- Repite las mismas ejecuciones sobre las mismas URLs.
- Compara bytes transferidos, número de peticiones, LCP y CLS. Los datos de campo de la sección Chrome UX Report de PageSpeed Insights se actualizan a lo largo de 28 días, así que vuelve a comprobarlos un mes después.
La tabla de tamaños de arriba te da el límite superior. En un tema clásico que ya carga los estilos de bloque bajo demanda, quitar los emojis, los estilos de tema clásico y las etiquetas del head ahorra unos pocos kilobytes y algunas líneas de HTML; las cifras grandes están en jQuery y en los recursos de los plugins.
Cómo comprobar la compatibilidad después de aligerar WordPress
Después de cada cambio, revisa tres áreas:
- Frontend: el diseño, los menús, los sliders y los formularios, y la consola del navegador en busca de errores de JavaScript.
- Administración: el editor de entradas, la biblioteca de medios, la pantalla de widgets y cada página de ajustes de plugin que uses.
- Sin sesión iniciada: formularios de contacto, comentarios si los mantienes, la búsqueda y todo lo que cargue datos sin recargar la página.
Activa el registro de errores mientras pruebas y deja la visualización desactivada para que los visitantes no vean avisos:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );| Problema | Causa probable | Solución |
|---|---|---|
| Errores de jQuery en la consola | Se eliminó jQuery Migrate | Restaura Migrate o actualiza el plugin que llama a APIs obsoletas |
| Los bloques aparecen sin estilos | Se eliminaron la biblioteca de bloques o los estilos globales | Restaura los estilos en las páginas con contenido de bloques |
| El bucle de consulta o la navegación no muestran nada | Se quitó do_blocks de the_content | Elimina esa línea |
| Los formularios fallan sin sesión iniciada | REST API limitada a usuarios conectados | Permite la ruta del plugin o quita la restricción |
| Falla la app móvil o el publicador remoto | XML-RPC bloqueado | Vuelve a activarlo o pasa el cliente a contraseñas de aplicación y REST |
| Se rompen las incrustaciones de tus entradas en otros sitios | Se quitó la parte de proveedor de oEmbed | Es lo esperado; restáurala si tus socios la necesitan |
Cómo empaquetar el código de aligeramiento como mu-plugin
El código de functions.php desaparece cuando cambia el tema. Un plugin de uso obligatorio en wp-content/mu-plugins/ se carga en cada petición, no se puede desactivar desde la administración y mantiene los ajustes de aligeramiento independientes del tema. WordPress carga los archivos PHP colocados directamente en esa carpeta, no los de subcarpetas, así que mantén un único archivo o añade un pequeño cargador:
wp-content/
mu-plugins/
debloat-loader.php
debloat/
emoji.php
head-cleanup.php
xmlrpc.php
heartbeat.php<?php
/**
* Plugin Name: Debloat
* Description: Removes front-end features this site does not use.
*/
defined( 'ABSPATH' ) || exit;
foreach ( array( 'emoji', 'head-cleanup', 'xmlrpc', 'heartbeat' ) as $module ) {
$file = __DIR__ . '/debloat/' . $module . '.php';
if ( is_readable( $file ) ) {
require_once $file;
}
}Cada módulo contiene los snippets de las secciones anteriores. Deja dos cosas fuera de un plugin de aligeramiento. Desactivar las actualizaciones automáticas de plugins y temas con auto_update_plugin y auto_update_theme es una política de mantenimiento, no un ajuste de rendimiento, y desactiva las versiones de seguridad junto con las de nuevas funciones. Y los límites de revisiones y autoguardado son constantes, así que su sitio es wp-config.php, no un plugin que se carga después de que esas constantes se hayan leído.
Resumen
El enfoque de WordPress de “baterías incluidas” es genial para principiantes, pero los desarrolladores que buscan máximo rendimiento necesitan podar el exceso. Las técnicas en esta guía, inspiradas en el excelente script de debloating de Terence Eden, te ayudarán a lograr una instalación WordPress más ligera y rápida.
Varios snippets clásicos ya no hacen nada en WordPress 7.1 (el manifiesto WLW, los enlaces a entradas adyacentes, los filtros SVG, el filtro autosave_interval), y algunos causan daños (quitar do_blocks, quitar el saneamiento de oEmbed, bloquear la REST API por completo). Cada línea de código que eliminas es un punto de fallo potencial menos, así que comprueba cada snippet contra la versión que usas antes de llevarlo a producción.
Si quieres ir más allá, consulta nuestros servicios de optimización de velocidad WordPress.







