Lo que hizo falta para que CrocoBuilder y Tailwind se hablen
Hace unos dias conté aquí que el builder se comía mis clases de Tailwind al guardar. Hoy la web de mi agencia está montada encima de los dos, con variantes, opacidades y valores arbitrarios funcionando. Entre una cosa y otra hay cuatro arreglos, y ninguno estaba donde yo lo buscaba.
Uno. El saneador no se arregla por dentro.
Me pasé un rato leyendo el código del builder buscando un filtro donde engancharme. No lo hay: el método es privado y no dispara nada. La salida estaba fuera — sanitize_html_class es un filtro global de WordPress. Un add_filter de doce líneas y las variantes vuelven intactas. La lección, que me la aplico a mí: cuando no encuentres el gancho dentro de un plugin, mira si lo que hace por
dentro es en realidad una función de WordPress.
Dos. Que la clase sobreviva no significa que exista.
Con el saneador arreglado, la página seguía saliendo a medio estilar. WindPress trae diecisiete integraciones —Bricks, Oxygen, Elementor, Gutenberg…— y ninguna es CrocoBuilder. El compilador buscaba clases donde el builder no guarda nada: CrocoBuilder no escribe en post_content, reparte en un meta y dos tablas propias. Sin decirle dónde mirar, compilaba un CSS impecable y vacío.
Tres. El que gana no es el más específico, es el que no está en una capa.
Este me tuvo un rato. El builder emite esto:
:where(.crocoblocks-document .cb-el) { box-sizing: border-box; max-width: 100% }
Especificidad cero, escrito a propósito para no estorbar. Y aun así se llevaba por delante cualquier max-w-* y hasta el contenedor de mi design system. Porque las utilidades de Tailwind viven en @layer utilities, y en la cascada lo que no está en ninguna capa gana siempre a lo que sí lo está, da igual la especificidad. La solución no es pelear con selectores: es meter la hoja del builder en su propia capa y ponerla la primera.
Cuatro. Recompilar al guardar no es un hook de PHP.
Buscando cómo automatizarlo descubrí que la función existe para media docena de builders y no es lo que yo pensaba: la página del builder publica un mensaje en un BroadcastChannel y la app de WindPress lo recoge y compila. Treinta líneas para replicarlo. El compilador es JavaScript y corre en el navegador, así que sigue haciendo falta tener WindPress abierto — pero eso vale igual para todos los demás.
Y una propina que no buscaba.
Mirando por qué se me caían la mitad de los modificadores del sistema de diseño, encontré esto: los identificadores de las clases globales se generan con random_int, y la consulta que las lee no lleva ORDER BY. O sea que el orden en que salen al CSS es, literalmente, aleatorio. Un modificador BEM funciona o no funciona según qué número le tocó al crearlo. En mi sistema había quince muertos. Reportado, con reproducción.
Lo que me llevo, y es lo que quería contaros: ninguno de los cuatro fallos está dentro de CrocoBuilder ni dentro de WindPress. Los dos son buenos y hacen bien lo suyo. Los fallos están en la frontera — el saneado al guardar, dónde busca el compilador, en qué capa cae el CSS, cómo se avisan entre sí. Y en la frontera no mira nadie, porque no es de nadie.
Por eso creo que este trabajo vale la pena aunque sea tedioso: las integraciones no se rompen por el centro, se rompen por los bordes, y los bordes solo se ven cuando alguien pone las dos herramientas juntas en un sitio de verdad y aguanta hasta el final.