Reporte Técnico

Aislamiento CSS TeamHost — Reporte Completo

WordPress + Tailwind CSS × Plugin TeamHost/Inmovilla (Bootstrap 3.3.7) · Scoping, Overrides & Server-side Strip

ProyectoHabitat Catalunya
Branchfeat/teamhost-isolation
Commits93 (5 esta semana)
Período14–20 marzo 2026
EstadoFase A en progreso
1 Resumen Ejecutivo
3,609
Selectores Scoped
7
Funciones PHP
3
CSS Nuevos
18
Lecciones Aprendidas

El Problema

El plugin TeamHost/Inmovilla —un CRM inmobiliario— inyecta Bootstrap 3.3.7 de forma global en todas las páginas del sitio. Bootstrap es un framework CSS que define estilos para grids (columnas), tipografía, botones, formularios y más. Al cargarse globalmente, estos estilos contaminan el tema custom basado en Tailwind CSS (otro framework CSS, utility-first), rompiendo layouts, sobreescribiendo fuentes, alterando tamaños de texto y causando conflictos visuales en cada página.

El plugin carga 6 archivos CSS y 8 archivos JS desde un CDN externo (imediasystems.es), sin ninguna opción nativa de aislamiento.

La Solución

Aislamiento CSS por scoping: descargamos todos los CSS del plugin, los procesamos con PostCSS (una herramienta de transformación CSS automática) para prefijar cada selector bajo .teamhost-shortcode, y los servimos localmente. Así, Bootstrap solo afecta elementos dentro de los wrappers de shortcodes, no el resto del sitio.

Adicionalmente, creamos un sistema de overrides CSS por capas (3 archivos específicos por contexto) y funciones PHP para eliminar galerías legacy server-side usando DOMDocument.

2 Cronología de Commits (14–20 marzo)
17 Mar
09:21

Correcciones generales + rescue plugin Inmovilla

Descarga del plugin desde el servidor de producción como respaldo. Correcciones de estilos generales del tema.

rescue-from-server/plugins/pluginInmovilla/ · functions.php · varios CSS/PHP
18 Mar
17:10

feat: Aislamiento CSS TeamHost — scoping PostCSS + dequeue inteligente

Commit central del proyecto. Descarga de 7 CSS remotos (246KB), concatenación en bundle, pipeline PostCSS con postcss-prefix-selector, generación de teamhost-scoped.css (11,138 líneas, 3,609 selectores). Reescritura completa de hc_manage_inmovilla_assets().

