Dev.to WebDev 🛠 Dev 👁 0 📖 8 min read

Core Web Vitals en WordPress: el orden para arreglar LCP, INP y CLS

Un WordPress lento casi nunca es “WordPress”. Es un tema con constructor, cuatro plugins haciendo lo mismo y una imagen hero que el navegador descubre tarde. Los Core Web Vitals —LCP, INP y CLS— sirven para ver eso con n

Un WordPress lento casi nunca es “WordPress”. Es un tema con constructor, cuatro plugins haciendo lo mismo y una imagen hero que el navegador descubre tarde. Los Core Web Vitals —LCP, INP y CLS— sirven para ver eso con números de usuarios reales, no con una corrida de Lighthouse en la notebook.

Los umbrales de “bueno”, en el percentil 75 de Chrome UX Report:

Métrica Qué mira Bueno
LCP Cuándo aparece el bloque más grande (imagen o texto) ≤ 2,5 s
INP Cuánto tarda la página en responder a un click, tap o tecla ≤ 200 ms
CLS Cuánto se mueve el layout mientras carga ≤ 0,1

Search Console usa una ventana de unos 28 días. Un cambio que en el laboratorio baja el LCP de 4 s a 1,5 s no pone el informe en verde ese mismo día.

Medí el campo y después el laboratorio

PageSpeed Insights muestra las dos capas. Arriba, datos de campo (CrUX): lo que les pasa a tus usuarios en móvil y en escritorio, por separado. Abajo, el laboratorio: una simulación de esa URL, útil para encontrar la causa, mala como score para celebrar.

Si el campo dice “sin datos”, el sitio no tiene tráfico suficiente. Ahí el laboratorio es lo único que hay. Tratá igual el móvil como el caso que importa: es el que suele fallar.

En el laboratorio, abrí el desglose de LCP. Viene en cuatro tramos:

  1. TTFB. El servidor tarda en responder.
  2. Demora de carga del recurso. El navegador ya tiene HTML y todavía no pide la imagen o la fuente que va a ser el LCP.
  3. Duración de carga. El archivo es pesado o la conexión es lenta.
  4. Demora de render. El archivo ya llegó y algo (CSS, fuente, JavaScript) impide pintarlo.

Ese desglose decide el orden. Optimizar imágenes cuando el TTFB es 1,8 s no mueve el LCP.

Para saber qué plugin mete cada script, Query Monitor en un entorno de prueba alcanza. En el navegador, la waterfall y el panel de cobertura muestran CSS y JS que se descargan y casi no se ejecutan.

Si el sitio ya está en producción y el informe de Search Console viene en rojo, conviene cerrar ese diagnóstico antes de tocar el tema. Es el trabajo de una auditoría de SEO técnico y rendimiento: Core Web Vitals, arquitectura y lo que de verdad está bloqueando el render.

Si el TTFB es el problema, el tema puede esperar

Un TTFB alto en WordPress suele ser PHP trabajando en cada request: muchos plugins en init, consultas sin caché y ningún page cache.

El orden que sí mueve el número:

  • PHP actual (8.2 o superior) y opcache activo.
  • Caché de página completa para las URLs anónimas. El HTML no tiene por qué generarse en cada visita.
  • Object cache (Redis) cuando hay WooCommerce, membresías o mucho WP_Query.
  • Menos plugins en cada request. Un plugin de seguridad, uno de formularios y uno de SEO. No tres optimizadores de imágenes pisándose.

Un plugin de caché no arregla un DOM de 3 MB ni un constructor que imprime 40 hojas de CSS. Guarda el resultado del TTFB y seguí con el recurso del LCP.

LCP: que el navegador pida la imagen correcta, temprano

En la mayoría de los sitios el elemento LCP es la imagen principal. WordPress, desde la 6.3, marca con fetchpriority="high" la imagen grande del contenido y pone loading="lazy" en el resto. Eso se rompe en cuatro casos muy comunes.

La imagen es un fondo CSS. El navegador la descubre cuando ya parseó el CSS. El hero tiene que ser un <img> (o <picture>), no un background-image.

Un plugin pone loading="lazy" en todas las imágenes. La que es LCP no se pide hasta que el layout la considera cercana al viewport. Tarde.

El hero es un slider. Se descargan tres fotos y el LCP es la que queda visible, o ninguna, porque el texto del slide entra por JavaScript. La primera vista alcanza con una imagen estática.

La imagen no tiene tamaño. Sin width y height el navegador reserva mal el espacio y, de paso, varios optimizadores dejan de tratarla como candidata a LCP.

La marca del hero, en una plantilla o en un bloque propio:

<img
  src="https://ejemplo.com/wp-content/uploads/hero.avif"
  alt="Equipo en el local, sobre la calle"
  width="1600"
  height="900"
  fetchpriority="high"
  decoding="async"
>

Sin loading="lazy". Formato AVIF o WebP, y un solo plugin de imágenes: dos optimizadores generan variantes distintas y a veces sirven el JPEG original.

sizes tiene que reflejar el tamaño real en pantalla. Una imagen de 1600 px que en el móvil se muestra a 400 px y se baja completa alarga el tramo de duración sin mejorar nada.

Fuentes: una sola, el mismo archivo

El otro candidato a LCP es un título con una webfont. Si el texto espera la fuente, el LCP se corre. Si la fuente entra tarde y cambia de métrica, sube el CLS.

