merge: el PDF nativo con FPDF llega a feat/app-documentate - #283
Merged
Conversation
Contributor
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
erseco
added a commit
that referenced
this pull request
Sep 6, 2026
…#283 El PDF nativo se dibujaba dentro de un `<div>` propio, así que un `</div>` sobrante en un campo rich —que `wp_kses_post()` conserva y que un layout con `strconv=no` inyecta tal cual— cerraba el envoltorio y tiraba en silencio todo lo que venía detrás: el RESUELVO, la firma y los anexos. Se dibuja desde un `<body>`, donde libxml se recupera de la etiqueta sobrante en vez de obedecerla. Las filas de un repetidor se emparejaban con las guardadas por posición, y el navegador renumera las filas en cada alta, baja y arrastre: el área podía mover el IGIC o el importe aprobado de gestión a otro proveedor sin tocar la columna. Ahora cada fila lleva su identidad en un `__row` oculto. El resto: - Un adjunto se servía inline con su propio mime, y la metacaja de wp-admin escribe esa misma meta desde cualquier ID de la mediateca: un SVG o un HTML se ejecutaba en el origen del sitio. Lo que no aceptó la aplicación se entrega como descarga opaca. - El filtro `comments_clauses` se registraba por consulta y se desenganchaba solo en su primera llamada, que no ocurre cuando `WP_Comment_Query` responde desde su caché: quedaba puesto y vaciaba la actividad de un documento que su lector sí puede ver. Se registra una vez y decide mirando la consulta. - `remove_role()` dejaba a los miembros del rol sin capacidad ninguna, ni `read`. Ahora pasan al rol por defecto antes de quitarlo. - `page_url()` resolvía por slug e ignoraba `documentate_app_page_id`: renombrar la página dejaba en blanco todos los enlaces y redirecciones. - `devolver_area` existe desde `en_gestion` y desde `pending`, y `confirmation()`, `redirect()` y `flag()` sólo miraban la clave. - `mode()` fallaba en cualquier sistema donde `chmod` es cosmético (Windows, CIFS, bind mounts), bloqueando toda generación; y un render abortado dejaba su `.tmp` para siempre. - `assign_missing()` escribía el marcador aunque `get_terms()` fallara, con lo que un tropiezo cancelaba la migración de layouts para siempre. - La desinstalación dejaba la página, cuatro opciones y los documentos generados, que llevan datos personales. - El último `__()` del plugin, en inglés sobre una interfaz en español. - `nombre_completo` nunca llegaba a su valor de ejemplo, y el autoloader del PDF se apilaba una vez por instancia.
This was referenced Sep 6, 2026
erseco
added a commit
that referenced
this pull request
Sep 6, 2026
…oj no avance `test_existing_document_preserves_dates` insertaba un borrador sin fecha, leía su `post_date` y comprobaba que el update no lo movía. Un borrador sin fecha lleva `post_date_gmt` a ceros, que para WordPress significa «esta fecha aún flota» y la refresca en cada guardado: la comprobación solo se cumplía si el insert y el update caían dentro del mismo segundo, y en CI no siempre caen. Falló así en el último run de #283, esperando 06:50:23 y recibiendo 06:50:24. Con la fecha puesta a mano deja de flotar, y cualquier desplazamiento pasa a ser cosa del plugin, que es justo lo que el test quiere vigilar.
erseco
force-pushed
the
integra/app-documentate-pdf-nativo
branch
from
September 8, 2026 17:04
daa68fe to
87f11ab
Compare
erseco
force-pushed
the
integra/app-documentate-pdf-nativo
branch
from
September 8, 2026 17:18
87f11ab to
fdbb5c9
Compare
El metabox de acciones solo se pinta para quien puede editar el documento, y aquí un documento publicado queda aprobado y bloqueado: los cuatro tests que afirman sobre sus botones lo devuelven antes a revisión. El botón se llama «Previsualizar PDF» en esta rama. El bloque de exportación ya no ofrece un DOCX deshabilitado para un tipo con plantilla ODT: la descarga editable solo ofrece el formato propio, así que el control no existe en vez de existir apagado.
…#283 El PDF nativo se dibujaba dentro de un `<div>` propio, así que un `</div>` sobrante en un campo rich —que `wp_kses_post()` conserva y que un layout con `strconv=no` inyecta tal cual— cerraba el envoltorio y tiraba en silencio todo lo que venía detrás: el RESUELVO, la firma y los anexos. Se dibuja desde un `<body>`, donde libxml se recupera de la etiqueta sobrante en vez de obedecerla. Las filas de un repetidor se emparejaban con las guardadas por posición, y el navegador renumera las filas en cada alta, baja y arrastre: el área podía mover el IGIC o el importe aprobado de gestión a otro proveedor sin tocar la columna. Ahora cada fila lleva su identidad en un `__row` oculto. El resto: - Un adjunto se servía inline con su propio mime, y la metacaja de wp-admin escribe esa misma meta desde cualquier ID de la mediateca: un SVG o un HTML se ejecutaba en el origen del sitio. Lo que no aceptó la aplicación se entrega como descarga opaca. - El filtro `comments_clauses` se registraba por consulta y se desenganchaba solo en su primera llamada, que no ocurre cuando `WP_Comment_Query` responde desde su caché: quedaba puesto y vaciaba la actividad de un documento que su lector sí puede ver. Se registra una vez y decide mirando la consulta. - `remove_role()` dejaba a los miembros del rol sin capacidad ninguna, ni `read`. Ahora pasan al rol por defecto antes de quitarlo. - `page_url()` resolvía por slug e ignoraba `documentate_app_page_id`: renombrar la página dejaba en blanco todos los enlaces y redirecciones. - `devolver_area` existe desde `en_gestion` y desde `pending`, y `confirmation()`, `redirect()` y `flag()` sólo miraban la clave. - `mode()` fallaba en cualquier sistema donde `chmod` es cosmético (Windows, CIFS, bind mounts), bloqueando toda generación; y un render abortado dejaba su `.tmp` para siempre. - `assign_missing()` escribía el marcador aunque `get_terms()` fallara, con lo que un tropiezo cancelaba la migración de layouts para siempre. - La desinstalación dejaba la página, cuatro opciones y los documentos generados, que llevan datos personales. - El último `__()` del plugin, en inglés sobre una interfaz en español. - `nombre_completo` nunca llegaba a su valor de ejemplo, y el autoloader del PDF se apilaba una vez por instancia.
…oj no avance `test_existing_document_preserves_dates` insertaba un borrador sin fecha, leía su `post_date` y comprobaba que el update no lo movía. Un borrador sin fecha lleva `post_date_gmt` a ceros, que para WordPress significa «esta fecha aún flota» y la refresca en cada guardado: la comprobación solo se cumplía si el insert y el update caían dentro del mismo segundo, y en CI no siempre caen. Falló así en el último run de #283, esperando 06:50:23 y recibiendo 06:50:24. Con la fecha puesta a mano deja de flotar, y cualquier desplazamiento pasa a ser cosa del plugin, que es justo lo que el test quiere vigilar.
erseco
force-pushed
the
integra/app-documentate-pdf-nativo
branch
from
September 8, 2026 18:51
fdbb5c9 to
0d66cae
Compare
erseco
added a commit
that referenced
this pull request
Sep 8, 2026
* refactor: la limpieza y el rendimiento que quedaron fuera de #283 Apilado sobre #283, que se queda con los fallos de correctitud y seguridad. Aquí no cambia nada de lo que ve el usuario. Los dos que la revisión pedía y allí no cabían: - El motor nativo estaba pegado a `Documentate_Admin_Helper` como cuatro «si es nativo, sal por aquí» repartidos por una clase con forma de conversor, y cada uno preguntaba el nombre del motor para deducir lo mismo. Quién puede hacer qué es asunto de `Documentate_Conversion_Manager`, así que ahora lo dice él en `capabilities()` y la metacaja lee la respuesta en vez de volver a derivarla. Un quinto motor se añade en un sitio, no en cuatro. - El layout genérico recorría el esquema dos veces: una para los campos de mezcla y otra para las filas que se dibujan con ellos, y la segunda volvía a leer el tipo, a parsear el cuerpo entero y a resolver cada campo para llegar a la misma respuesta. Ahora las filas salen del mismo recorrido. `build_generic_rows()` desaparece: era ese segundo recorrido. Y el resto de la limpieza: - `Documentate_Pdf_Layout::slugs()` / `is_shipped()` responden «¿existe este layout?» con los nombres de fichero. Antes se abrían y se parseaban los once layouts, con `DOMDocument`, para tirar después los títulos — en cada PDF y en cada pantalla de tipo de documento. - `Documentate_Pdf_Table_Writer` construía un `DOMXPath` sobre el documento entero en cada consulta, varias por fila y por celda, y dos veces: al medir y al dibujar. Ahora se construye uno por documento. - Pintar una bandeja lanzaba una decena de `WP_Query` de conteo, varias idénticas. Se recuerdan durante la petición, con la marca de cambios de `posts` en la clave, así que cualquier escritura las invalida sola. - El stepper repetía la misma consulta de eventos por cada paso completado. - `own_format_state()` seguía construyendo `available` y `message`, que ya no lee nadie desde que se borró la rama del botón deshabilitado. - Un filtro `wp_insert_post_empty_content` en cada inserción cuyo cuerpo entero era `return $maybe_empty;`. - `.distignore` deja fuera los `.ttf`: FPDF sólo lee el `.json` y el `.z`, y el TrueType son 157 KB muertos en cada release. Sigue en git, que es de donde el README regenera el par. - Dos specs E2E: cuatro tests desbloqueaban un documento publicado para ver una metacaja que sólo mira `edit_post` —otros cuatro del mismo fichero ya la miraban sin desbloquear— y una rama de `checkControl()` que ninguna fila podía activar desde que se quitó DOCX. * test: capabilities() se prueba rama a rama, y en la clase que la declara El informe de cobertura del PR daba 0 % para `class-documentate-conversion-manager.php`: el método lo ejercitaba un test de la metacaja, que declara `@covers Documentate_Admin_Helper`, así que las líneas que ejecutaba en otra clase no se le atribuían a esa clase. Las pruebas van ahora a `DocumentateConversionManagerTest`, que es quien declara `@covers Documentate_Conversion_Manager`, y cubren las cuatro respuestas que el método puede dar: el motor nativo, Collabora accesible, Collabora dentro de Playground —donde la conversión la hace un fetch del navegador y hace falta el documento base— y un motor que no se alcanza y tampoco tiene ventana. De paso queda escrito que el motor nativo sigue siendo nativo dentro de Playground, que es lo que desvía la previsualización al visor incrustado.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Qué es
Traer a
feat/app-documentatelo que se mezcló enmaincon el PR #282: el PDF se dibuja en el servidor con FPDF a partir de maquetas HTML por tipo de documento, Collabora Online y el conversor WASM quedan como motores seleccionables, la descarga editable se ofrece solo en el formato de la plantilla, y los ficheros generados quedan protegidos enuploads/documentate/.Es una mezcla de
main, no un rehacer: un solo commit de merge.Adaptado a las convenciones de esta rama
Sin i18n. Las doce cadenas que llegaban con
__()yesc_html_e()pasan a literales en castellano, ylanguages/sigue sin existir. Los tests que afirmaban sobre el texto en inglés afirman ahora sobre el castellano.mainNative PDF renderingPDF nativo (FPDF)Editable download:Descarga editable:PDF layoutMaqueta PDFThe generated PDF could not be saved.No se ha podido guardar el PDF generado.Conflictos y cómo se resolvieron
Once ficheros, resueltos a favor de la estructura de
mainy del idioma de esta rama.fpdfy el selector de maqueta PDF, con sus etiquetas en castellano.Documentate_Admin_Helper:build_format_state()cede anteown_format_state(), que ofrece solo el formato de la plantilla del tipo. Los tests de la función que desaparece se eliminan con ella.prefixyhas_managementde esta rama junto apdf_layoutdemain.protect_output_dir()se elimina:Documentate_Private_Outputhace lo mismo y más — permisos, migración de ficheros anteriores y fallo cerrado. El.htaccessque dejara la versión anterior sigue siendo válido, porque ya declara «Require all denied».main, que parcheawindow.openen vez de esperar a que la pestaña pinte; el endpoint que abre el botón esdocumentate_preview_stream, que es sobre el que afirma.composer.lock: regenerado concomposer update --locksobre elcomposer.jsonya fusionado, que aquí no llevawp-cli/i18n-command.E2E adaptado
Los specs que llegan de
maindaban por hecho que un documento publicado se puede editar. Aquí el flujo lo aprueba y lo bloquea, y el metabox de acciones solo se pinta para quien puede editar el documento, así que los cuatro tests que afirman sobre sus botones lo devuelven antes a revisión. El botón se llama «Previsualizar PDF» en esta rama, no «Vista previa».El bloque de exportación de la aplicación esperaba un botón DOCX deshabilitado en un tipo con plantilla ODT. Con la descarga editable limitada al formato propio, ese control ya no existe apagado: no existe. El spec lo comprueba ahora así.
Tres specs de la aplicación (
documentate-app.spec.js,documentate-app-flow.spec.js,documentate-app-roles.spec.js) fallaban por datos acumulados en el sitio de desarrollo, no por la mezcla: fallan igual enfeat/app-documentatesin ella, y pasan trasmake reset-demo.Presupuesto de PHPMD
La mezcla cruzaba la puerta por cinco líneas. Sin tocar
phpmd-baseline.xml:Documentate_Demo_Dataestaba en 2504 líneas. La tabla de valores de ejemplo, 155 líneas de datos con un solo punto de llamada, se va aDocumentate_Demo_Field_Values.load_dependencies()estaba en 151. La carga de la aplicación de/documentate/pasa a su propio método.Verificación
make testmake test-generationmake lintmake phpmdmake check-pluginmake test-e2emake reset-demo)