assets/dist/teamhost-scoped.css · assets/src/css/vendor/* (7 archivos) · scripts/scope-teamhost.cjs · functions.php · package.json · scripts/teamhost-sync.sh · docs/*
19 Mar
00:06

fix: FA icons + Galleria error + button hover + TeamHost override layer

Primer archivo de overrides CSS (553 líneas). Fix de iconos Font Awesome, eliminación parcial del banner rojo de Galleria, corrección de hover en botones del tema.

teamhost-overrides.css (553 nuevas) · functions.php · contact-cta.php · property-contact.php
19 Mar
11:59

feat: Arquitectura híbrida ficha propiedad — galería custom + datos TeamHost

Implementación del flujo híbrido en fichas: extracción de imágenes del CRM vía DOMDocument, galería Ken Burns propia, inyección de slug en $_GET['title'], detección de redirects de TeamHost, soporte NORDIK para páginas en catalán.

functions.php (+176 líneas) · page-propiedad.php (reescritura mayor)
20 Mar
08:22

feat: Split CSS overrides por contexto + server-side gallery strip

Split del monolítico (896 líneas) en 3 archivos por contexto. Función hc_strip_legacy_galleries() con DOMDocument. Fix definitivo del overlap ubicación/precio con flex-shrink: 0. Nuclear Galleria kill (CSS + JS inline).

+teamhost-universal.css · +teamhost-home-listing.css · +teamhost-ficha.css · functions.php · page-home.php · page-propiedad.php
3 Arquitectura CSS — Sistema de 3 Capas

El CSS del sitio usa un sistema de capas que garantiza que Bootstrap del plugin solo afecte a los shortcodes, y que nuestros estilos visuales se apliquen correctamente encima. Scoping significa que cada selector CSS está prefijado con una clase contenedora (como .teamhost-shortcode .btn en vez de .btn global).

Capa 1 — Scoped Bundle (generada por pipeline)
teamhost-scoped.css · 11,138 líneas · 3,609 selectores
Bootstrap 3.3.7 + jQuery UI + Multiselect + Galleria + estilos del plugin, todos prefijados bajo .teamhost-shortcode. Generado automáticamente por scripts/scope-teamhost.cjs. NUNCA editar manualmente.
Capa 2 — Universal Overrides (compartidos)
teamhost-universal.css · 110 líneas
Design tokens (variables CSS), tipografía base (Montserrat), overrides globales (links, botones, inputs ocultos del plugin), backup CSS para Galleria kill. Se carga en TODAS las páginas con shortcodes TeamHost.
Capa 3A — Home: Buscador + Listado
teamhost-home-listing.css · 732 líneas · Solo en page-home.php
Estilos del buscador (shortcode [BAmbos KUBE]), cards de propiedades (shortcode [LAmbos KUBE]), tags, paginación, responsive. Usa wrappers .teamhost-buscador y .teamhost-listado.
Capa 3B — Ficha: Galería + Detalle
teamhost-ficha.css · 187 líneas · Solo en page-propiedad.php
Hide de Galleria/Jssor (backup CSS), layout del detalle, tarjeta de agente, características, condiciones. Usa wrapper .teamhost-ficha.
Capa 3C — Alertas (pendiente)
teamhost-alertas.css · Pendiente · Solo en page-contacto.php
Estilos del formulario [FAlertas KUBE] en la página de contacto. Fase C del plan.

Orden de carga: Tema Tailwind (hc-main-css) → Capa 1 (scoped) → Capa 2 (universal) → Capa 3 (específica por template). Cada capa depende de la anterior via wp_enqueue_style() dependencies.

4 Funciones PHP — Inventario Completo

hc_is_teamhost_context() Core

Qué hace: Detecta si la página actual necesita assets de TeamHost.

Cómo funciona: 3 capas de detección en orden de confiabilidad:

  • Capa 1 — Template slug: Revisa si la página usa page-home.php, page-contacto.php o page-propiedad.php (los 3 templates que renderizan shortcodes).
  • Capa 2 — URL slug: Usa hc_get_property_slug_from_url() para detectar si hay un slug de propiedad en la URL (ej: /propiedad/casa-martorell/).
  • Capa 3 — Shortcode fallback: Busca shortcodes TeamHost en el post_content con has_shortcode().

Ubicación: functions.php:266

hc_dequeue_teamhost_css() Core

Qué hace: Elimina TODOS los CSS del plugin en TODAS las páginas (global).

Cómo funciona: Doble criterio de detección:

  • Handles conocidos: bootstrap, bootstrapMultiselectCSS, jqueryUICSS, galleriaStyle, style (5 handles). Se llama wp_dequeue_style() + wp_deregister_style() para cada uno.
  • Patrón de URL: Recorre $wp_styles->registered y busca URLs que contengan pluginInmovilla, inmovilla o imediasystems. Atrapa handles nuevos que no conocemos por nombre (robusto ante updates del plugin).

Nota: Font Awesome NO se dequeue porque los shortcodes usan sus iconos y no conflicta con Tailwind.

Ubicación: functions.php:310

hc_dequeue_teamhost_js_if_not_needed() Core

Qué hace: Gestiona los scripts JS del plugin de forma inteligente.

Cómo funciona:

  • SIEMPRE elimina: galleria y galleriaTheme (no usamos la galería legacy del plugin en ningún contexto).
  • Solo en páginas SIN TeamHost: Elimina todos los scripts del plugin (bootstrapmin, bootstrapMultiselect, zonas, functions, functionsAgencia) + patrón de URL.
  • En páginas CON TeamHost: Los scripts PERMANECEN cargados porque los shortcodes los necesitan (filtros, mapas, formularios).

Ubicación: functions.php:357

hc_isolate_teamhost_assets() Core

Qué hace: Orquesta todo el aislamiento. Es la función principal enganchada a wp_enqueue_scripts con prioridad 999 (se ejecuta después de que el plugin registre sus assets).

Cómo funciona:

  1. Inyecta CSS inline global: hide de reCAPTCHA badge, Galleria kill nuclear, cursor pointer.
  2. Inyecta JS inline: DOMContentLoaded para eliminar elementos Galleria del DOM.
  3. Llama a hc_dequeue_teamhost_css() (global).
  4. Si es contexto TeamHost: carga Capa 1 (scoped) → Capa 2 (universal) → Capa 3 (específica).
  5. Llama a hc_dequeue_teamhost_js_if_not_needed().

Ubicación: functions.php:407

hc_strip_legacy_galleries($html) Nuevo

Qué hace: Elimina markup de Galleria/Jssor del HTML server-side, ANTES de que llegue al navegador.

Por qué existe: El banner rojo de error de Galleria persistía a pesar de 3 capas de CSS hide + JS dequeue. La razón: el plugin inyecta los errores con estilos inline que tienen mayor especificidad que cualquier CSS externo, y el JS re-enqueue ocurre en wp_footer (después de nuestro dequeue).

Cómo funciona: Usa DOMDocument (parser HTML nativo de PHP, no regex) para:

  • Buscar elementos por ID: #jssor_1, #slider1_container
  • Buscar por clase: .galleria-container, .galleria-errors, .galleria
  • Buscar <script> tags que referencien Galleria o Jssor
  • Eliminar todos los nodos encontrados del árbol DOM
  • Devolver el HTML limpio

Se aplica a: Todo output de do_shortcode() en page-home.php y page-propiedad.php.

Ubicación: functions.php:585

hc_extract_teamhost_images($html) Nuevo

Qué hace: Extrae URLs de imágenes de la propiedad desde el HTML del shortcode de TeamHost.

Cómo funciona: 3 fuentes de datos, procesadas en orden:

  1. Tags <img>: Busca src que contenga fotos, apinmo o inmovilla (CDN de imágenes del CRM).
  2. Data attributes: Busca data-image, data-big, data-src en cualquier elemento.
  3. URLs en scripts: Regex sobre el HTML raw para encontrar URLs de imagen en scripts de Galleria (galleria.push / galleria.load).

Deduplica por URL, ordena por posición en el DOM, y retorna un array de ['url', 'thumb', 'alt', 'orden'].

Ubicación: functions.php:649

hc_get_property_slug_from_url() Nuevo

Qué hace: Extrae el slug de propiedad desde la URL actual.

Por qué no usar get_query_var('title'): WordPress intercepta title como query var interno de WP_Query, así que nunca contiene el slug del plugin. La solución: parsear $_SERVER['REQUEST_URI'] directamente, igual que hace el propio plugin.

Soporta rutas en 3 idiomas:

  • Español: /propiedad/[slug], /propiedad-alquiler/[slug], /propiedad-alquiler-vacacional/[slug]
  • Catalán: /propietat/[slug], /propietat-lloguer/[slug]
  • Inglés: /property/[slug], /rental-property/[slug]

Ubicación: functions.php:543

hc_parse_teamhost_property($html) Nuevo

Qué hace: Extrae datos estructurados (título, referencia, imágenes) del HTML de TeamHost para alimentar componentes custom (galería, breadcrumb, formulario de contacto pre-llenado).

Ubicación: functions.php:724

5 Pipeline de Scoping — Cómo se genera el bundle

Scoping es el proceso de prefijar todos los selectores CSS de un framework externo con una clase contenedora, de modo que sus reglas solo apliquen dentro de esa clase. Ejemplo: .btn { ... } se convierte en .teamhost-shortcode .btn { ... }.

7 CSS remotos
imediasystems.es
Descarga local
vendor/*.css
Concatenar
teamhost-raw.css
PostCSS Scope
scope-teamhost.cjs
teamhost-scoped.css
11,138 líneas

Archivos CSS del Plugin (Inventario)

ArchivoOrigenPropósito
bootstrap.cssimediasystems.esBootstrap 3.3.7 completo (6,769 líneas)
bootstrap-multiselect.cssimediasystems.esPlugin de multi-select para filtros del buscador
jquery-ui.cssimediasystems.esjQuery UI (sliders de precio, datepickers)
galleria-azur.cssimediasystems.esTema Azur de Galleria (galería de imágenes que NO usamos)
panorama.cssimediasystems.esEstilos de layout de fichas y listados
inmovilla-agency-style.cssimediasystems.esEstilos custom de la agencia (configurados por Steven)
font-awesome-all.cssimediasystems.esFont Awesome 4.x (iconos — NO se scopea, se deja global)

scripts/scope-teamhost.cjs — El Motor del Scoping

Script Node.js que usa la API directa de PostCSS (no postcss-cli, que no ejecuta plugins correctamente) con postcss-prefix-selector.

Exclusiones críticas (no se prefijarían porque romperían funcionalidad):

  • @font-face — Las fuentes deben ser globales para cargar correctamente
  • @keyframes, from, to, % — Las animaciones CSS no se prefijarían
  • :root, html, body — Selectores globales que contaminarían Tailwind si se dejaran

Post-procesamiento AST: Después del prefijado, un walker del AST (Abstract Syntax Tree = árbol de nodos que representa el CSS parseado) elimina reglas con selectores bare como html, body, :root que postcss-prefix-selector no prefija pero tampoco elimina.

Comando: npm run scope:teamhost

scripts/teamhost-sync.sh — Pipeline de Actualización

Script Bash que ejecuta el pipeline completo cuando los CSS de TeamHost cambian:

  1. Descarga CSS frescos del servidor (SSH/SCP)
  2. Concatena en teamhost-raw.css
  3. Ejecuta scope-teamhost.cjs
  4. Verifica: 0 @font-face prefijados, 0 @keyframes prefijados
  5. Genera backup del bundle anterior
6 Cómo se Logró — Cards de Propiedad

El Momento “Eureka”: flex-shrink: 0

Después de múltiples intentos fallidos (float:none, clear:both, overflow:hidden, text-overflow:ellipsis, order, max-width, position:static), el fix definitivo fue una sola propiedad CSS: flex-shrink: 0 en el <header> del card body.

El problema:

Las cards de propiedad de TeamHost tienen esta estructura HTML:

<!-- Estructura real del HTML de TeamHost --> <div class="info-plus-amaze listing"> <!-- Card body --> <header> <!-- Contiene tipo + ubicación --> <div class="row">...<div class="type">Casa</div>...</div> <div class="row">...<div class="type">📍 Sant Esteve Sesrovires</div>...</div> </header> <div class="col-md-12 grid-precio-amaze"> <!-- Precio (hermano de header) --> <a class="precio-amaze">295.000€</a> </div> <div class="col-md-12 prop-info-amaze"> <!-- Camas/Baños/m² --> <div class="col-md-12 brokerage"> <!-- REF. 01241 --> </div>

Lo que pasaba:

Aplicábamos display: flex; flex-direction: column al card body para forzar apilamiento vertical. DevTools confirmaba que flex estaba activo. Pero la ubicación (“Sant Esteve Sesrovires”) y el precio (“295.000€”) se renderizaban en la misma línea visual, produciendo “295.000€rovires”.

Cards con nombres de ubicación cortos (“Martorell”, “Piera”) se veían bien porque el precio cubría completamente el texto. Solo nombres largos (“Sant Esteve Sesrovires”) revelaban el overlap.

Raíz del problema:

En un flex container con flex-direction: column, si hay cualquier restricción de altura (explícita o implícita), los flex items pueden encogerse (flex-shrink por defecto es 1). El <header> contenía 2 filas (~36px total), pero al competir con precio, features y ref por espacio vertical, el header se comprimía, y su segunda fila (ubicación) colapsaba en el espacio del precio.

El fix (2 líneas):

/* Header del card body: NUNCA se encoge */ .teamhost-listado .info-plus-amaze header { flex-shrink: 0 !important; /* ← LA CLAVE: no permitir que flexbox lo comprima */ height: auto !important; /* Tomar altura natural del contenido */ overflow: hidden !important; /* Clipear cualquier leak residual */ margin-bottom: 4px !important; /* Separación visual del precio */ }
7 Design Tokens — Variables CSS