En un block theme, theme.json (WordPress 6.5+) declara la cara y el font-display:

{
  "settings": {
    "typography": {
      "fontFamilies": [
        {
          "fontFamily": "\"Source Sans 3\", sans-serif",
          "slug": "body",
          "fontFace": [
            {
              "fontFamily": "Source Sans 3",
              "fontWeight": "400 700",
              "fontStyle": "normal",
              "fontDisplay": "swap",
              "src": ["file:./assets/fonts/source-sans-3-latin.woff2"]
            }
          ]
        }
      ]
    }
  }
}

Preload de esa misma woff2, no de otra ruta y no de cuatro pesos:

add_action('wp_head', function () {
    if (is_admin()) {
        return;
    }

    $href = get_theme_file_uri('assets/fonts/source-sans-3-latin.woff2');
    printf(
        '<link rel="preload" href="%s" as="font" type="font/woff2" crossorigin>' . "\n",
        esc_url($href)
    );
}, 1);

swap evita el texto invisible. Para que no empuje el layout, la fallback del sistema tiene que parecerse en ancho (size-adjust, ascent-override) o el título tiene que usar un peso que ya está en ese único archivo. Precargar la itálica “por si acaso” compite con la imagen del hero.

Google Fonts en un <link> externo suma una conexión y un CSS que bloquea. Self-host del archivo que realmente usa la página es más corto de explicar y más fácil de medir.

INP: menos JavaScript en el hilo principal

INP mira la peor interacción, no el promedio. En WordPress el tiempo se va en tres lugares.

El constructor. Elementor, Divi, WPBakery y compañía envían su runtime en todas las páginas, aunque el diseño sea estático. Cada módulo registra handlers. Un tap en el menú espera a que ese JS termine.

Plugins que escuchan todo el documento. Sliders, popups, galerías lightbox, contadores de shares. Muchos dependen de jQuery y se encolan en el header.

Terceros. Chat, pixel de ads, heatmaps, un embed de mapa. No son tu tema, y cuentan igual para INP.

Los scripts propios, con la estrategia de carga de WordPress 6.3+:

wp_enqueue_script(
    'site-extras',
    get_theme_file_uri('assets/extras.js'),
    array(),
    null,
    array(
        'strategy'  => 'defer',
        'in_footer' => true,
    )
);

defer mantiene el orden y saca el script del parser. No lo uses en algo que el primer render necesita.

El chat y los píxeles pueden esperar a la primera interacción:

function loadChat() {
  var s = document.createElement('script');
  s.src = 'https://ejemplo-chat.test/widget.js';
  s.async = true;
  document.body.appendChild(s);
}

window.addEventListener('pointerdown', loadChat, { once: true });

Sacar wp-block-library a ciegas no es una optimización. Si la página usa bloques, se rompe el CSS. Lo que sí se puede quitar es el CSS de un plugin en las plantillas donde ese plugin no aparece (wp_dequeue_style condicionado a la plantilla, no global).

CLS: reservar el lugar antes de que llegue el contenido

CLS en WordPress suele ser concreto:

  • Imágenes y embeds sin width y height (o sin aspect-ratio).
  • Un banner de cookies o una barra de admin que empuja el header.
  • Anuncios o iframes que se inyectan arriba del contenido.
  • Icon fonts o webfonts que cambian el ancho de un menú.

El banner de cookies va en un espacio ya reservado, o superpuesto, con una altura fija. Un iframe de mapa debajo del pliegue lleva aspect-ratio en el contenedor para que el hueco exista antes de la respuesta del tercero.

.mapa {
  aspect-ratio: 16 / 9;
  width: 100%;
  background: #e7e2d8;
}

Qué dejar de sumar

Cada optimizador nuevo es otra capa que reescribe HTML:

  • Un plugin de lazy load encima del lazy load de WordPress.
  • Autoptimize o un combinador de CSS, más el CSS ya concatenado del constructor.
  • Un plugin de “quitar emojis, query strings y heartbeat” como si eso fuera el LCP.

El heartbeat y los emojis no explican un LCP de 5 s. El constructor, la imagen y el TTFB sí.

Cuando el CSS del tema pesa más que el contenido, el paso siguiente es otro tema: bloques nativos, sin page builder, con las imágenes y la caché resueltas como arriba. Eso es un tema WordPress a medida, medido por Core Web Vitals, no un ajuste más del plugin de caché.

Orden de trabajo

  1. Anotá LCP, INP y CLS de campo, móvil y escritorio.
  2. Mirá el desglose de LCP. Si manda el TTFB, caché de página, PHP y plugins activos.
  3. Identificá el elemento LCP. <img> con tamaño, fetchpriority="high" y sin lazy load.
  4. Una sola webfont, self-hosted, preload del mismo archivo.
  5. Sacá JavaScript que no participa del primer render: constructor de más, sliders, chat, píxeles.
  6. Reservá espacio para imágenes, banners y embeds.
  7. Volvé a correr el laboratorio. El campo se actualiza en las semanas siguientes, no en el deploy.

Si el laboratorio mejora y a los 28 días el campo sigue igual, estás midiendo otra URL (home con caché vs. una ficha de producto sin caché) o el tráfico real entra por una plantilla que no tocaste.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.