= 3.1.0 =
* "Custom PHP" renombrado a "Custom Code" y ampliado para soportar CSS y JS además de PHP. Motivo: el agente necesitaba poder ajustar CSS/JS de secciones del sitio que no son landings/componentes de Editor IA (theme, páginas nativas, WooCommerce, otros plugins) sin tocar `functions.php` ni el Customizer — el modo `global` de PHP ya resolvía esto para hooks, faltaba el equivalente para estilos y scripts. Alineado con el modelo del plugin de referencia (Woody Code Snippets / Insert PHP): tipo de snippet (PHP/CSS/JS) + modo de ejecución ("shortcode" o "global").
* Nuevo campo `type` (`php`|`css`|`js`) en el CPT interno `eia_php_snippet` (se mantiene el nombre interno del CPT para no romper snippets PHP ya guardados en sitios existentes — ausencia del campo se interpreta como `php`, cero cambio de comportamiento sobre datos previos).
* CSS global se inyecta en `wp_head` (prioridad 100, después del CSS del theme/plugins); JS global se inyecta en `wp_footer` (prioridad 100). Nuevos shortcodes `[eia_css id="X"]` y `[eia_js id="X"]` para el modo puntual — `[eia_php id="X"]` sigue funcionando exactamente igual que antes (sin cambios de comportamiento, compatibilidad total con landings publicadas que ya lo usan).
* Validación de CSS/JS: al no ejecutarse (no hay `eval`), solo se rechaza código que rompa la etiqueta que lo envuelve (`</style` o `</script` literal) — incluir código PHP inseguro sigue bloqueado (funciones prohibidas + validación de sintaxis), sin cambios.
* Archivo renombrado `includes/class-editor-ia-custom-php.php` → `includes/class-editor-ia-custom-code.php`, clase `Editor_IA_Custom_PHP` → `Editor_IA_Custom_Code`.
* REST: nuevo namespace `/wp-json/editor-ia/v1/custom-code` (con campo `type` en el body y filtro `?type=` en el listado) — reemplaza a `/custom-php`, que se retira sin alias (el agente redescubre la API en vivo vía `GET /info`/`tools/list` en cada sesión, ningún `landing.html` depende de esta ruta).
* MCP: abilities `editor-ia/list-custom-php`, `get-custom-php`, `create-custom-php`, `update-custom-php`, `delete-custom-php` renombradas a `...-custom-code`, con parámetro `type` agregado en `create`/`update`.
* Admin: menú "Custom PHP" renombrado a "Custom Code" (slug de página `editor-ia-custom-code`), nuevo selector de Tipo (PHP/CSS/JS) con CodeMirror que cambia de modo según el tipo, nueva columna "Tipo" en la lista de snippets guardados.
* `GET /info` (`discover()`): bloque "Custom PHP snippets" reemplazado por "Custom Code snippets (PHP/CSS/JS)", documentados `type` y los 3 shortcodes.
* Admin de Custom Code reorganizado en pestañas (`nav-tab-wrapper`, mismo patrón nativo que usan las pantallas de Ajustes de WP): "Nuevo/Editar snippet" y "Snippets guardados (N)". Guardar o eliminar redirige automáticamente a la pestaña de guardados (además evita el reenvío del formulario al recargar la página); "Editar" desde la lista lleva directo a la pestaña del formulario con los datos cargados.

= 3.0.21 =
* Fix: la admin bar de WordPress tapaba la franja superior del header (sticky, `top: 0`) de landings y componentes al hacer scroll estando logueado como administrador — reportado por un usuario del plugin. WordPress empuja el documento hacia abajo al cargar la página, pero un elemento sticky/fixed ignora ese margen al pegarse durante el scroll y vuelve a pegarse al borde real del viewport, donde vive la admin bar (fixed, por encima de todo). Nuevo `Editor_IA_Renderer::inject_admin_bar_offset()`: cuando `is_admin_bar_showing()`, inyecta CSS que fuerza `top: 32px` (46px en móvil, breakpoint 782px) en el tag `<header>` — se apunta al tag semántico en vez de a una clase por proyecto porque el skill `design` exige `<header>` en todo header de landing. Hookeado en los tres puntos de render: modo full, modo integrado (antes de `get_header()`) y componente global inyectado en páginas nativas.

= 3.0.20 =
* Removido por completo el módulo "Skills para Elementor" (conversión de landings a widgets nativos de Elementor, fusionado en v3.0.0). Motivo: comparado contra el alcance real del proyecto de referencia (emcp-tools), nuestra implementación no tenía edición granular por elemento (`update-element`/`update-widget` con merge parcial) — todo pasaba por reescribir el árbol completo vía `set-test-page-data` más un ciclo obligatorio de página-de-test + aprobación + swap, demasiado pesado incluso para un cambio de un texto o una imagen. Para la etapa de lanzamiento se decidió sacarlo y evaluar más adelante si vale la pena una integración más liviana, puntual a una necesidad real.
* Borrados: `includes/class-editor-ia-elementor-assets.php`, `includes/class-editor-ia-elementor-widget-catalog.php`, `includes/class-editor-ia-elementor-data.php`, `includes/class-editor-ia-elementor-test-page.php`, `includes/class-editor-ia-elementor-abilities.php`.
* Editados (se les quitó solo la parte de Elementor): `editor-ia.php` (define de la opción de página de test, requires, registro de assets), `includes/class-editor-ia-mcp.php` (hooks de abilities/categoría, caché del cerebro de Elementor, concatenación en `instructions`), `includes/class-editor-ia-settings.php` (bloques del generador de `AJUSTES_MCP.md`), `includes/class-editor-ia-rest.php` y `includes/class-editor-ia-abilities.php` (descripciones).
* Se mantiene, igual que con WooCommerce/Astra, solo el dato informativo de si Elementor está instalado y activo en el sitio (`GET /info`, `AJUSTES_MCP.md`) — sin mencionar tools ni flujos que ya no existen.
* Respaldo completo del código removido en `backups/v3.0.19-pre-elementor-removal/` del repo, y el skill de cerebro-api (`producto=elementor`) queda desactivado (no borrado) en el servidor central — ver `cerebro/elementor-cerebro/` para el respaldo local del `.md`.

= 3.0.19 =
* AJUSTES_MCP.md: nuevo paso 0 en "Pasos recomendados para empezar" — antes, escribir la entrada de `.mcp.json` (el puente local para clientes stdio-only: Claude Desktop, Cursor, Windsurf, Antigravity) solo aparecía como una sección aparte más abajo ("si te toca escribir esta entrada vos mismo"), sin ningún paso explícito en el flujo numerado que le dijera al agente cuándo le toca. Ahora es el paso 0, con el criterio de decisión (¿tu cliente soporta HTTP remoto directo? si no, generá el archivo antes de intentar conectarte).