Los design tokens son variables CSS definidas en teamhost-universal.css dentro del scope .teamhost-shortcode. Centralizan todos los valores de diseño para que cambiar un color o radio de borde se propague automáticamente a todos los componentes.

Colores

--hc-primary #24559D
--hc-accent #D57A1C
--hc-gold #EEC216
--hc-text #1a1a1a
--hc-text-light #6b7280
--hc-bg-card #ffffff

Espaciado & Formas

--hc-radius-card16px
--hc-radius-input8px
--hc-radius-tag6px
--hc-fontMontserrat, sans-serif
--hc-img-ratio4 / 3
--hc-shadow-card0 4px 20px rgba(0,0,0,0.15)
8 Arquitectura Híbrida — Ficha de Propiedad

La página de ficha (page-propiedad.php) implementa una arquitectura híbrida: los datos vienen de TeamHost (CRM), pero la UI la controlamos nosotros.

Flujo de Renderizado

  1. Extraer slug de la URL vía hc_get_property_slug_from_url()
  2. Determinar shortcode según Page ID (6 variantes: Venta/Alquiler/Vacacional × ES/CA, con temas KUBE o NORDIK)
  3. Forzar registro de shortcodes si el plugin no los registró (bug de strpos() posición 0 = falsy)
  4. Inyectar slug en $_GET['title'] + set_query_var('title', ...)
  5. Ejecutar shortcode vía do_shortcode()
  6. Restaurar estado de $_GET y query vars (no contaminar el request)
  7. Detectar redirect: si TeamHost devuelve window.location.href = slug no existe en CRM
  8. Extraer imágenes vía hc_extract_teamhost_images() para galería custom
  9. Renderizar: Galería Ken Burns (UI propia) + Detalle (HTML de TeamHost con overrides) + Similares

Mapa de Shortcodes por Página

Page IDShortcodeIdiomaTipo
3941[FVenta KUBE]EspañolVenta
3920[FAlquiler KUBE]EspañolAlquiler
124[FVenta NORDIK]CatalánVenda
923[FAlquiler NORDIK]CatalánLloguer
166[FAlquilerV KUBE]ES/CAVacacional
3939[FAlquilerV KUBE]ES/CAVacacional

KUBE vs NORDIK: Son temas visuales de TeamHost. Las páginas en español usan KUBE, las de catalán usan NORDIK. Configurado así por el administrador del CRM (Steven) desde wp-admin.

9 Estado del Plan — Fases

Fase 1: Aislamiento Core Completada

  • Inventario de assets TeamHost (SSH)
  • Extracción de CSS (7 archivos, 246KB raw)
  • Pipeline PostCSS de scoping (3,609 selectores)
  • Reescritura de asset management en functions.php
  • Detección de contexto TeamHost (3 capas)
  • Kill switch (HC_TEAMHOST_KILL)
  • Script de pipeline (teamhost-sync.sh)
  • Documentación (checklist + política)
  • Limpieza Home A/B (zonas duplicadas)

Fase A: Home En progreso

  • Fondo azul #24559D
  • Wrappers .teamhost-buscador/.listado
  • Cards: overlap resuelto (flex-shrink)
  • Galleria banner eliminado (server-side)
  • Split CSS monolítico en 3 archivos
  • Buscador: alineación vertical
  • ×Buscador: todos los filtros visibles
  • ×Paginación: no redirigir a /propiedades/
  • ×Contraste sobre fondo azul

