Un plugin de terceros con vulnerabilidades sin parchear te obliga a elegir entre esperar al proveedor y escribir tú lo que hacía. Yo escribí lo que hacía. Los widgets de las webs de Libelium e iris360 vivían en plugins ajenos, y hoy son 59 widgets propios de Elementor. El caso completo de Libelium e iris360 lo resume en un apartado. Aquí cuento qué ganas, qué pagas y por qué el riesgo no desaparece.
El casero y el inquilino
Vivir de alquiler significa que, si se rompe la caldera, esperas a que el casero mande a alguien. Comprar el piso significa que la caldera es tuya, con su reparación, su factura y su madrugada sin agua caliente. Ninguna de las dos opciones elimina la caldera. Solo cambia quién responde cuando falla.
De qué plugins me deshice
El 22 de septiembre audité en modo lectura los 29 plugins activos del servidor de producción. El plan retiraba ocho. Cinco eran de widgets, dos de SEO y uno de campos personalizados. Hablo de plan porque ningún registro que conserve confirma que los ocho estén desinstalados en producción.
Lo que sí hice fue sustituir la funcionalidad. Los widgets de imagen dinámica, acordeones, tablas y sliders pasaron a widgets propios. Los tipos de contenido y campos personalizados pasaron a código con los mismos nombres y formatos, y el motor de SEO propio genera ya el llms.txtGlosariollms.txtArchivo de texto en la raíz de un sitio que ofrece a los modelos de lenguaje un índice resumido de sus páginas más relevantes.
Funciona como un mapa legible por IA, comparable a un sitemap pensado para asistentes. Un generador propio puede construirlo a partir del modelo de contenido del sitio en lugar de mantenerlo a mano. Más detalle en WebMCP y llms.txt.Ver término completo → y el JSON-LDGlosarioJSON-LDFormato de datos estructurados basado en JSON que describe el contenido de una página con el vocabulario de Schema.org.
Se inserta en un bloque <script type="application/ld+json"> del HTML. Buscadores y asistentes de IA lo leen para identificar entidades como un producto, un artículo o una ruta de navegación sin interpretar el diseño de la página.Ver término completo →. Sigo dependiendo de Elementor y Elementor Pro, que no se van. La diferencia es que antes dependía de media docena de plugins y ahora de uno, y de una parte mucho más pequeña de su superficie.
Queda un acoplamiento que no tenía anotado. El generador de llms.txt todavía lee la descripción que escribía el plugin de SEO anterior. El plugin puede irse y sus datos se quedan.
Las reglas que me impuse
Una biblioteca propia sin reglas se convierte en otro plugin opaco, solo que tuyo. Por eso escribí un estándar antes de seguir añadiendo widgets, y es el mismo que lee a diario el agente de IA con el que trabajo, como cuento en programar con un agente de IA.
Cada widget extiende la clase base de Elementor, y ningún contenido de negocio va fijo en el código. Los textos, las listas y los iconos se editan desde el panel. Los colores, radios y sombras salen de variables de diseño con valor de reserva, y desde que refactoricé 28 módulos para leer la variable de color de marca, el mismo widget sirve a las dos marcas. Cada widget tiene además su propia hoja de estilos.
Una sola copia de los 59 widgets vive en el monorepo, como conté en WordPress en monorepo en vez de multisite.
Una advertencia. Ninguna prueba automática verifica la regla del contenido fijo. Solo comprueba que el PHP compila. La regla la sostienen la revisión y el texto escrito, y algunos incumplimientos los encontré después.
Migrar 355 páginas sin romper ninguna
Cambiar de plugin es fácil. Lo caro es el contenido que ya usa los widgets viejos. 126 widgets repartidos en 355 entradas llevaban marcado propio del plugin, y sin él esos bloques desaparecían de la página.
Al principio pensé en migrarlos landing a landing. Acabé haciendo lo contrario. Analicé en solo lectura, probé con una entrada, volqué la base de datos del servidor a un entorno local y ensayé allí el orden completo. No ensayé en el servidor porque el plugin de medios podía escribir en el almacenamiento real.
El barrido final dio 685 respuestas correctas, sin errores fatales ni referencias al plugin antiguo, y un día después seguían sin aparecer widgets viejos ni revisiones antiguas. La limpieza borra de forma definitiva, así que esperó a mi confirmación expresa. Las cuatro entradas eliminadas se recuperan desde la copia de contenido, y las 13.183 revisiones anteriores a agosto solo viven en un volcado que guardé en local antes de empezar.
El ensayo pagó solo. Una página de selección de producto seguía sirviendo el selector del plugin antiguo desde la caché de render de Elementor. Sin ensayo lo habría descubierto en producción, y por eso añadí al orden el vaciado de esa caché.
Dos cosas salieron mal. Los scripts de migración quedaron en una carpeta temporal fuera de git, así que si hay que repetir la operación no existe un comando versionado que la haga. Y cinco entradas rezagadas con imágenes dinámicas del plugin antiguo aparecieron el 7 de octubre y las convertí con otro script.
Lo que pagas por tener el código
Un código propio se puede leer, versionar y corregir sin esperar a nadie. También hay que corregirlo, y me tocó pronto. El 23 de septiembre audité la tipografía de los 51 widgets de entonces y 14 tenían secciones de estilo sin ningún control de tipografía, con lo que esos textos no admitían ajuste alguno. Uno traía además el tamaño y la familia de fuente escritos en línea, el único caso que violaba mi propia regla.
Ese mismo día apareció un widget con dos juegos de controles que pisaban las mismas propiedades según el orden de registro. Para fijar la tipografía global de un badge tuve que actualizar los ajustes guardados de 230 widgets en 32 entradas, porque cada entrada guarda sus ajustes y algunos ya estaban desvinculados del valor global. Y el 6 de octubre quité de dos páginas unas etiquetas de ejemplo que un widget rellenaba cuando el campo quedaba vacío. Un valor por defecto cómodo para quien programa acaba filtrándose a la página pública.
- ✕Vulnerabilidades sin parche. Varios plugins las acumulaban y el plan los retiraba por eso.
- ✕Código sin suma pública que verificar. La comprobación de checksums de WP-CLI no cubre los plugins comerciales.
- ✕Marcado propio dentro del contenido. Sin el plugin, esos bloques desaparecían de la página.
- ✓Código auditable. Pago la revisión, y me tocó auditar yo mismo la tipografía.
- ✓Una copia para dos marcas. Un cambio de variable sirve a las dos webs. Un error también llega a las dos.
- ✓Parches a mi ritmo. Corrijo cuando lo detecto. Pago que la detección dependa de mi revisión.
Lo que no he medido
No sé si los widgets propios cargan más rápido o más lento que los anteriores, porque no los comparé sobre la misma página. Tampoco registré cuánto tiempo lleva mantener la biblioteca ni cuántas correcciones por semana exige, ni repetí un análisis de vulnerabilidades sobre la web nueva. Lo único que puedo afirmar es el cambio de riesgo. Antes dependía de que un proveedor publicara parches. Ahora dependo de que yo detecte y corrija defectos en 59 widgets.
Qué me llevo
Sustituir una dependencia por código propio no elimina el riesgo. Lo traslada a quien escribe el código, y si ese eres tú, el coste real es tu atención sostenida. Antes de hacerlo, pregúntate si vas a mantener una revisión periódica, no solo si sabes escribir el widget. Si la respuesta es no, quizá te convenga más un plugin ajeno bien vigilado que uno propio abandonado. El criterio general, sin los datos de este caso, está en la lección código propio frente a dependencias de terceros en WordPress.