= 3.0.18 =
* GET /info: reestructurado para que el servidor MCP sea la opción prominente y no una fila más entre ~30 endpoints REST. Antes `/info` devolvía el catálogo completo de endpoints REST (con method/path/body/returns de cada uno, autosuficiente para operar el plugin) en el mismo nivel que la recomendación de MCP — un agente que ya tenía todo lo que necesitaba en REST no tenía ningún incentivo real para hacer el handshake MCP y leer las instructions/skills. Nueva clave `servidor_mcp` (antes `instrucciones_agente`) va primero en la respuesta con endpoint, cómo arrancar la sesión y por qué conviene; el catálogo REST pasa a `endpoints_fallback_rest` (antes `endpoints`) con una nota explícita de que es fallback para entornos que no pueden hacer POST JSON-RPC. Ningún endpoint cambia de comportamiento, solo la forma en que `/info` los presenta.

= 3.0.17 =
* Ajustes: nuevo link "Ajustes" en Plugins → Editor IA (junto a "Desactivar"), antes inexistente — WordPress no lo agrega solo, hay que registrarlo explícitamente vía `plugin_action_links_{basename}`. Nuevo `Editor_IA_Settings::add_settings_link()`, aparece primero en la fila (antes de "Desactivar") como es convención en WordPress.

= 3.0.16 =
* Fix: AJUSTES_MCP.md generaba una entrada de `.mcp.json` con el paquete `@modelcontextprotocol/server-http-sse`, que no existe en npm (verificado en el registro) — cualquier cliente stdio-only (Claude Desktop, Cursor, Windsurf) que dependiera de ese puente para conectar fallaba en el primer intento. Reemplazado por `@automattic/mcp-wordpress-remote` (paquete real, mantenido por Automattic, mismo modelo de auth por usuario+Application Password vía `WP_API_URL`/`WP_API_USERNAME`/`WP_API_PASSWORD`) — encontrado comparando contra la config de ejemplo que Astra/Automattic entrega para su propio MCP.
* AJUSTES_MCP.md: nueva guía corta antes del handshake para cuando el agente tiene que escribir esa entrada en el config file del cliente del usuario — confirmar la ubicación real del archivo en vez de asumirla, sumar sin pisar otras entradas de `mcpServers`/`servers`, y detectar la versión de Node y el `PATH` real del usuario antes de fijarlos en el JSON (los clientes de escritorio no heredan el PATH de la shell). Redactada en el mismo tono de sugerencia práctica que el resto del archivo, no como orden.

= 3.0.15 =
* Fix: Ajustes: el link "Probar conexión con los skills" volvió a mostrarse siempre que las Instrucciones del agente están activas, aunque todavía no estén verificadas. La v3.0.14 lo había dejado oculto hasta `is_verified()`, pero ese mismo link es el único botón que dispara `Editor_IA_MCP::test_connection()` — el método pensado justo para diagnosticar por qué la verificación no avanza (firewall del hosting, key bloqueada). Resultado real reportado por un usuario: activó el interruptor, esperó varios minutos, refrescó la página y quedó sin ninguna acción disponible más que esperar a que un agente se conectara solo. Ahora la Key y el link se muestran de entrada; mientras no esté verificado se agrega un texto corto explicando que la primera verificación tarda y qué la dispara (conexión de un agente, o el propio link).
* Ajustes: el aviso "Application Passwords no disponibles en este sitio" pasa de texto en cursiva sin estilo a un cuadro con fondo rojo claro y sombra suave, para que se note como advertencia real en vez de leerse como una nota al pie.

= 3.0.14 =
* Ajustes: la Key de MCP Server y el link "Probar conexión con los skills" ya no se muestran apenas se activan las Instrucciones del agente — quedan ocultos hasta que el cerebro central confirme la primera verificación real (key-proof del dominio exitoso). Antes se mostraban de inmediato aunque la instalación nunca hubiera llegado a verificarse, lo que confundía en el primer uso (se veía un aviso de error justo al lado de una key y un link que parecían "listos para usar"). Nueva opción local `editor_ia_installation_verified`, marcada por `Editor_IA_Settings::mark_verified()` en cuanto llega una respuesta 200 real del cerebro central (`Editor_IA_MCP::get_cerebro_nucleo()` o el botón "Probar conexión"), persiste entre activar/desactivar porque la verificación es sobre la key+dominio, no sobre el interruptor.
* Fix: `Editor_IA_Settings::app_passwords_available()` usaba `WP_Application_Passwords::is_in_use()` (WP core: solo indica si el sitio *alguna vez* creó una Application Password, no si están disponibles ahora) en vez de `wp_is_application_passwords_available()` (la función correcta, que sí refleja HTTPS + el filtro que usan plugins de seguridad como Wordfence para desactivarlas). Encontrado diagnosticando un caso real: un sitio con Application Passwords bloqueadas por Wordfence seguía mostrando el botón "Generar acceso para agentes" como si funcionara.
* Ajustes: mensaje de "Application Passwords no disponibles" reescrito para apuntar a la causa más común (un plugin de seguridad/firewall tipo Wordfence o iThemes Security desactivándolas — sugiere buscar una opción "Disable Application Passwords" en su firewall), dejando HTTPS como causa secundaria. Antes solo mencionaba HTTPS, lo cual llevaba a buscar en el lugar equivocado.

= 3.0.13 =
* MCP Adapter: migrado de copia manual embebida (lib/mcp-adapter/, guard class_exists simple) a dependencia Composer + Jetpack Autoloader (vendor/, entrypoint vendor/autoload_packages.php). Es el mecanismo que WordPress/mcp-adapter documenta oficialmente para evitar choques de versión cuando varios plugins activos empaquetan la misma librería (hoy WooCommerce trae su propia copia 0.1.0): entre todas las copias que también usen Jetpack Autoloader, deja viva solo la más nueva automáticamente, en vez de depender de qué plugin cargó primero. No cambia ningún comportamiento del servidor MCP propio (`editor-ia/v1/mcp`) ni de las tools — es solo el mecanismo de carga de la librería base. Los compat shims existentes para WooCommerce (metadata duplicada raíz+mcp.*, abilities de resources sin input_schema, cerebro como `instructions` a nivel de servidor) se mantienen sin cambios como red de seguridad para el caso en que la copia de un tercero no use Jetpack Autoloader.

= 3.0.12 =
* Ajustes: eliminada la fila informativa "Skills para Elementor" de la tabla de "Instrucciones del agente". Desde la v3.0.9 las tools `facilwp-elementor/*` ya se activan solo por detección de Elementor (sin ningún interruptor humano), así que ese texto de solo lectura no aportaba ninguna acción posible al usuario — solo ocupaba espacio en la pantalla. El comportamiento no cambia: si Elementor está instalado, las tools siguen disponibles automáticamente en `tools/list`.

= 3.0.11 =
* AJUSTES_MCP.md: quitados los emojis decorativos de los 7 encabezados de sección (🔴🤖🔌🧩🛒🎨🌐). No cumplían ninguna función real para el agente que procesa el archivo — solo adorno visual para un lector humano — y el usuario prefiere texto plano en todo el código y documentación del proyecto. Mismo criterio aplicado al cerebro (nucleo, imagenes, condiciones — desplegado como skill v4.23).

= 3.0.10 =
* AJUSTES_MCP.md: nueva nota en "Contexto para el Agente" para cuando el usuario le da al agente acceso FTP/SFTP/SSH directo al sitio (aparte de la conexión MCP): ese acceso no tiene el sistema de revisiones del plugin, así que el agente debe guardar su propio respaldo local versionado antes de tocar un archivo por ese canal. El detalle completo vive en el cerebro de Editor IA (nueva sección "Acceso directo por FTP/SFTP/SSH", desplegada en el cerebro v4.22) — este archivo solo apunta ahí. Pensado para el caso frecuente de que el usuario se olvide de darle esta instrucción a su agente.

= 3.0.9 =
* Skills para Elementor: eliminado el checkbox "¿Deseas trabajar también con Elementor?" de Ajustes. Las tools `facilwp-elementor/*` ahora se activan 100% por detección (Elementor instalado = tools disponibles en `tools/list` automáticamente), mismo criterio que ya se usaba para Astra y WooCommerce — sin ningún interruptor humano de por medio. Instalaciones que antes tenían el checkbox desactivado ahora tienen las tools disponibles automáticamente si Elementor sigue instalado (cambio de comportamiento intencional).
* `GET /info`, la ability `editor-ia/get-info` y `AJUSTES_MCP.md` ya no mencionan un estado "activado/desactivado" para Elementor — solo "instalado" o "no instalado", y refuerzan que el sistema HTML/CSS/JS propio de Editor IA sigue siendo la prioridad por defecto: las tools de Elementor son para el flujo de conversión a JSON nativo (página de test + swap), a usar solo cuando el usuario lo pide explícitamente.
* Ajustes: la fila "Skills para Elementor" pasa a ser un texto informativo de solo lectura (cuando Elementor está instalado) en vez de un checkbox/estado activable.
* Eliminados `Editor_IA_Settings::OPTION_ELEMENTOR_ACTIVE` y `elementor_skill_active()` (reemplazado en todos sus usos por `elementor_plugin_detected()`).

= 3.0.8 =
* El archivo de credenciales/conexión que genera Ajustes se renombra de AGENTS.md a AJUSTES_MCP.md. Motivo: AGENTS.md es un nombre estándar que muchos agentes cargan automáticamente como instrucciones de sistema, lo que hacía que agentes con entrenamiento de seguridad lo trataran como intento de prompt injection; como AJUSTES_MCP.md el agente lo lee como documentación de configuración (el usuario se lo pide leer al empezar) en vez de auto-inyectarlo.
* AJUSTES_MCP.md (ex AGENTS.md): reescritura del encuadre para que los agentes con entrenamiento de seguridad (Claude, etc.) no lo confundan con un intento de prompt injection. Se elimina el título "System Prompt Bootstrap", la exigencia de "incorporar directivas obligatorias antes de cualquier acción" y la mención a operar "de forma autónoma" — exactamente las frases que disparaban la alarma en agentes reales. En su lugar: nota de procedencia al inicio (el archivo lo genera y coloca el propio administrador del sitio), el campo `instructions` del initialize se presenta como documentación técnica de referencia (estilo README) y se declara explícitamente que las instrucciones del usuario del agente siempre tienen prioridad sobre lo que devuelva el servidor. Mismo contenido operativo, cero pérdida de funcionalidad.

= 3.0.7 =
* Fix: rutas relativas `assets/logo.png` (en `<img src=`, `href=` o `url()` de CSS) ahora se reescriben a la URL absoluta del proyecto al renderizar. Antes se rompían en silencio porque una landing, header/footer de componente o CSS inline nunca se sirve desde su propia carpeta — resolvían contra la URL pública de destino en vez de contra `wp-content/uploads/editor-ia/projects/{slug}/assets/`. Encontrado auditando una landing real: la imagen del hero nunca cargaba en producción pese a que la API devolvía 200 al guardarla. Nuevo método `Editor_IA_Renderer::rewrite_asset_urls()`.

= 3.0.6 =
* Header del plugin: declara `Requires at least: 6.9` (WordPress) y `Requires PHP: 8.0` — antes no declaraba ninguno de los dos, así que WordPress no podía avisar si un sitio no cumplía los requisitos (mostraba "-" en la pantalla de actualización). WP 6.9 es requisito real para que la Abilities API (y por lo tanto el servidor MCP) se registre; PHP 8.0 es un piso moderno razonable — el código en sí no usa sintaxis exclusiva de 8.x, pero PHP 7.4 lleva sin soporte de seguridad desde 2022.

= 3.0.5 =
* `GET /info` y la ability `editor-ia/get-info` ahora reportan Elementor (instalado, versión, si "Skills para Elementor" está activo) y Astra (si expone su propio servidor MCP en `/wp-json/astra/v1/mcp`) dentro de `environment` — antes ninguno de los dos aparecía ahí, solo WooCommerce y el theme genérico.
* AGENTS.md: nueva sección "Estado de integraciones detectadas" (Elementor, WooCommerce, Astra) que siempre se imprime con el estado real al momento de generar el archivo — antes la mención a Elementor solo aparecía si el toggle estaba activo en ese instante, así que un archivo descargado antes de activarlo quedaba sin mencionarlo nunca, aunque el agente lo leyera después de activado.
* AGENTS.md: nueva sección "Regla de oro" al inicio del archivo que obliga a llamar `tools/list`/`resources/list` completos antes de asumir qué hay disponible, en vez de conformarse con el resumen de este archivo o de las `instructions` del handshake — pensado para agentes con modelos económicos/flash.
* Nuevo método `Editor_IA_Settings::astra_active()`.

= 3.0.4 =
* Ajustes: actualización de terminología en la pantalla de Ajustes (api gratuita -> MCP Server gratuito, Editor IA WP -> Editor IA FacilWP, Api key de Instalación -> Key de MCP Server, dirección de la API -> MCP Server).

= 3.0.3 =
* Ajustes: un solo botón para Skills para Agentes/Elementor en vez de dos. Al conectar Skills para Agentes aparece un checkbox opcional "¿Deseas trabajar también con Elementor?" (solo si Elementor está instalado), con el mismo patrón que el checkbox de WooCommerce en Accesos para agentes; se apaga junto con todo al desactivar. Eliminado el botón/handler separado "Activar/Desactivar Skills para Elementor". Cuando ya está activo, el estado de Elementor se muestra como texto de solo lectura junto a la Api key.

= 3.0.2 =
* Handshake initialize del MCP y GET /info ahora entregan `design_contract_filename`: el nombre ya calculado (design-{dominio-sanitizado}.md) para el contrato visual del skill `design`, para que el agente nunca tenga que derivar/sanitizar el dominio por su cuenta (evita inconsistencias entre sesiones con modelos económicos/flash). Nuevos métodos `Editor_IA_Mcp::sanitized_domain()` y `Editor_IA_Mcp::design_contract_filename()`.