Fases B & C Pendientes

  • Query var injection robusto
  • Redirect detection para slugs inválidos
  • NORDIK shortcodes (catalán)
  • Galería custom Ken Burns
  • ×Detalle TeamHost: styling HTML raw
  • ×Similares: cards consistentes
  • ×Mobile responsive ficha
  • ×FAlertas en contacto
10 Lecciones Aprendidas
#1
SCSS nesting sobre @import "archivo.css" no prefixa reglas internas. Al importar un CSS dentro de SCSS y envolverlo en un selector padre, el nesting solo aplica al import, no a las reglas dentro del archivo. Solución: usar PostCSS sobre CSS plano ya resuelto.
#2
contain: style layout no aísla cascade CSS entre frameworks. Esta propiedad CSS aísla layout y paint, pero NO impide que estilos heredados (cascade) crucen fronteras. No sirve como sandbox de estilos.
#3
all: revert-layer genera whack-a-mole. Intentar resetear todos los estilos con all: revert-layer causa que cada ajuste rompa otra cosa. Deuda técnica exponencial.
#4
Dequeue por handle es frágil ante updates del plugin. Si el plugin cambia nombres de handles en un update, nuestro dequeue falla silenciosamente. Complementar SIEMPRE con detección por patrón de URL (src).
#5
has_shortcode() no detecta shortcodes renderizados desde PHP. Solo revisa post_content (lo que el usuario escribe en el editor). Si el shortcode se llama vía do_shortcode() en un template PHP, has_shortcode() no lo ve.
#6
postcss-cli no ejecuta plugins correctamente. El CLI de PostCSS tenía problemas al cargar el plugin postcss-prefix-selector. Solución: usar la API directa de Node.js (scripts/scope-teamhost.cjs) en vez de npx postcss -c config.
#7
El plugin no tiene CSS locales — todo es remoto. Los assets vienen del CDN imediasystems.es, no de la carpeta del plugin en el servidor. Hay que descargar y congelar una copia local para poder procesarla.
#8
Bootstrap es 3.3.7, no 5. Bootstrap 3 usa data-toggle (sin prefijo bs-). Las estrategias de aislamiento para BS5 (data-bs-* namespace) no aplican aquí.
#9
Kill switch debe hacer dequeue incondicional de JS. La función de dequeue JS preserva scripts en páginas TeamHost. El kill switch necesita su propio loop de dequeue que ignore el contexto.
#10
postcss-prefix-selector exclude solo evita prefixar, no elimina reglas. Selectores bare como html, body, :root quedan en el output sin prefijar, contaminando Tailwind. Hay que eliminarlos en post-procesamiento AST.
#11
Bootstrap .col-md-12 tiene float: left; width: 100%. Causa overlap de siblings (título/precio/ubicación en cards). float: none !important no basta si hay reglas BS más específicas. Necesita combo: clear + display:block + position:static.
#12
Galleria “Fatal error” banner persiste a pesar de 3 capas de hide. Dequeue JS + inline CSS + override CSS no son suficientes. El error aparece ANTES de que CSS cargue y usa estilos inline. Solución: strip HTML server-side con DOMDocument.
#13
CSS overrides monolítico es inmanejable a 900+ líneas. Reglas de Home, Ficha y Alertas mezcladas causan side-effects cruzados. Split por contexto (3 archivos) elimina este problema.
#14
WordPress intercepta title como query var interno. get_query_var('title') no funciona para el slug de TeamHost. Hay que inyectar en $_GET['title'] directamente + restaurar después.
#15
TeamHost devuelve JS redirect cuando slug no existe en CRM. En vez de un error HTTP, devuelve <script>window.location.href="..."</script>. Hay que detectar y limpiar el output.
#16
Paginación usa <form action="/propiedades/"> hardcodeado. TeamHost genera el form con action apuntando a una página Divi legacy. Necesita intercepción (JS o PHP) para reescribir el action.
#17
Enfoque correcto: 80% CSS estructurado + 20% JS puntual. No intentar resolver todo con JS overrides ni con CSS global. CSS por contexto + JS solo para lo que CSS no puede (form action, DOM manipulation).
#18
flex-shrink: 0 es crítico en flex column con hijos que no deben comprimirse. Sin flex-shrink: 0, un flex item puede colapsar y superponerse visualmente con sus siblings. Especialmente problemático cuando Bootstrap aplica alturas/anchos que el flex container no espera. Siempre proteger elementos críticos con esta propiedad.
11 Mapa de Archivos
ArchivoTipoPropósito
functions.phpModificadoAsset management, strip galleries, extract images, parse property
templates/page-home.phpModificadoWrappers .teamhost-buscador/.listado, strip galleries, inline bg
templates/page-propiedad.phpModificadoArquitectura híbrida, query var injection, NORDIK/KUBE
assets/src/css/components/teamhost-universal.cssNuevoTokens, tipografía base, Galleria kill CSS
assets/src/css/components/teamhost-home-listing.cssNuevoBuscador, cards, tags, paginación, responsive
assets/src/css/components/teamhost-ficha.cssNuevoGallery hide, detalle, agente, condiciones
assets/dist/teamhost-scoped.cssGeneradoBundle scoped (11,138 líneas, automático)
assets/src/css/vendor/teamhost-raw.cssGeneradoConcatenado de 7 CSS remotos (input del pipeline)
scripts/scope-teamhost.cjsNuevoPipeline PostCSS de scoping
scripts/teamhost-sync.shNuevoScript de actualización del bundle
docs/TEAMHOST-REGRESSION-CHECKLIST.mdNuevoChecklist de regresión visual
docs/TEAMHOST-POLICY.mdNuevoPolítica de congelamiento para Steven
assets/src/css/components/teamhost-overrides.cssDeprecatedMonolítico original (896 líneas). YA NO se enqueue.
12 Glosario Técnico

