Aligerar WordPress: 11 correcciones que uso para eliminar la hinchazón

Aligerar WordPress: 11 correcciones que uso para eliminar la hinchazón

Última verificación: 12 de octubre de 2026
28 min de lectura
Guía
500+ proyectos WP

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_dangit es la forma que tiene WordPress de autocorregir Wordpress (con p minúscula) a WordPress. Es agresivo y a veces no se desea.

[!WARNING] Quitar do_blocks de the_content significa 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:

  1. Google PageSpeed Insights: verifica tus Core Web Vitals
  2. GTmetrix: análisis detallado de cascada
  3. 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.

RecursoArchivoEn brutoGzipCuándo se carga
Cargador de emojis (inline, pie)wp-emoji-loader.min.js2,977 B1,290 BEn todas las páginas del frontend
Script de reemplazo de emojiswp-emoji-release.min.js22,752 B5,310 BSolo cuando el navegador no supera la prueba de emojis
Estilos de tema clásicoclassic-themes.min.css291 B233 BTemas sin theme.json
Biblioteca de bloques combinadablock-library/style.min.css140,829 B18,938 BSolo cuando la carga de estilos de bloque bajo demanda está desactivada
Estilos de tema de la biblioteca de bloquesblock-library/theme.min.css2,752 B751 BTemas que declaran wp-block-styles, con la carga bajo demanda desactivada
jQueryjquery.min.js87,553 B30,356 BCuando el tema o un plugin lo encola
jQuery Migratejquery-migrate.min.js13,577 B4,891 BJunto con el handle jquery
Dashiconsdashicons.min.css59,004 B35,693 BBarra de administración para usuarios conectados, o un plugin
Script anfitrión de entradas incrustadaswp-embed.min.js1,251 B710 BSolo en páginas que incrustan una entrada de WordPress
Heartbeatheartbeat.min.js5,947 B2,058 BPantallas de administración; en el frontend solo si lo pide un plugin
Respuesta a comentarioscomment-reply.min.js2,950 B1,371 BCuando 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" />
EtiquetaRiesgoRecomendación
generatorBajo, la versión también aparece como ?ver= en los recursos del núcleoQuítala si quieres, oculta poco
shortlinkNingunoQuitar
RSD (EditURI)Dirige a los clientes a xmlrpc.phpQuitar junto con XML-RPC
Enlaces de la REST APIBajoMantener 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ón

El 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 60

#Có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:

  1. 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.
  2. 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.
  3. Despliega el código de aligeramiento en staging y vuelve a vaciar la caché.
  4. Repite las mismas ejecuciones sobre las mismas URLs.
  5. 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:

  1. Frontend: el diseño, los menús, los sliders y los formularios, y la consola del navegador en busca de errores de JavaScript.
  2. Administración: el editor de entradas, la biblioteca de medios, la pantalla de widgets y cada página de ajustes de plugin que uses.
  3. 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 );
ProblemaCausa probableSolución
Errores de jQuery en la consolaSe eliminó jQuery MigrateRestaura Migrate o actualiza el plugin que llama a APIs obsoletas
Los bloques aparecen sin estilosSe eliminaron la biblioteca de bloques o los estilos globalesRestaura los estilos en las páginas con contenido de bloques
El bucle de consulta o la navegación no muestran nadaSe quitó do_blocks de the_contentElimina esa línea
Los formularios fallan sin sesión iniciadaREST API limitada a usuarios conectadosPermite la ruta del plugin o quita la restricción
Falla la app móvil o el publicador remotoXML-RPC bloqueadoVuelve a activarlo o pasa el cliente a contraseñas de aplicación y REST
Se rompen las incrustaciones de tus entradas en otros sitiosSe quitó la parte de proveedor de oEmbedEs 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.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Quieres implementar esto en tu sitio?

Si quieres transformar el artículo en mejoras concretas, rediseño o un plan de implementación, puedo cerrar el alcance y ejecutar.

Cluster relacionado

Explora otros servicios WordPress y base de conocimiento

Refuerza tu negocio con soporte técnico profesional en áreas clave del ecosistema WordPress.

Preguntas frecuentes

Respuestas prácticas para aplicar el tema en la ejecución real.

¿Es seguro eliminar los scripts de emoji de WordPress?#
Sí, en navegadores actuales. En WordPress 7.1.3 cada página carga un cargador en línea de 2,977 bytes en el pie; el script de sustitución de 22,752 bytes solo se descarga cuando el navegador no supera la prueba de emoji. Quitarlo ahorra poco, y en dispositivos antiguos los emoji recientes pueden verse como cuadros vacíos.
¿Qué pasa si elimino los estilos Gutenberg y algo se rompe?#
Si tu tema no usa bloques Gutenberg en el frontend, es seguro eliminar los estilos. Si usas un tema de bloques (FSE), NO elimines estos estilos. Siempre prueba en un entorno staging primero.
¿Por qué debería deshabilitar XML-RPC?#
XML-RPC es un protocolo legacy usado por la app móvil de WordPress y Jetpack. También es el vector número 1 para ataques de fuerza bruta. A menos que necesites específicamente la app móvil, deshabilitarlo reduce la carga del servidor y mejora la seguridad.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados