| name | wordpress-elementor |
| description | Conocimiento especializado sobre WordPress + Elementor para auditorías SEO. Issues recurrentes, soluciones y checklist de verificación específicos para sitios construidos con Elementor (free y Pro). Usar cuando el sitio auditado corra WordPress + Elementor o cuando el usuario mencione "Elementor", "Hello Elementor", "Elementor Pro" o "elementor-post".
|
WordPress + Elementor — Guía SEO Técnica
Verificado en Elementor 4.0.x / Elementor Pro 3.35.x + WordPress 6.x.
Documentación oficial Elementor: https://elementor.com/help/
Documentación desarrolladores: https://developers.elementor.com/
Contexto de plataforma
Elementor es un page builder visual con sistema de widgets. A diferencia de
Divi, genera archivos CSS externos por post/página (elementor-post-XXXXX.css)
además de bloques <style> inline para estilos widget-específicos.
Características clave con impacto SEO:
- Renderizado server-side (SSR): contenido en HTML inicial. No es SPA.
Googlebot puede indexar sin ejecutar JS. Señalarlo como positivo.
- CSS externo por página:
elementor-post-[ID].css — cargado como stylesheet
externo, no como CSS inline masivo (diferencia clave vs. Divi).
- Sin embargo: genera bloques
<style> inline para estilos widget-específicos
que se inyectan en el <head>.
- Lazy loading nativo: Elementor aplica lazy load a secciones mediante CSS:
.e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded) → oculta backgrounds
hasta que JS lo marca como cargado. Afecta CLS y LCP.
- Google Fonts puede servirse localmente desde
/wp-content/uploads/elementor/google-fonts/ — verificar si está activo.
Stacks técnicos habituales:
| Variante | Componentes |
|---|
| Básico | Elementor (free) + Hello Elementor theme + Yoast SEO |
| Pro | Elementor Pro + Hello Elementor o GeneratePress + Yoast + WP Rocket |
| WooCommerce | Elementor Pro + WooCommerce + WP Rocket + Yoast SEO + Schema Pro |
Temas frecuentes: Hello Elementor (con child theme), GeneratePress
Issues recurrentes — Detección y solución
LCP hero image lazy-loaded (CRÍTICO — frecuencia: muy alta)
Síntoma A — Elementor nativo: La imagen hero above-the-fold tiene
class="lazyload" y data-src en lugar de src. El src real es un
placeholder SVG base64.
<img data-src="https://dominio.com/hero.jpg"
src="data:image/svg+xml;base64,..."
class="lazyload wp-image-53">
Síntoma B — WP Rocket + Elementor: WP Rocket reemplaza el src real con
un placeholder SVG y mueve la URL real a data-lazy-src. Incluso si
fetchpriority="high" está en el elemento, el preload scanner no puede
descubrir la imagen.
<img src="data:image/svg+xml,..."
data-lazy-src="https://cdn.shortpixel.ai/.../hero.webp"
fetchpriority="high"> ← fetchpriority inútil si src es SVG placeholder
Causa: Elementor aplica lazy load a imágenes y backgrounds por defecto.
WP Rocket duplica el problema con su propio sistema de lazy load.
Impacto: LCP imagen no descubierta por preload scanner → LCP elevado en
mobile y conexiones lentas.
Solución A — desactivar lazy load en sección hero (Elementor):
- Abrir sección hero en Elementor Builder
- Advanced > Attributes: añadir
data-no-lazyload o aplicar clase e-no-lazyload
- El CSS de Elementor excluye estas secciones del lazy load:
.e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload)
Solución B — excluir de WP Rocket lazy load:
- WP Rocket > Media > LazyLoad > Excluded Images: añadir el filename de la imagen hero
(ej:
hero-portada, envio-flores-domicilio)
Solución C — preload manual en <head>:
<link rel="preload" as="image"
href="https://dominio.com/wp-content/uploads/hero.jpg"
fetchpriority="high">
Solución D — imagen con <img> real y fetchpriority:
add_filter('wp_get_attachment_image_attributes', function($attr, $attachment, $size) {
if ($attachment->ID === HERO_IMAGE_ID) {
$attr['fetchpriority'] = 'high';
$attr['loading'] = 'eager';
unset($attr['class']);
}
return $attr;
}, 10, 3);
fetchpriority en elemento incorrecto (CRÍTICO — impacto LCP)
Síntoma: fetchpriority="high" aplicado a una imagen decorativa (separador,
divider) en lugar de a la imagen LCP real. A veces aparece duplicado en el
mismo elemento.
Causa: Elementor o el editor asigna manualmente fetchpriority="high" sin
criterio en el widget Image.
Verificación: Buscar en el HTML fetchpriority="high" y verificar que
corresponde a la imagen visualmente más grande above-the-fold.
Solución:
- Quitar
fetchpriority="high" de imágenes decorativas (separadores, iconos)
- Añadirlo a la imagen hero / LCP real
- En Elementor > Widget Image > Advanced > Attributes
CSS/JS excesivos — render-blocking (CRÍTICO — CWV)
Síntoma: 40-90+ recursos CSS y JS en el <head> o body temprano.
Causas específicas de Elementor:
- CSS widget-específico cargado globalmente (no por página):
widget-image.min.css, widget-icon-list.min.css, widget-divider.min.css,
widget-social-icons.min.css, etc.
- CSS de Font Awesome (eicons, fa-brands, fa-solid) cargado en todas las páginas
- jQuery + jQuery Migrate sin
defer
- Plugins de eventos (The Events Calendar), GDPR, sliders — cargan en todas
las páginas sin carga condicional
Solución principal — Improved Asset Loading (Elementor):
- Elementor > Settings > Performance (o Experiments)
- Activar "Improved Asset Loading": carga solo el CSS de los widgets
presentes en cada página, no el CSS global de todos los widgets
- Activar "Inline Font Icons" si está disponible: reduce peticiones de fonts
Solución complementaria — WP Rocket o LiteSpeed Cache:
- Diferir jQuery (con exclusión si hay conflictos con Elementor)
- Minificar y combinar CSS
- Activar "Delay JS execution" para scripts no críticos
Carga condicional PHP para plugins que no respetan páginas:
add_action('wp_enqueue_scripts', function() {
if (!is_singular('tribe_events') && !is_post_type_archive('tribe_events')) {
wp_dequeue_script('tec-user-agent-js');
wp_dequeue_style('tribe-events-calendar-style');
wp_dequeue_style('tribe-events-full-calendar-style');
}
}, 100);
Inline CSS masivo — bloques <style> de Elementor (ALTO — CWV)
Síntoma: 40+ bloques <style> inline en el <head> sumando 80-100+ KB.
Causa: Elementor inyecta estilos personalizados de cada widget directamente
en el HTML. En sitios con muchos widgets y secciones, esto acumula CSS inline
significativo.
Diferencia con Divi: El CSS principal de Elementor es externo
(elementor-post-XXXXX.css), pero los estilos personalizados del editor
se inyectan inline. Divi inyecta todo inline.
Solución:
- Activar "Improved Asset Loading" (reduce CSS inline moviendo estilos a archivo externo)
- WP Rocket > File Optimization > "Minify CSS" + "Combine CSS"
- Reducir uso de estilos custom por widget en el editor (usar clases CSS globales
en lugar de estilos inline por elemento)
WP Rocket + Elementor — HTML payload masivo (ALTO — CWV)
Síntoma: HTML de la página supera 500 KB o 1 MB.
Causa: WP Rocket inyecta inline la clase RocketLazyLoadScripts completa y
el objeto de configuración elementorFrontendConfig como script inline. En
sitios con muchos widgets se han medido payloads de 700 KB - 1.4 MB.
Impacto: TTFB parsing alto, INP degradado, TBT elevado.
Solución:
- WP Rocket > File Optimization > "Minify JavaScript" activo
- Revisar si el objeto
elementorFrontendConfig puede moverse a archivo externo
via JS deferral settings
- Reducir número de secciones/widgets por página
- Activar "Improved Asset Loading" para reducir el objeto de configuración
Elementor backgrounds como CSS background-image (ALTO — LCP)
Síntoma: La sección hero usa background-image en CSS inline del contenedor,
no un <img> tag.
Causa: El módulo Section/Container de Elementor aplica background vía CSS
por defecto para imágenes de sección.
Impacto: Imagen no visible para el preload scanner → LCP elevado.
Comportamiento específico de Elementor lazy load:
.e-con.e-parent:nth-of-type(n+4):not(.e-lazyloaded):not(.e-no-lazyload) {
background-image: none !important;
}
Las secciones con background image después de la 3ª (desktop) o 2ª (mobile)
son invisible hasta que JS las marca como e-lazyloaded. Causa CLS cuando
"aparecen" al scroll.
Solución: Marcar secciones críticas con e-no-lazyload. Para secciones
hero que usen background, añadir preload manual del background.
Seguridad — headers ausentes (CRÍTICO — frecuencia: 100%)
Detectado de forma consistente en auditorías. Frecuencia: muy alta.
Solución Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
fastcgi_hide_header X-Powered-By;
Solución Apache / .htaccess:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
CSP con Elementor: Elementor y WooCommerce requieren 'unsafe-inline' para
scripts y estilos. CSP estricta no viable sin nonces. CSP mínima recomendada:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
'unsafe-eval' *.googletagmanager.com *.facebook.net;
img-src 'self' data: *.facebook.com;
Advertencia: ajustar tras auditar todos los third-parties (GTM, Pixel, etc.).
Exposición de versiones (ALTO — seguridad)
Elementor expone su versión en meta generator:
<meta name="generator" content="Elementor 4.0.0; features: e_optimized_markup">
Solución PHP:
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');
add_action('wp_head', function() {
remove_action('wp_head', [\Elementor\Core\Base\App::class, 'add_generator_tag']);
}, 0);
X-Powered-By: Igual que en Divi — eliminar en Nginx/Apache/php.ini.
WP REST API — REST Link header expone IDs (MEDIO)
Síntoma: La cabecera Link en cada respuesta HTTP expone el ID interno
de WordPress de la página:
Link: <https://dominio.com/wp-json/wp/v2/pages/29615>; rel="alternate"
Nota Elementor Pro: Elementor Pro puede requerir el REST API para algunas
funcionalidades (formularios, templates). Verificar antes de restringir.
Solución — eliminar Link header sin bloquear REST API:
remove_action('template_redirect', 'rest_output_link_header', 11);
Solución — eliminar endpoint users (enumeración):
add_filter('rest_endpoints', function($endpoints) {
unset($endpoints['/wp/v2/users']);
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
return $endpoints;
});
DOM size — estructura Section/Column vs Container (MEDIO)
Elementor Sections (legado): Cada sección genera 4 divs de envoltura
(section > .elementor-container > .elementor-row > .elementor-column > .elementor-widget-wrap).
Elementor Containers (Flexbox — moderno): Genera solo 2 divs.
Lighthouse avisa si el body supera 818 nodos (warning) o 1.400 nodos (error).
Solución: Migrar layouts Section/Column → Containers vía el botón "Convert"
de Elementor. Reducción de DOM ~50% en secciones de una sola columna.
Ruta: Elementor > Tools > Replace URL / Converter.
WooCommerce + Elementor — issues específicos (MEDIO)
Duplicate schema breadcrumb: Si se usan Yoast SEO + Schema Pro simultáneamente,
se generan dos BreadcrumbList conflictivos. Desactivar breadcrumbs en Schema Pro
y dejar solo el de Yoast.
FAQPage schema en sitios e-commerce: Google restringió FAQ rich results a
sitios gov/salud desde 2023. No genera rich results en e-commerce. No añadir
nuevas implementaciones de FAQPage en sitios comerciales.
Product schema ausente: WooCommerce no genera automáticamente Product +
Offer schema sin Yoast WooCommerce SEO add-on o Schema Pro correctamente
configurado. Verificar en cada producto.
Mi cuenta en sitemap: /mi-cuenta/ suele estar marcada noindex pero
aparece en page-sitemap.xml. Excluir vía Yoast: SEO > Search Appearance >
WooCommerce > My Account: No.
Robots.txt — bloquear URLs transaccionales WooCommerce:
Disallow: /carrito/
Disallow: /checkout/
Disallow: /mi-cuenta/
Disallow: /cart/
Disallow: /checkout/
PHP EOL — Elementor y PHP 7.4 (CRÍTICO si presente)
Elementor 4.x requiere mínimo PHP 7.4 pero recomienda PHP 8.0+. PHP 7.4 está EOL desde nov 2022.
Fix: Actualizar en el panel del hosting (Hostinger hPanel, cPanel, Plesk).
Pasos: PHP Manager > Seleccionar PHP 8.2 o 8.3 > Guardar.
Verificar compatibilidad de plugins antes de actualizar.
Google Tag Manager — posición bloqueante (MEDIO)
GTM se implementa frecuentemente como script síncrono en <head>. Aunque el
script principal de GTM se carga con async, el fragmento de inicialización
inline es render-blocking.
Fix: No existe solución perfecta — GTM requiere ser lo más early como sea
posible. Mitigaciones:
- Auditar tags dentro del contenedor GTM para eliminar los que bloquean
- Configurar tags de GTM para dispararse en
DOM Ready o Window Loaded
en lugar de Page View cuando sea posible
- Evaluar Partytown para mover GTM a web worker (experimental)
Canibalización en páginas de localización (MEDIO)
Elementor facilita duplicar templates de página cambiando solo el nombre de
localidad. Detectado en sitios de servicios locales con 10+ páginas de zona.
Señales de alerta:
- Múltiples páginas con la misma imagen decorativa (separador, divider)
lastmod idéntico en grupo de URLs similares en el sitemap
- Patrón URL:
/servicio-[ciudad]/ con contenido idéntico salvo el nombre
Fix: Cada página de localización debe tener:
- Párrafo introductorio único con referencia a barrios / landmarks de esa ciudad
- Schema
areaServed apuntando a esa municipalidad específica
- Mínimo 400-600 palabras de contenido único
LiteSpeed / Hostinger — X-Robots-Tag noindex en sitemaps XML (CRÍTICO)
Síntoma: Todos los sitemaps devuelven el header X-Robots-Tag: noindex, follow
aunque Yoast los tenga correctamente configurados. GSC reporta los sitemaps como no procesables.
Causa: LiteSpeed Cache o la configuración del hosting aplica noindex globalmente
a archivos con extensión .xml. El sitemap es accesible pero Google no puede procesarlo
porque la respuesta HTTP le indica que no lo indexe.
Verificación:
curl -I https://dominio.com/sitemap_index.xml | grep -i x-robots
Impacto: Google no incorpora el sitemap aunque esté declarado en robots.txt y enviado
en GSC. El crawl budget se desperdicia en descubrimiento en lugar de en crawl dirigido.
Solución A — LiteSpeed Cache:
LiteSpeed Cache > Avanzado > Excluir de caché → añadir /sitemap*.xml a exclusiones de headers.
Solución B — .htaccess (Apache/LiteSpeed):
<FilesMatch "sitemap.*\.xml$">
Header unset X-Robots-Tag
Header set X-Robots-Tag "index, follow"
</FilesMatch>
Solución C — Soporte de hosting:
En algunos planes de Hostinger, la configuración LiteSpeed es a nivel servidor.
Reportar el issue indicando el header exacto y la URL del sitemap afectada.
Nota: Verificar siempre X-Robots-Tag en sitemaps con curl -I antes de
marcar el sitemap como correctamente configurado — el status 200 no garantiza procesabilidad.
Elementor Theme Builder — override en archive pages (CRÍTICO)
Qué es Theme Builder: Elementor Pro incluye un constructor de plantillas para
secciones del tema: Header, Footer, Single (post/página individual), Archive
(categorías, tags, autor, fecha), 404, Search Results.
El problema SEO: Cuando Theme Builder sobreescribe una plantilla de archive,
puede desconectar la propagación de directivas SEO del plugin (Yoast/Rank Math):
-
noindex no heredado en archive paginado:
Si el plugin SEO tiene configurado noindex para páginas de paginación
(/categoria/page/2/), pero Theme Builder genera esas páginas usando su
propia plantilla, el plugin puede no inyectar el meta robots en el <head>.
El resultado: páginas paginadas indexables cuando no deberían serlo.
Verificación: curl -s https://dominio.com/categoria/page/2/ | grep -i "noindex"
-
Canonical incorrecto en archive con Theme Builder:
Theme Builder puede generar un canonical que apunta a la plantilla de archive
genérica en lugar de a la URL específica de cada página.
Verificación: WebFetch de una página de categoría y buscar rel="canonical".
-
BreadcrumbList duplicado:
Elementor Pro puede inyectar su propio widget de breadcrumb (con su schema)
además del breadcrumb de Yoast. Resultado: dos bloques BreadcrumbList en el mismo head.
Fix: Usar solo uno — desactivar el schema de breadcrumb en Yoast (SEO >
Search Appearance > Breadcrumbs: Off) si se usa el widget de Elementor con schema,
o viceversa.
-
/shop/ page con Theme Builder:
La página shop de WooCommerce bajo Theme Builder Archive puede no recibir
correctamente el noindex de paginación. Verificar que /shop/page/2/ tiene
<meta name="robots" content="noindex">.
Verificación general de Theme Builder:
- Elementor > Templates > Theme Builder > verificar qué páginas están siendo
controladas por cada template
- Para cada archive template activo: WebFetch de varias URLs y comparar
canonical + meta robots con lo configurado en el plugin SEO
Elementor Pro vs Free — diferencias con impacto SEO (MEDIO)
| Feature | Free | Pro | Impacto SEO |
|---|
| Theme Builder | No | Sí | Riesgo de canonical/noindex override en archives |
| Dynamic Tags | No | Sí | Permite usar el título de la página como H1 dinámico — positivo |
| Popup Builder | No | Sí | Popups pueden inyectar contenido adicional en el DOM |
| Forms | No (básico) | Sí | Formularios con eventos GTM/GA4 más fáciles de configurar |
| WooCommerce Builder | No | Sí | Permite personalizar product pages — riesgo de alterar schema Product |
| Loop Grid | No | Sí | Para listing pages dinámicas — verificar canonical en cada item |
Dynamic Tags — riesgo específico:
Elementor Pro permite usar Dynamic Tags para rellenar campos del builder con
datos de WordPress (título del post, meta description, custom fields).
Si se usa un Dynamic Tag para el H1 y este extrae el campo equivocado, el H1
resultante puede no coincidir con el título configurado en Yoast/Rank Math.
Verificación: WebFetch de la página y comparar H1 visible con el title tag.
Popup Builder:
Los popups de Elementor Pro se cargan en el DOM de la página aunque estén ocultos.
Si el popup contiene texto con keywords relevantes, Google puede leer ese contenido
y mezclar las señales de relevancia.
TranslatePress — Hreflang duplicado (MEDIO)
Síntoma: El <head> contiene dos bloques de hreflang para las mismas URLs:
uno de TranslatePress y otro de Yoast SEO.
Causa: Ambos plugins generan hreflang automáticamente si no se desactiva en uno de ellos.
Impacto: Google puede ignorar ambos bloques si detecta conflicto.
Solución:
- Desactivar hreflang en Yoast: SEO > Search Appearance > General > Hreflang: Off
- Dejar TranslatePress como única fuente, o viceversa
- Verificar post-fix:
rel="alternate" debe aparecer solo una vez por par idioma+URL en <head>
Checklist de auditoría técnica para sitios Elementor
CRÍTICO
[ ] LiteSpeed/Hostinger: ¿X-Robots-Tag: noindex en sitemaps XML? (curl -I sitemap_index.xml)
[ ] LCP hero: ¿imagen con src real o SVG placeholder (data-src / data-lazy-src)?
[ ] fetchpriority="high": ¿está en la imagen LCP o en elemento incorrecto?
[ ] Security headers: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
[ ] PHP version: ¿EOL? Detectar en X-Powered-By
[ ] CSS/JS count: ¿>40 recursos en el head?
ALTO
[ ] WP Rocket: ¿reemplaza src hero con SVG placeholder?
[ ] Secciones hero: ¿marcadas con e-no-lazyload?
[ ] HTML payload: ¿supera 500 KB?
[ ] CSS inline blocks: ¿cuántos <style> en <head>?
[ ] Improved Asset Loading: ¿activo en Elementor Settings > Performance?
[ ] <meta name="generator"> Elementor: ¿eliminado?
[ ] X-Powered-By: ¿eliminado de headers HTTP?
[ ] WP REST API: Link header con IDs expuesto
[ ] WooCommerce: /mi-cuenta/ en sitemap con noindex (conflicto)
[ ] WooCommerce: schema Product + Offer en páginas de producto
MEDIO
[ ] DOM size: ¿Section/Column legado o Containers modernos?
[ ] GTM: ¿tags audited? ¿fire en Page View o DOM Ready?
[ ] WooCommerce + Yoast + Schema Pro: ¿BreadcrumbList duplicado?
[ ] FAQPage schema: ¿implementado en sitio e-commerce? (no genera rich results)
[ ] TranslatePress + Yoast: ¿hreflang duplicado en <head>?
[ ] Index bloat: páginas de localización con contenido idéntico
[ ] Author archives: ¿indexados? (Yoast > Apariencia > Archivos)
[ ] "Sin categoría": ¿en sitemap?
[ ] og:type: ¿"article" en páginas de servicio? (debe ser "website")
[ ] OG image: ≥1200×630px, no decorativa
BAJO
[ ] IndexNow: ¿implementado?
[ ] Robots.txt: política AI crawlers
[ ] RSS feeds: ¿necesarios para este tipo de sitio?
[ ] Dofollow links a agencia en footer
[ ] URLs >100 caracteres en secciones programáticas
Positivos habituales en sitios Elementor bien configurados
- SSR confirmado: contenido en HTML inicial sin necesidad de JS
- CSS externo por página (
elementor-post-XXXXX.css) — no todo inline como Divi
- Google Fonts servidas localmente (
/wp-content/uploads/elementor/google-fonts/)
- Imágenes con
width + height explícitos → previene CLS
srcset y sizes en imágenes → delivery responsivo
- ShortPixel CDN con WebP/AVIF si está configurado
- Canonical self-referencing en HTML inicial
Referencias rápidas — Rutas de configuración
Elementor:
- Improved Asset Loading: Elementor > Settings > Performance
- Lazy load hero image: Widget > Advanced > Attributes:
data-no-lazyload o clase e-no-lazyload
- DOM Converter (Section → Container): Elementor > Tools
- Google Fonts local: Elementor > Settings > Advanced > Google Fonts
WP Rocket:
- Excluir imagen de lazy load: WP Rocket > Media > LazyLoad > Excluded Images
- Defer JS: WP Rocket > File Optimization > Defer JS execution
- Minify CSS/JS: WP Rocket > File Optimization
Yoast SEO:
- WooCommerce pages en sitemap: SEO > Search Appearance > WooCommerce
- Author archives: SEO > Search Appearance > Archives
- OG/Twitter Card: SEO > Search Appearance > Social
WordPress core (mismo stack que Divi — ver wordpress-divi skill):
- Eliminar generator:
remove_action('wp_head', 'wp_generator')
- Restringir REST API users:
unset($endpoints['/wp/v2/users'])
- Eliminar REST Link header:
remove_action('template_redirect', 'rest_output_link_header', 11)