CSS & Frameworks

ScopingPrefijar selectores CSS con una clase contenedora para limitar su alcance
SpecificitySistema de prioridad CSS: cuántas clases, IDs y elementos tiene un selector determina cuál gana
CascadeMecanismo por el cual CSS determina qué estilos aplican cuando hay conflictos
PostCSSHerramienta que transforma CSS con plugins JavaScript. Usamos postcss-prefix-selector
ASTAbstract Syntax Tree — representación en árbol del código parseado. Permite manipular CSS programmáticamente
Design TokensVariables CSS centralizadas (--nombre: valor) que definen colores, tamaños, radios, etc.
Tailwind CSSFramework CSS utility-first: clases como bg-blue-500 text-center p-4
BootstrapFramework CSS component-based: clases como .btn .col-md-6 .row
flex-shrinkPropiedad flexbox que controla cuánto puede encogerse un elemento. 0 = nunca se encoge

WordPress & PHP

ShortcodeTag tipo [BAmbos KUBE] que WordPress reemplaza con HTML generado por un plugin
wp_enqueueSistema de WordPress para cargar CSS/JS de forma ordenada con dependencias
wp_dequeueEliminar un CSS/JS previamente registrado por un plugin o tema
DOMDocumentParser HTML nativo de PHP. Más seguro que regex para manipular HTML
XPathLenguaje de consulta para buscar nodos en un árbol DOM (como SQL para HTML)
do_shortcode()Función PHP que ejecuta un shortcode y devuelve el HTML resultante
Template SlugIdentificador del archivo de template asignado a una página en WordPress
Query VarVariable que WordPress extrae de la URL para determinar qué contenido mostrar
13 Do’s & Don’ts — Protocolo Post-Implementación

El plugin TeamHost/Inmovilla se configura desde wp-admin → Plugin CRM Inmo, que tiene 6 pestañas: Home, Listado, Ficha, Buscadores, Códigos y Notas. Todos los settings se guardan en la tabla wp_options bajo la clave 'PluginInmovilla'. A continuación se clasifica cada acción por nivel de riesgo.

✓ SEGURO — Se puede cambiar sin afectar el tema

Estos cambios se procesan internamente por el plugin y no afectan nuestros overrides CSS porque no modifican la estructura HTML ni los selectores que usamos.