= 3.0.1 =
* Skills para Elementor: el CSS (y JS opcional) del proyecto de origen ahora se guarda y se sirve de forma automática — nunca dentro del JSON de Elementor ni en el "CSS adicional" de Elementor/Customizer. Nuevos parámetros `css`/`js` en `facilwp-elementor/set-test-page-data`, guardados en `uploads/editor-ia/elementor/{post_id}/` (nueva clase `Editor_IA_Elementor_Assets`) y enganchados vía `wp_enqueue_style()`/`wp_enqueue_script()` automáticamente en la página real cuando corresponde.
* `swap-to-live` copia el CSS/JS aprobado a la página real como snapshot (igual criterio que el JSON: se congela al momento del swap, no sigue al proyecto de origen si este cambia después); `undo-last-swap` restaura el CSS/JS anterior de esa página, con el contenido real guardado (no solo el nombre de archivo, para que un swap posterior no imposibilite deshacer el anterior).
* `get-page-data` ahora también devuelve `css`/`js` de la página consultada, para que el agente pueda verificar lo que quedó guardado.

= 3.0.0 =
* Fusión: Elementor Skills FacilWP deja de ser un plugin standalone y se absorbe como módulo interno de Editor IA. Un solo servidor MCP (editor-ia/v1/mcp) en vez de dos — las tools facilwp-elementor/* (list-widgets, get-test-page, set-test-page-data, get-page-data, swap-to-live, undo-last-swap) ahora viven en el mismo endpoint, gateadas por un toggle nuevo en Ajustes ("Skills para Elementor") que solo se muestra si Elementor está instalado.
* El campo "instructions" del handshake initialize concatena el cerebro de Editor IA con el de Elementor cuando el toggle está activo — ya no hace falta conectarse a un segundo servidor MCP para tener ambos cerebros.
* Simplifica la generación de AGENTS.md: ya no documenta un endpoint MCP separado para Elementor.
* Migración automática: si el sitio ya tenía una página de test creada por el plugin standalone, se adopta su post_id (no se crea una duplicada).
* El plugin standalone Elementor Skills FacilWP queda deprecado (ver su propio CHANGELOG.txt) — no requiere acción del usuario, simplemente se desactiva.
* Se documenta/commitea (ya estaba desplegado en el servidor sin registrar) el adaptador de supresión limpia de header/footer para el theme propio `lienzo-editor-ia` en `class-editor-ia-theme-compat.php`: en vez de remover hooks (como el caso Astra), activa los filtros `lienzo_editor_ia_hide_header`/`lienzo_editor_ia_hide_footer` que el theme ya consulta en su `header.php`/`footer.php`.

= 2.9.6 =
* Corrección de nombre: el plugin de Elementor se llama "Elementor Skills FacilWP" (con S), no "Elementor Skill FacilWP". Corregido en los textos de Ajustes (checkbox y encabezado del bloque MCP en AGENTS.md).

= 2.9.5 =
* Ajustes: se simplifica el texto del checkbox de Elementor Skill FacilWP, quitando la aclaración "(reusa el mismo acceso generado arriba)" que quedaba redundante en la UI.

= 2.9.4 =
* Ajustes: si el plugin Elementor Skill FacilWP está activo, aparece un checkbox nuevo (debajo del de WooCommerce) para incluir su servidor MCP en el AGENTS.md generado — reusa la misma Application Password ya creada, sin credenciales propias. Nuevo método Editor_IA_Settings::elementor_skill_facilwp_active().

= 2.9.3 =
* Ajustes UI: el botón para conectar los skills ahora dice "Conectar" (antes "Activar Skills para Agentes"), y se quitó la mención a "Markdown" en el texto de descarga de AGENTS.md.
* Cambio de marca: el autor del plugin pasa a ser FacilWP (https://facil-wp.com/), reemplazando el nombre y enlace anteriores.

= 2.9.2 =
* Ajustes: Cambiado el formato del archivo de credenciales de agentes de un .txt plano a un archivo Markdown estructurado (AGENTS.md).
* AGENTS.md: Incluye instrucciones claras de inicialización para agentes de IA, un bloque de configuración de .mcp.json con token Basic Auth en Base64 calculado en tiempo de ejecución, acceso documentado a la API REST de WooCommerce y acceso a la API REST Core de WordPress.
* Ajustes UI: Actualizado el texto descriptivo de la sección de descarga de credenciales.

= 2.9.1 =
* Renderer: las landings ahora se benefician del srcset/sizes nativo de WordPress (el navegador elige el tamaño de imagen correcto según pantalla y densidad de píxeles) SIN depender de que el agente escriba class="wp-image-{id}" en el HTML. El renderer resuelve el attachment_id real a partir del src (con fallback para URLs de tamaños recortados, ya que attachment_url_to_postid() de WordPress solo hace match exacto contra el archivo original) e inyecta la clase antes de que corra wp_filter_content_tags(). Como efecto secundario también cubre width/height si el HTML no los trae. Nueva función Editor_IA_Renderer::auto_tag_wp_image_class().
* Beneficia automáticamente a landings ya existentes, sin tener que volver a editarlas.

= 2.9.0 =
* Servidor MCP: 12 tools nuevas que envuelven endpoints que hasta ahora solo existían por REST clásico — get-info (/info: versión, tema activo, WooCommerce, tamaños de imagen), upload-media/list-media (Biblioteca de WordPress), list/create/update/delete-assignment (sistema de condiciones granular) y list/get/create/update/delete-custom-php (snippets de PHP). Antes el agente tenía que salir del canal MCP y hacer una llamada REST aparte para estas cuatro áreas; ahora todo el flujo se puede hacer 100% por MCP. Total: 30 tools MCP.
* Descripción del endpoint POST /mcp en /info actualizada: ya no dice que media/condiciones "todavía no son tools MCP" (quedaba desactualizado).

= 2.8.2 =
* Ajustes → Instrucciones del agente: nuevo enlace "Probar conexión con los skills". Limpia los cachés (incluido el de fallo, que dura 5 min) y vuelve a contactar al servidor de instrucciones al instante, mostrando el resultado real ("Conexión correcta — los skills están disponibles" o el motivo exacto del fallo). Pensado para diagnosticar sin esperar cachés cuando la verificación de instalación falla (ej. firewall del hosting bloqueando el reto de verificación).

= 2.8.1 =
* Servidor MCP: se agregan 10 tools nuevas que envuelven endpoints REST ya existentes: get/set-componentes, set-seo, link/unlink-page, list-revisions, rollback, set/unset-global, list-menus y delete-file. Antes el agente tenía que caer a la API REST clásica para estas operaciones; ahora el flujo completo (crear, escribir, vincular componentes/SEO/página, publicar) se puede hacer 100% por MCP.
* rollback, delete-file y unset-global quedan marcadas como destructive:true en sus annotations MCP.

= 2.7.7 =
* Soporte opcional de WooCommerce en "Accesos para agentes": si WooCommerce está activo aparece un checkbox "¿Deseas trabajar también con los productos de WooCommerce?". Con el checkbox marcado, el mismo botón "Generar acceso para agentes" genera además un Consumer Key/Secret de la API REST de WooCommerce (permisos lectura/escritura, replicando el mecanismo del admin nativo de WooCommerce) y lo incluye en el mismo Accesos-agentes.txt junto con el endpoint wc/v3. Un solo botón, un solo archivo. Cada clic revoca las credenciales anteriores generadas por este botón (no toca claves creadas manualmente ni por otras integraciones).

= 2.7.6 =
* Nueva sección "Accesos para agentes" en Ajustes: un botón genera una WordPress Application Password para el usuario actual (revoca la anterior generada por este mismo botón, si existe) y descarga un archivo "Accesos-agentes.txt" con: URL del sitio, usuario, Application Password y el endpoint de la API del plugin Editor IA. Facilita entregarle credenciales a un agente de IA sin exponerlas en pantalla más de lo necesario (WordPress solo muestra la contraseña una vez, al crearla).
* Si el sitio no soporta Application Passwords (sin HTTPS o desactivadas por el hosting), se muestra un aviso en vez del botón.

= 2.7.5 =
* La API key se conserva siempre: "Desactivar" ya no borra la key — ahora es un interruptor (option editor_ia_agent_active, '1'/'0') sobre la misma key. Al reactivar se reutiliza la key existente, así el historial de la instalación en el servicio central nunca se fragmenta en varias keys. La key solo se genera la primera vez (con aceptación de términos); instalaciones activadas antes de esta versión se consideran activas.
* /info: el estado "instrucciones_agente_desactivadas" ahora se basa en el interruptor (is_active) y no en si existe la key. Desactivado, el agente no recibe ni la URL del servicio central ni la key.
* UI de Ajustes: texto de privacidad simplificado; botones renombrados a "Activar/Desactivar Skills para Agentes"; "Identificador de instalación" pasa a "Api key de Instalación"; se quita la fila "Términos aceptados" (los options de evidencia se conservan internamente).
* Menú admin: "Ajustes" se mueve al final del submenú (después de Tracking y Custom PHP).
* Fix UI: cuando las instrucciones están inactivas, la pantalla vuelve a mostrar el checkbox "Acepto los términos y condiciones" y oculta la Api key (aunque la key siga guardada internamente); al reactivar se reutiliza la misma key.
* Ajustes: aviso sutil con enlace a https://facil-wp.com (tutoriales, soporte y novedades del plugin).
* Ajustes: el párrafo de "Instrucciones del agente" ahora nombra ejemplos de agentes de IA compatibles (Claude, Antigravity, Codex) y describe la conexión como "la api gratuita del Editor IA WP".
* Cabecera del plugin: Author URI ahora apunta a https://facil-wp.com (antes facil-wp.com) — es el enlace que WordPress muestra en Plugins → "Por FacilWP".
* Cabecera del plugin: Description nueva — "El motor de páginas que tu agente de IA sabe usar, compatible con Claude, Antigravity o Codex." (antes: "Motor de publicación de landing pages para agentes de IA.")

= 2.7.3 =
* Cambio de texto: "Instrucciones remotas del agente" pasa a "Instrucciones del agente" en toda la UI y en los mensajes de /info y /key-proof. Solo texto — sin cambios funcionales. El código de estado interno en /info cambia de "instrucciones_remotas_desactivadas" a "instrucciones_agente_desactivadas".

= 2.7.2 =
* Separación de menús de administración: "Tracking" (GA4/GTM/Meta Pixel) pasa a su propia página independiente. "Ajustes" queda exclusivamente para "Instrucciones remotas del agente" (activar/desactivar la API key). Sin cambios funcionales — mismos options, mismo comportamiento, solo reorganización de la UI para no mezclar dos temas sin relación en una sola pantalla.

= 2.7.1 =
* Verificación de instalación (anti keys inventadas): nuevo endpoint PÚBLICO GET /key-proof?challenge=XYZ que responde {proof: HMAC-SHA256(challenge, key)} sin revelar la key. El servidor central lo llama UNA vez por instalación nueva: genera un challenge aleatorio, pide la firma al dominio declarado y solo sirve las instrucciones si la firma coincide — una key solo funciona si existe un WordPress real en ese dominio con esa key activada. El agente nunca necesita llamar este endpoint, y el plugin sigue sin hacer llamadas salientes (es el servidor quien verifica).

= 2.7.0 =
* Nueva arquitectura: instrucciones remotas del agente (el "cerebro" deja de entregarse manualmente). GET /info ahora incluye "paso_0_obligatorio": la primera instrucción del agente es leer sus instrucciones de trabajo en vivo desde el servicio central (GET https://api-editor.ia-facil.net/api/cerebro?key=...&domain=...&plugin_version=...). Las instrucciones se leen en contexto por sesión, nunca se descargan a disco. Al final del cerebro núcleo el servicio inyecta un índice de skills especializados (diseno, menus, imagenes, condiciones, woocommerce, custom-php, seo) que el agente pide por slug solo cuando los necesita (GET /api/cerebro/{slug}).
* Consentimiento explícito (opt-in): instalar/activar el plugin NO genera identificador ni conecta con ningún servidor. En Ajustes → "Instrucciones remotas del agente" el usuario marca "Acepto los términos y condiciones" y pulsa "Activar instrucciones del agente"; recién ahí se genera la key local (formato EIA-XXXX-XXXX-XXXX, random_int criptográfico) y se guarda la fecha/versión de términos aceptados como evidencia. Botón "Desactivar" borra la key. El consentimiento solo puede darse desde wp-admin, no por API.
* Servicios externos (transparencia): la única conexión saliente ocurre cuando el agente pide sus instrucciones a api-editor.ia-facil.net; se envía únicamente: identificador aleatorio de la instalación, dominio del sitio y versión del plugin. Sin datos personales, sin IPs almacenadas en el servicio, sin contenido del sitio. El plugin en sí nunca hace llamadas salientes.
* Sin consentimiento, /info instruye al agente ("el error es la documentación") a pedirle al usuario que active las instrucciones remotas en Ajustes.
* Nueva constante EDITOR_IA_CENTRAL_API.

= 2.6.9 =
* Nuevo: Editor_IA_Theme_Compat — cuando un componente global tiene hide_header/hide_footer configurado y el tema activo es Astra, ahora se remueven directamente los hooks nativos de Astra (astra_header / astra_footer, mismo patrón que Astra usa para su propia compatibilidad con Elementor Pro) en vez de ocultar el header/footer nativo con CSS display:none. Elimina el markup huérfano del tema y evita depender de que el selector CSS coincida exactamente con la estructura del tema.
* Temas sin adaptador (cualquiera fuera de Astra) siguen usando el fallback CSS display:none como antes — sin cambios de comportamiento para esos sitios.
* Próximas iteraciones: GeneratePress y OceanWP.

= 2.6.8 =
* Nuevo endpoint PUT /projects/{slug}/status { "status": "publish"|"draft" } para publicar o poner en borrador un proyecto (landing o componente). Antes no existía forma de despublicar una landing sin eliminar sus archivos: el post_status del proyecto se creaba hardcodeado en "publish" y no había manera de cambiarlo vía API.
* Si la landing tiene página nativa de WordPress vinculada (_editor_ia_page_id), esa página recibe el mismo status que el proyecto — no se desvincula, evita que el proyecto y su página queden en estados distintos (uno publicado y el otro no, o viceversa).
* get_project() y list_projects() ahora exponen "status" (del proyecto) y "page_status" (de la página vinculada, si existe).
* Corrección (SEO): las URLs de preview del plugin (/editor/{slug}/) ahora siempre incluyen <meta name="robots" content="noindex,nofollow">, publicada la landing o no — son una ruta interna de staging, contenido duplicado de la URL pública real, y no debían ser indexables.

= 2.6.7 =
* Corrección: en sitios con tema Astra, el mensaje "No hay productos en el carrito" aparecía duplicado dentro de [eia_cart] (uno suelto sin botón, otro dentro de un bloque con el botón "Seguir comprando"). No era un doble-llamado a woocommerce_mini_cart() (se confirmó que el plugin lo llama una sola vez) — Astra engancha su propio bloque enriquecido de carrito vacío a la acción woocommerce_after_mini_cart, que la plantilla core de WooCommerce dispara siempre, y el CSS que Astra usa para ocultar el mensaje suelto está encapsulado a su propio contenedor de header, no al drawer de [eia_cart].
* Fix: en eia-cart.css se oculta el <p class="woocommerce-mini-cart__empty-message"> suelto únicamente cuando el tema ya agregó su propio bloque .ast-mini-cart-empty justo después (selector :has()) — no afecta sitios sin ese tema/hook, donde el mensaje por defecto de WooCommerce sigue siendo el único y se muestra normalmente.

= 2.6.6 =
* Nuevo campo `dimensions` en GET/POST /media: {thumbnail, medium, large, full} → cada uno con {width, height} reales del archivo (además de las URLs en `sizes`, que no cambian — cambio 100% aditivo). Habilita que el HTML declare width/height en <img>, requisito de WordPress para aplicar su optimización automática de imágenes (ver 2.6.4).
* Documentación /info actualizada: la imagen hero/banner (candidata a LCP) nunca debe llevar loading="lazy" — dejar que WordPress la detecte automáticamente como prioritaria a partir de width/height.

= 2.6.5 =
* Corrección de accesibilidad (auditoría "Navegación agéntica" de PageSpeed): el drawer del carrito ([eia_cart]) se ocultaba con transform: translateX(100%) manteniendo aria-hidden="true", pero sus botones/enlaces internos (cerrar, ver carrito, checkout) seguían siendo focusables por teclado — violación "ARIA hidden element must not be focusable or contain focusable elements".
* Fix: se añade el atributo inert al drawer junto con aria-hidden. openCart()/closeCart() en eia-cart.js ahora quitan/agregan inert además de alternar aria-hidden, así el navegador saca todo el contenido del drawer del orden de tabulación mientras está cerrado, sin tener que recorrer manualmente cada elemento focusable.

= 2.6.4 =
* Nueva feature: compatibilidad con plugins de cache de página (WP Rocket, WP Super Cache, W3 Total Cache, LiteSpeed Cache, Seraphinite Accelerator, etc.). Editar una landing/componente vía REST (write_file, delete_file, set_seo, set_componentes, set_global/unset_global) o vía el meta box de admin ahora invalida automáticamente la cache de la página WordPress vinculada — antes esos cambios se escribían directo a disco y no pasaban por save_post/transition_post_status, así que ningún plugin de cache se enteraba y seguían sirviendo la versión vieja hasta expirar su TTL.
* Nueva clase Editor_IA_Cache: invalida por post, y si el proyecto es un componente asignado globalmente (scope global/post_type), hace un best-effort de vaciar la cache completa del sitio ante la imposibilidad de acotar qué URLs se ven afectadas.
* Corrección (render-blocking): el style.css propio de la landing y el del componente vinculado (comp_css) ya no se cargan como <link> externo en modo full — se inyectan inline en <head>, igual que ya se hacía con el CSS crítico del componente global. Elimina 1-2 solicitudes que bloqueaban el primer render.
* Corrección (LCP / lazy loading): el body de la landing ahora pasa por wp_filter_content_tags() antes de imprimirse. Al construirse con echo directo (no vía el_content), WordPress nunca le aplicaba su optimización nativa de imágenes (loading="lazy" fuera de la primera pantalla, fetchpriority="high" en la candidata a LCP); ahora sí, sin que el agente tenga que escribir esos atributos a mano.

= 2.6.3 =
* Corrección (universal, sin configuración por sitio): el style.css del componente global ya no se carga como <link> externo — se inyecta completo e inline en <head> vía inject_global_critical_css() (wp_head, prioridad 1), junto con html { overflow-y: scroll; }.
* Motivo: un <link> externo, aunque esté bien ubicado en <head>, puede llegar tarde por latencia de red o porque un plugin de optimización (WP Rocket, Autoptimize, LiteSpeed Cache, etc. — comunes en cualquier sitio WordPress) lo marque como no-bloqueante para mejorar PageSpeed. En ese intervalo el navegador dibuja el header del componente sin estilos (FOUC): logo a su tamaño natural, menú <ul> vertical con viñetas, salto de ancho por aparición tardía del scrollbar.
* Al ser inline, no depende de un request externo ni de cómo cada sitio/tema cargue assets — funciona igual en cualquier instalación de WordPress sin necesidad de tocar header.html ni crear archivos adicionales por componente.
* Se elimina el enqueue externo (wp_enqueue_style 'editor-ia-global-comp') que quedó redundante.

= 2.6.2 =
* (Superada por 2.6.3 — la solución de 2.6.2 dependía de un archivo critical.css opcional escrito a mano por componente, lo cual no escala a "diferentes sitios con diferentes temas". 2.6.3 lo reemplaza por un fix automático y universal.)

= 2.3.0 =
* Nueva feature: Custom PHP — sistema de snippets PHP con dos modos de ejecución: shortcode ([eia_php id="X"]) y global (init prioridad 1, permite add_action / add_filter / hooks de WordPress y WooCommerce).
* Seguridad: validación de sintaxis PHP con token_get_all(TOKEN_PARSE) antes de guardar — la API devuelve HTTP 422 con mensaje descriptivo si hay error de sintaxis.
* Seguridad: bloqueo de funciones peligrosas del sistema operativo (exec, system, shell_exec, passthru, proc_open, popen, pcntl_exec) en tiempo de guardado.
* Seguridad: try/catch de \ParseError y \Throwable en ejecución — el sitio no se rompe si hay un error en runtime.
* Seguridad: register_shutdown_function para capturar fatal errors (E_ERROR, memoria agotada, etc.) que eval() no puede atrapar con try/catch. Si un fatal ocurre, el snippet se auto-desactiva automáticamente para que el siguiente request funcione.
* Seguridad: errores de ejecución persistidos en wp_options — el admin ve el aviso en el panel aunque el error haya ocurrido en el frontend.
* Seguridad: respeto de DISALLOW_UNFILTERED_HTML — si está activo en la instalación, no se ejecuta ningún snippet.
* Eliminado: feature "Editor de Theme" (conectar con theme hijo) — removido por razones de seguridad. Los endpoints /theme/* y el toggle en Ajustes han sido eliminados.
* API: nuevos endpoints REST GET/POST /custom-php y GET/PUT/DELETE /custom-php/{id} con campo scope (shortcode|global).

= 2.1.2 =
* Corrección: el CSS del proyecto/componente se cargaba antes de wp_head(), permitiendo que el theme activo (ej. Astra) sobreescribiera estilos de botones y otros elementos con reglas genéricas (button { padding: 15px 30px; ... }). Ahora los <link> del proyecto se inyectan después de wp_head(), ganando la cascada sin necesidad de !important en cada landing.
* Esto aplica en modo full cuando hay un componente global activo (en ese caso el theme no se desencola para preservar el header nativo), y en cualquier otro escenario donde el CSS del theme llegue a la página.

= 2.1.1 =
* Corrección: el drawer del [eia_cart] quedaba recortado o "por debajo" cuando el shortcode estaba dentro de un header con CSS transform, filter, will-change o position:sticky. Estos contextos rompen position:fixed haciendo que sea relativo al contenedor padre en vez del viewport.
* Fix: el drawer (.eia-cart-drawer) y el overlay (.eia-cart-overlay) ahora se teleportan automáticamente al <body> via JavaScript al inicializar, garantizando que position:fixed siempre sea relativo al viewport sin importar la estructura del header.
* CSS: añadido height:100vh explícito en drawer y overlay como refuerzo adicional.

= 2.1.0 =
* Nueva feature: endpoint GET /media — lista imágenes de la Biblioteca de WordPress con sus URLs en todos los tamaños (thumbnail, medium, large, full). Soporta filtro por nombre (?search=) y límite (?limit=).
* Nueva feature: endpoint POST /media — sube una imagen (base64) directamente a la Biblioteca de WordPress. WordPress genera automáticamente los tamaños configurados (thumbnail 150px, medium 300px, large 1024px). Devuelve id, url y objeto sizes con las URLs de cada tamaño.
* Las imágenes de los proyectos ahora se gestionan desde la Biblioteca de WordPress, no como archivos binarios en assets/. Esto permite optimización móvil usando <picture> o srcset con los tamaños generados.
* Documentados en /info los nuevos endpoints /media con parámetros, cuerpo y campo uso_movil que orienta al agente sobre qué tamaño usar según el contexto (banner, card, miniatura).

= 2.0.0 =
* Nueva feature: shortcode [eia_cart] — carrito WooCommerce nativo, sin dependencia de ningún tema. Muestra un botón con ícono SVG (bolsa o carrito clásico) y badge rojo con el contador de ítems. Al hacer clic abre un panel lateral deslizante (drawer) con el mini-carrito completo de WooCommerce: imagen del producto, nombre, cantidad, precio en naranja, subtotal y botones "Ver carrito" / "Finalizar compra" en verde.
* [eia_cart] atributos: icon="bag" (default) | icon="cart", title="Tu carrito" (personalizable).
* Auto-apertura del drawer: cuando el usuario hace clic en "Añadir al carrito" de WooCommerce, el panel lateral se abre automáticamente para mostrar el producto recién agregado.
* AJAX nativo: el contador se actualiza sin recargar la página usando wc-cart-fragments (sistema nativo de WooCommerce). El ícono elegido se persiste en la base de datos para que el fragmento AJAX respete siempre el atributo icon definido en el shortcode.
* Eliminada dependencia de Astra para el carrito: removidos [carrito_astra] y [astra_header_completo] del child theme. El renderer (modo full) siempre desencola assets del tema, sin condicionales.
* API /info actualizada: environment.woocommerce incluye versión de WooCommerce, URL del carrito y documentación completa del shortcode [eia_cart] con atributos, ejemplos y cómo funciona.

= 1.9.1 =
* Actualización: endpoint GET /info ahora documenta los 24 endpoints completos del plugin, organizados por sección (proyectos, archivos, revisiones, SEO, componentes, global, página, menús, theme editor, rollback). Anteriormente omitía SEO, theme editor y revisiones.
* Las restricciones en /info ahora están separadas por contexto: proyectos (sin PHP) y theme (con PHP, sin binarios), para que el agente sepa exactamente qué está permitido en cada uno.

= 1.9.0 =
* Nueva feature: sistema de revisiones automáticas — cada vez que el agente sobreescribe un archivo (PUT /file o PUT /theme/file), el plugin guarda automáticamente la versión anterior. Se conservan hasta 5 revisiones por archivo.
* Nuevo endpoint: GET /projects/{slug}/revisions?path=landing.html — lista las revisiones disponibles de un archivo de proyecto, con timestamp y fecha legible, ordenadas de más reciente a más antigua.
* Nuevo endpoint: POST /projects/{slug}/rollback { "path": "landing.html", "revision": "20260627143000" } — restaura una revisión anterior de un archivo de proyecto. Guarda el estado actual como revisión antes de restaurar.
* Nuevo endpoint: GET /theme/revisions?path=functions.php — lista las revisiones disponibles de un archivo del theme hijo (requiere toggle activo).
* Nuevo endpoint: POST /theme/rollback { "path": "functions.php", "revision": "20260627143000" } — restaura una revisión del theme. Usa WP Filesystem API para restaurar.
* Las revisiones de proyectos se guardan en {project_dir}/.revisions/ y se excluyen automáticamente del GET /tree.
* Las revisiones del theme se guardan en wp-content/uploads/editor-ia/.theme-revisions/{theme-slug}/ para no contaminar el directorio del theme.

= 1.8.1 =
* Nuevo endpoint: DELETE /wp-json/editor-ia/v1/theme/file?path=archivo.css — elimina un archivo del theme hijo activo vía API.
* Mejora UI: texto del toggle "Acceso al Theme" en Ajustes simplificado — solo muestra la etiqueta esencial sin descripción redundante.

= 1.8.0 =
* Nueva feature: Editor de Theme — los agentes pueden leer y editar archivos del tema hijo activo directamente desde la API REST del plugin, sin necesidad de acceso FTP o SSH.
* Nueva opción en Ajustes: "Habilitar editor de theme" — toggle que activa/desactiva los endpoints de acceso al theme. Desactivado por defecto.
* Nuevo endpoint: GET /wp-json/editor-ia/v1/theme/tree — lista todos los archivos del tema hijo (.php, .css, .js, .json) con su ruta relativa.
* Nuevo endpoint: GET /wp-json/editor-ia/v1/theme/file?path=style.css — lee el contenido de un archivo del theme.
* Nuevo endpoint: PUT /wp-json/editor-ia/v1/theme/file — escribe un archivo en el theme usando WP Filesystem API (seguro, respeta permisos del servidor).
* Seguridad: solo se permiten extensiones .php, .css, .js y .json. No se puede salir del directorio del theme hijo con path traversal.
* Constante THEME_EXT definida en la clase REST para extensiones permitidas.

= 1.7.3 =
* Corrección: cambio de estrategia para desactivar Yoast SEO — en lugar de intentar remover el objeto de clase (frágil y dependiente de versión), se usa remove_all_actions('wpseo_head') con prioridad 0 en wp_head. Esto vacía todos los callbacks internos de Yoast antes de que imprima algo, compatible con cualquier versión.

= 1.7.2 =
* Corrección: el hook wpseo_head de Yoast no es un filtro sino una acción interna — no se puede suprimir con __return_false. Ahora se remueve directamente la acción de wp_head que Yoast registra, compatible con Yoast v14+ (DI container, Front_end_integration::call_wpseo_head) y versiones legacy (WPSEO_Frontend::head). Rank Math se desactiva via su filtro oficial rank_math/frontend/disable_head.

= 1.7.1 =
* Corrección de arquitectura SEO: eliminada la auto-sincronización de meta descripción desde el HTML (sync_meta_desc). Los campos seo_title y meta_desc ahora son exclusivamente responsabilidad del plugin via PUT /projects/{slug}/seo o el meta box del admin. Esto evita que el agente pierda los valores al reescribir landing.html.
* Los agentes deben eliminar <meta name="description"> del HTML y usar PUT /projects/{slug}/seo {"seo_title":"...","meta_desc":"..."} en su lugar.

= 1.7.0 =
* Nueva feature: campo "Título SEO" (_editor_ia_seo_title) — si está definido se usa como <title> en lugar del título interno del proyecto. Permite tener un nombre de guía en el admin y un título optimizado para buscadores.
* Nueva feature: compatibilidad con Yoast SEO y Rank Math — si el proyecto tiene seo_title o meta_desc configurados, se desactiva automáticamente la salida de estos plugins en esa página para evitar etiquetas duplicadas.
* Mejora: campo meta descripción cambiado de input texto a textarea en el meta box del admin (más cómodo para textos largos).
* Nuevo endpoint REST: PUT /projects/{slug}/seo — permite al agente setear seo_title y meta_desc vía API.
* GET /projects/{slug} ahora expone seo_title y meta_desc en la respuesta para landings.

= 1.6.0 =
* Compatibilidad con plugins de WordPress en modo full: el renderer ahora llama wp_head() y wp_footer(), permitiendo que WPForms, Cloudflare Turnstile y cualquier plugin que use el sistema de enqueue de WP funcione correctamente dentro de landings full.
* Los estilos y scripts del tema activo se desencolan automáticamente (dequeue_theme_assets()) para preservar el aislamiento visual, sin afectar los assets de plugins externos.
* La barra de administración de WordPress vuelve a mostrarse correctamente en modo full (gestionada ahora via wp_head/wp_footer en lugar de código manual).
* Corrección: restaurado soporte de meta descripción por proyecto (_editor_ia_meta_desc) que se había perdido por desincronización entre local y servidor.

= 1.5.0 =
* (Versión interna — renombrada a 1.6.0 antes de publicar. Sin cambios adicionales.)

= 1.4.0 =
* Nueva feature: meta box "Editar textos" en el admin de WordPress — permite editar el texto de todas las landings directamente desde el CPT sin tocar código.
* El parser (DOMDocument + DOMXPath) extrae h1–h6, p, li y button en orden de documento; los identifica por posición (H1, P #2, LI #5, etc.).
* Títulos y botones usan input de texto simple; párrafos y listas usan TinyMCE mínimo (negrita, cursiva, enlace) para preservar formato inline.
* Configuración forced_root_block:false en TinyMCE + unwrap defensivo en PHP para evitar el anidado <p><p> que rompe el layout.
* Validación client-side (JS): bloquea el submit y muestra aviso si algún campo está vacío antes de guardar.
* Validación server-side (PHP): segunda capa de seguridad — si el JS se saltó, el servidor verifica y no escribe el archivo si hay campos vacíos.
* El HTML del proyecto es siempre la fuente de verdad; ningún texto se guarda en la base de datos.

= 1.3.0 =
* Nueva feature: Componente Global — inyecta header.html y footer.html de un componente en páginas nativas de WordPress (blog, archivo, posts, páginas), sin afectar las landings del plugin.
* Nuevo endpoint: PUT /projects/{slug}/global — activa un componente como global con control de selectores CSS a ocultar y contextos donde aplica (blog, archive, single, page, all).
* Nuevo endpoint: DELETE /projects/{slug}/global — desactiva el componente global.
* GET /projects/{slug} — los componentes ahora exponen el campo "global" con su estado de activación, selectores y contextos.
* GET /info — documentación actualizada con el nuevo endpoint y descripción del tipo componente.
* Solo puede haber un componente global activo a la vez; activar uno desactiva el anterior automáticamente.

= 1.2.0 =
* Sistema de tracking de sesión del usuario (persistencia entre recargas).
* Endpoint GET /menus — lista los menús de navegación de WordPress.
* Shortcode [editor_ia_menu] — inserta menús dinámicos de WordPress en header.html/footer.html.
* Modo full aislado: el renderer no carga ningún CSS/JS del tema activo.
* GET /info — endpoint de descubrimiento con documentación completa de la API.
* Corrección: map_meta_cap cambiado a false (eliminaba notice de WP).
* Corrección: PUT /file usa get_json_params() para manejar JSON grande correctamente.
* Corrección: CORS para clientes browser via hook init con respuesta OPTIONS 200.

= 1.1.0 =
* Sistema de componentes: header.html, footer.html y style.css reutilizables entre landings.
* Endpoints PUT/GET /projects/{slug}/componentes.
* El CSS del componente se encola antes que el CSS del proyecto (permite override).
* El renderer inyecta header/footer del componente directamente en el HTML.

= 1.0.0 =
* Versión inicial.
* Custom Post Type editor_ia_project.
* Endpoints REST: /projects (GET, POST), /projects/{slug} (GET), /projects/{slug}/file (GET, PUT, DELETE), /projects/{slug}/tree (GET), /projects/{slug}/page (PUT, DELETE).
* Modos de rendering: full (HTML puro) e integrado (con tema de WP).
* Rewrite rule /editor/{slug}/ para preview sin publicar.
* Rol y capability manage_editor_ia_projects.
* Soporte de archivos de texto (.html, .css, .js, .json) y binarios en assets/.