ConfiguraciónUbicación en wp-adminQué hace
Número de propiedades por sección Listado → Número de propiedades Controla cuántas propiedades se muestran por página (3, 6, 9 o 12). Solo cambia la cantidad de cards, no su estructura HTML.
Toggles de bloques Home
Destacadas, Nuevas, Exclusivas, Obra nueva, Ocasión
Home → Bloques ON/OFF Activa o desactiva secciones completas en la página de inicio del plugin. Nota: no afecta nuestra Home custom porque usamos [LAmbos KUBE] (listado general), no los bloques individuales.
Campos de información visible
Tipo, Ciudad, Zona, Habitaciones, Baños, m²
Home → Checkboxes de info
Ficha → Bloques de información
Controla qué datos aparecen en cada card. Puede agregar o quitar campos pero el HTML resultante usa las mismas clases CSS.
Toggles en Ficha
Mapa, Agentes, Similares, Imprimibles, Botones
Ficha → Toggles Activa/desactiva secciones de la ficha de propiedad. Si se desactiva “Similares”, el shortcode [Similares KUBE] simplemente no renderiza nada.
Tipo de mapa
Google Maps vs OpenStreetMap
Ficha → Mapa Cambia el proveedor de mapas. No afecta nuestro CSS.
API Key de Google Maps Ficha → API Key Google Configuración de API, no visual.
reCAPTCHA Keys Ficha → Formulario contacto Keys de seguridad. El badge de reCAPTCHA ya está oculto vía CSS inline.
Logos para PDF/Impresión Ficha → Imprimibles Solo afecta documentos generados (PDF, impresión), no la web.
Teléfono y email de imprimibles Ficha → Imprimibles Datos de contacto en documentos impresos.
URL de política de privacidad Ficha → Formulario Link en formularios de contacto.
Rangos de precio del buscador Listado → Buscador Rango Standard Define los rangos del slider de precio. Cambia valores de <option>, no selectores CSS.
Filtros de propiedades similares
Tipo, Ciudad, Rango de precio
Ficha → Similares Cambia la lógica de filtrado de propiedades similares, no el markup HTML.

⚠ PRECAUCIÓN — Avisar a HIXION antes de cambiar

Estos cambios pueden alterar la estructura HTML o las clases CSS que usa el plugin, lo que podría romper nuestros overrides visuales. Requieren verificación en staging antes de aplicar en producción.

ConfiguraciónUbicaciónPor qué es riesgosoQué hacer
Colores principales
color_web_principal
color_web_secundario
Home → Colores El plugin inyecta estos colores como variables CSS inline (--color-web-principal) y como <input type="hidden"> en el HTML. Nuestros overrides ya sobreescriben estos valores, pero un cambio drástico podría filtrar en elementos que no tenemos cubiertos. Cambiar en staging → verificar todas las páginas → reportar a HIXION si hay fugas de color
Color alternativo
color_web_alternativo
Home → Colores Usado como background en algunas secciones. Mismo riesgo que los colores principales. Verificar en staging
Altura de imágenes
rango_imagen_height (208-400px)
Home → Slider de altura Cambia la altura de las imágenes en cards. Nuestro CSS usa aspect-ratio: 4/3 y object-fit: cover que sobreescribe esto, pero podría causar conflictos si el plugin inyecta el valor como estilo inline. Verificar que aspect-ratio siga ganando
Radio de borde de botones
rango_button_border_css (0-200px)
Home → Slider de borde Se inyecta como estilo inline en botones. Nuestros overrides usan border-radius: var(--hc-radius-full) !important que debería ganar, pero es mejor verificar. Verificar visualmente en staging
Layout de título en ficha
radio_titulo_cabecera
Ficha → Cabecera Cambia qué campos aparecen en la cabecera de la ficha de propiedad (Tipo/Ciudad/Precio/Ref). Puede alterar el orden y cantidad de elementos HTML. Verificar que hc_parse_teamhost_property() siga extrayendo datos correctamente
Formato del formulario de contacto
Vertical vs Horizontal
Ficha → Formulario Cambia clases CSS del formulario. Nuestros overrides podrían no cubrir el layout alternativo. Verificar estilos del formulario en staging
Layout del buscador
Vertical vs Horizontal (por cada tipo)
Buscadores → Layout Cambia la estructura HTML del buscador. Nuestro CSS asume layout horizontal con display: flex en la fila. Un cambio a vertical rompería la alineación. Coordinar con HIXION — requiere ajuste de CSS overrides
Campos visibles en buscador Buscadores → Checkboxes Agregar o quitar campos del buscador cambia el número de columnas. Nuestro flex layout se adapta, pero podría necesitar ajuste de gap o padding. Verificar alineación visual en staging
URL personalizada de propiedad
custom_url_property
Ficha → URL Cambia la estructura de URLs de propiedades. Nuestra función hc_get_property_slug_from_url() parsea la URL — si cambia el formato, la extracción de slug falla y las fichas no cargan datos. Coordinación obligatoria con HIXION — requiere actualizar la función PHP

✗ PROHIBIDO — No cambiar sin autorización de HIXION

Estos cambios rompen la integración de forma inmediata. Requieren intervención técnica para restaurar el funcionamiento.

Acción ProhibidaQué se rompeCómo se recupera
Actualizar el plugin
WordPress → Actualizaciones
El plugin carga CSS/JS desde imediasystems.es. Una actualización puede cambiar los selectores CSS, agregar nuevos archivos, o modificar el HTML de los shortcodes. Nuestro bundle scoped (3,609 selectores) quedaría desfasado y los overrides podrían no matchear. Ejecutar pipeline completo: teamhost-sync.sh → verificar diff → ajustar overrides → staging → deploy
Cambiar el tema del shortcode
KUBE → NORDIK o viceversa
Los temas (KUBE, NORDIK, FLAVOR, etc.) generan HTML con clases CSS diferentes. Todos nuestros selectores asumen la estructura de KUBE (español) y NORDIK (catalán). Cambiar el tema de un shortcode invalida los overrides. Re-inspeccionar HTML → actualizar todos los selectores CSS → staging completo
Desactivar o reinstalar el plugin Los shortcodes dejan de renderizar. Las páginas Home, Ficha y Contacto quedan sin contenido de propiedades. La galería custom no tiene imágenes para extraer. Restaurar plugin desde backup en rescue-from-server/
Editar CSS del plugin desde wp-admin
Si existe un editor de CSS custom en el panel del plugin
El CSS custom se guarda en wp_options y se inyecta como <style> inline. Nuestro scoping de archivos NO atrapa estilos inline inyectados desde la base de datos. Pueden contaminar Tailwind. Identificar las reglas inline → agregar overrides específicos → considerar MutationObserver (Fase D del plan)
Cambiar los Page IDs de las páginas de propiedades
Borrar y recrear páginas en WP
El mapa de shortcodes en page-propiedad.php usa Page IDs hardcodeados (3941, 3920, 124, 923, 166, 3939). Si se cambian los IDs, la ficha no sabe qué shortcode ejecutar. Actualizar el array $ficha_shortcodes en page-propiedad.php
Agregar shortcodes nuevos en el contenido de páginas existentes Si se añaden shortcodes TeamHost dentro del editor de WordPress (no en nuestros templates PHP), se renderizan SIN wrappers .teamhost-shortcode y SIN hc_strip_legacy_galleries(). El HTML crudo de TeamHost con Bootstrap no-scoped contamina la página. Todos los shortcodes deben renderizarse exclusivamente desde los templates PHP con los wrappers correctos

Escenarios de Emergencia

E1
El sitio se ve roto después de un cambio en wp-admin Acción inmediata: Activar kill switch — agregar define('HC_TEAMHOST_KILL', true); en wp-config.php. Esto dequeue TODO (incluido nuestro CSS scoped), dejando los shortcodes sin estilo pero sin contaminar Tailwind. Luego contactar a HIXION para diagnosticar.
E2
TeamHost cambió algo en su CDN (imediasystems.es) Síntoma: Los estilos del plugin se ven diferentes aunque nadie tocó wp-admin. Esto sucede cuando TeamHost actualiza los CSS remotos.
Acción: Ejecutar scripts/teamhost-sync.sh para re-descargar, re-scopear y comparar el diff. Si hay cambios significativos en selectores, ajustar overrides.
E3
Se necesita agregar una nueva página con shortcodes de TeamHost Proceso: 1) Crear la página en WordPress con el template correcto. 2) Agregar wrappers .teamhost-shortcode en el template PHP. 3) Envolver el output de do_shortcode() con hc_strip_legacy_galleries(). 4) Si es un template nuevo, agregar su slug a hc_is_teamhost_context() y crear un CSS de overrides específico. NUNCA añadir shortcodes directamente en el editor de WordPress.
E4
Se quiere cambiar el diseño visual de las cards o el buscador Proceso: Modificar únicamente los archivos de Capa 2 o Capa 3 (teamhost-universal.css, teamhost-home-listing.css, teamhost-ficha.css). NUNCA tocar teamhost-scoped.css (es generado automáticamente). Para cambios de color, actualizar los design tokens en teamhost-universal.css.

Resumen Rápido

✓ SÍ SE PUEDE

  • Cambiar número de propiedades por página
  • Activar/desactivar bloques (Destacadas, Nuevas, etc.)
  • Modificar campos de información visible
  • Cambiar tipo de mapa (Google/OSM)
  • Actualizar API keys y logos de PDF
  • Modificar rangos de precio del buscador
  • Cambiar filtros de propiedades similares
  • Editar CSS de overrides (Capa 2 y 3)

✗ NO SE PUEDE

  • Actualizar el plugin sin pipeline completo
  • Cambiar temas de shortcode (KUBE/NORDIK)
  • Desactivar o reinstalar el plugin
  • Editar CSS custom desde el panel del plugin
  • Borrar/recrear páginas con IDs conocidos
  • Añadir shortcodes en el editor de WordPress
  • Cambiar estructura de URLs de propiedades
  • Editar teamhost-scoped.css manualmente

Protocolo Obligatorio ante Cualquier Cambio del Plugin

Cambio detectado
wp-admin, update, CDN
Ejecutar
teamhost-sync.sh
Comparar diff
selectores críticos
Staging
verificar visual
Producción

Si el staging falla: activar kill switch (HC_TEAMHOST_KILL) → diagnosticar → ajustar overrides → re-verificar. Si no se puede resolver: escalar formalmente a TeamHost solicitando opción de carga aislada de assets.