Compare commits

...

11 Commits

Author SHA1 Message Date
inma bbae0571ae fixtures: .doc originales de Fray Marcos (#209)
Los 30 .doc tal cual llegan por correo, de la carta 713 a la 740, para poder
reproducir el borrado silencioso por <w:smartTag> y diffear contra lo publicado.
Pedidos por Rafa en el #209, donde el barrido quedó bloqueado sin ellos.
2026-08-19 09:06:08 +00:00
inma a806cf9cae doc_convert.py: conversor .doc->.docx de Fray Marcos, con el arreglo de los smartTag (#209) 2026-08-18 09:24:55 +00:00
rafa 696934016f Merge pull request 'Backfill evangelio: modo apply explícito vía variable de entorno' (#208) from fix/backfill-apply-mode into main 2026-08-12 13:57:12 +00:00
rafa 06d7057e76 fix: support explicit backfill apply mode
Co-authored-by: rafa <rcalvotorrejon@gmail.com>
Signed-off-by: rafa <rcalvotorrejon@gmail.com>
2026-08-12 09:56:10 -04:00
rafa ef2978fc21 Merge pull request 'Mostrar el evangelio también en Comentario editorial (no solo Comentarios al evangelio)' (#207) from feat/evangelio-editorial into main 2026-08-12 13:53:41 +00:00
rafa 587b10c2b3 Merge pull request 'Modo oscuro: toggle duplicado, evangelio, navegación, visited, colaboradores' (#206) from fix/theme-button-duplicate into main 2026-08-12 13:53:37 +00:00
rafa 6b966a3b5f fix: style contributor cards in dark mode
Co-authored-by: rafa <rcalvotorrejon@gmail.com>
Signed-off-by: rafa <rcalvotorrejon@gmail.com>
2026-08-12 09:33:58 -04:00
rafa 75c0f07eab fix: keep visited links readable in dark mode
Co-authored-by: rafa <rcalvotorrejon@gmail.com>
Signed-off-by: rafa <rcalvotorrejon@gmail.com>
2026-08-12 09:20:34 -04:00
rafa f0946be1fc fix: cover navigation and gallery dark states
Co-authored-by: rafa <rcalvotorrejon@gmail.com>
Signed-off-by: rafa <rcalvotorrejon@gmail.com>
2026-08-12 09:16:43 -04:00
rafa d836297c89 fix: cover editorial components in dark mode
Co-authored-by: rafa <rcalvotorrejon@gmail.com>
Signed-off-by: rafa <rcalvotorrejon@gmail.com>
2026-08-12 09:15:47 -04:00
rafa d9ff5e891c fix: prevent duplicate theme toggle
Co-authored-by: rafa <rcalvotorrejon@gmail.com>
Signed-off-by: rafa <rcalvotorrejon@gmail.com>
2026-08-12 09:04:15 -04:00
34 changed files with 270 additions and 2 deletions
+117 -1
View File
@@ -105,7 +105,8 @@ add_action('wp_head', function () {
--wp--preset--color--base: #0d0d0d;
--wp--preset--color--contrast: #ececec;
}
html[data-fea-theme="dark"] a { color: <?php echo esc_html($accent_dark); ?>; }
html[data-fea-theme="dark"] a,
html[data-fea-theme="dark"] a:visited { color: <?php echo esc_html($accent_dark); ?>; }
html[data-fea-theme="dark"] a:focus-visible,
html[data-fea-theme="dark"] button:focus-visible {
outline-color: <?php echo esc_html($accent_dark); ?> !important;
@@ -184,6 +185,117 @@ add_action('wp_head', function () {
color: #b8afa8;
}
/* Comentarios al evangelio: el panel usa colores editoriales claros fijos. */
html[data-fea-theme="dark"] .fea-com-evangelio {
background: #1a1711;
border-left-color: #c9973e;
color: #ececec;
}
html[data-fea-theme="dark"] .fea-com-evangelio-details summary {
color: #f0c674;
}
/* Elementos editoriales presentes en artículos y resultados. */
html[data-fea-theme="dark"] .fea-audio {
background: #161311;
border-color: #3a302b;
border-left-color: <?php echo esc_html($accent_dark); ?>;
}
html[data-fea-theme="dark"] .fea-byline-name { color: #ececec; }
html[data-fea-theme="dark"] .fea-byline-cat,
html[data-fea-theme="dark"] .fea-eed-link .fecha { color: #b8afa8; }
html[data-fea-theme="dark"] .fea-share-rule { border-top-color: #3a302b; }
html[data-fea-theme="dark"] .fea-share-row { color: #d5cbc3; }
html[data-fea-theme="dark"] .fea-share-label,
html[data-fea-theme="dark"] .fea-share-sep { color: #b8afa8; }
/* Formulario y filtros de búsqueda avanzada. */
html[data-fea-theme="dark"] .fea-adv-details {
background: #161311; border-color: #3a302b;
}
html[data-fea-theme="dark"] .fea-adv-summary {
background: #24181c; border-bottom-color: #3a302b;
color: <?php echo esc_html($accent_dark); ?>;
}
html[data-fea-theme="dark"] .fea-adv-label,
html[data-fea-theme="dark"] .fea-adv-chips-label,
html[data-fea-theme="dark"] .fea-adv-meta,
html[data-fea-theme="dark"] .fea-archive-card .fea-adv-byline { color: #b8afa8; }
html[data-fea-theme="dark"] .fea-adv-chip {
background: #2a1b20; border-color: #56343d; color: #ececec;
}
html[data-fea-theme="dark"] .fea-adv-input,
html[data-fea-theme="dark"] .fea-adv-select {
background: #1c1c1c; border-color: #3a3a3a; color: #ececec;
}
html[data-fea-theme="dark"] .fea-adv-count { color: #b8afa8; }
/* Recopilatorios y galería multimedia. */
html[data-fea-theme="dark"] .fea-recop-year { border-bottom-color: #3a302b; }
html[data-fea-theme="dark"] .fea-recop-list li { border-bottom-color: #2a2320; }
html[data-fea-theme="dark"] .fea-recop-list a,
html[data-fea-theme="dark"] .fea-mm-title { color: #ececec; }
html[data-fea-theme="dark"] .fea-recop-date,
html[data-fea-theme="dark"] .fea-mm-date,
html[data-fea-theme="dark"] .fea-mm-excerpt { color: #b8afa8; }
html[data-fea-theme="dark"] .fea-mm-card { background: #161311; border-color: #2a2320; }
html[data-fea-theme="dark"] .fea-mm-thumb { background: #241f1c; }
/* Galerías de pensamientos y navegación del tema base. */
html[data-fea-theme="dark"] .fea-gallery-item {
background: #161311; border-color: #3a302b;
}
html[data-fea-theme="dark"] .fea-lightbox-frame img { background: #161311; }
html[data-fea-theme="dark"] .fea-lightbox button { background: #2a2320; color: #ececec; }
html[data-fea-theme="dark"] .wp-block-navigation .wp-block-navigation-item__content {
color: #ececec;
}
html[data-fea-theme="dark"] .wp-block-navigation__submenu-container {
background: #161311; border-color: #3a302b;
}
/* Página de apoyo: plantilla propia con colores claros explícitos. */
html[data-fea-theme="dark"] .fea-support-page {
--fea-support-ink: #ececec;
--fea-support-warm: #161311;
--fea-support-line: #3a302b;
--fea-support-card: #161311;
}
html[data-fea-theme="dark"] .fea-support-hero,
html[data-fea-theme="dark"] .fea-support-banner {
background: #1a1711 !important;
border-color: #3a302b !important;
}
html[data-fea-theme="dark"] .fea-support-card,
html[data-fea-theme="dark"] .fea-support-button.is-secondary {
background: #161311 !important;
border-color: #3a302b !important;
color: #ececec !important;
}
html[data-fea-theme="dark"] .fea-support-card__title,
html[data-fea-theme="dark"] .fea-support-progress__numbers span,
html[data-fea-theme="dark"] .fea-support-progress__note,
html[data-fea-theme="dark"] .fea-support-sidebar__small { color: #b8afa8; }
html[data-fea-theme="dark"] .fea-support-progress__track { background: #3a302b; }
/* Colaboradores: stylesheet propio del tema con tarjetas claras y !important. */
html[data-fea-theme="dark"] .entry-content .wrapper {
background: #161311 !important;
border-color: #3a302b !important;
color: #ececec !important;
box-shadow: 0 2px 4px rgba(0,0,0,.45) !important;
}
html[data-fea-theme="dark"] .entry-content .wrapper strong {
color: #ececec !important;
}
html[data-fea-theme="dark"] .entry-content .wrapper a,
html[data-fea-theme="dark"] .entry-content .wrapper a:visited {
color: #ececec !important;
}
html[data-fea-theme="dark"] .entry-content .wrapper a:hover {
color: <?php echo esc_html($accent_dark); ?> !important;
}
/* Selector de idioma (fea-homepage.php) */
html[data-fea-theme="dark"] #fea-lang-btn { border-color: rgba(255,255,255,0.3); }
html[data-fea-theme="dark"] #fea-lang-btn:hover,
@@ -240,6 +352,10 @@ add_action('wp_footer', function () {
?>
<script>
(function() {
// El footer puede renderizarse más de una vez en algunos templates FSE.
// Evitamos crear un segundo toggle en ese caso.
if (document.getElementById('fea-theme-btn')) return;
var btn = document.createElement('button');
btn.id = 'fea-theme-btn';
btn.type = 'button';
+5 -1
View File
@@ -2,7 +2,11 @@
/** Propuesta/aplicación segura del backfill de _cita_evangelio. */
/** Uso: wp eval-file scripts/backfill_evangelio_meta.php [--apply] --path=/var/www/html */
$apply = in_array('--apply', $_SERVER['argv'] ?? [], true);
// WP-CLI no reenvía de forma consistente argumentos desconocidos a eval-file.
// El modo escritura exige por tanto una intención explícita y auditable:
// FEA_EVANGELIO_APPLY=1 wp eval-file scripts/backfill_evangelio_meta.php
$apply = getenv('FEA_EVANGELIO_APPLY') === '1'
|| in_array('--apply', $_SERVER['argv'] ?? [], true);
$posts = get_posts([
'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => -1,
'category__in' => fea_evangelio_comment_categories(),
+79
View File
@@ -0,0 +1,79 @@
"""doc_convert.py — convierte un .doc viejo a .docx usando Microsoft Word (COM).
Necesario para Marcos (marroro@telefonica.net), que envía .doc (Word antiguo) y
python-docx no sabe leer .doc. El contenido ya viene en EML (lo etiqueta Inma al
revisar); aquí solo cambiamos el FORMATO de archivo.
Requiere Microsoft Word instalado + pywin32 (igual que marcos_review).
API: doc_to_docx(path, force=False) -> Path | None
"""
from __future__ import annotations
from pathlib import Path
WD_FORMAT_DOCX = 16 # wdFormatDocumentDefault (.docx)
def doc_to_docx(path, force: bool = False):
"""Convierte un .doc a .docx con Word COM. Idempotente: si el .docx ya existe y
no force, lo devuelve sin reconvertir. Devuelve la ruta .docx, o None si falla."""
path = Path(path)
if path.suffix.lower() != ".doc":
return None
out = path.with_suffix(".docx")
if out.exists() and not force:
return out
try:
import win32com.client # type: ignore
except ImportError:
return None
word = win32com.client.Dispatch("Word.Application")
word.Visible = False
try:
d = word.Documents.Open(str(path))
d.SaveAs(str(out), FileFormat=WD_FORMAT_DOCX)
d.Close(SaveChanges=False)
finally:
word.Quit()
if out.exists():
quitar_smarttags(out)
return out if out.exists() else None
def quitar_smarttags(docx_path) -> int:
"""Desenvuelve los <w:smartTag> del .docx. Devuelve cuántos ha quitado.
⚠️ CRÍTICO, no es cosmético. Los .doc de Fray Marcos traen `smartTag` (el viejo
reconocimiento de nombres de Word) envolviendo expresiones como "la Iglesia" o
"la Cananea". **python-docx solo lee los <w:r> que cuelgan directamente del párrafo,
así que el texto de dentro del smartTag DESAPARECE sin dar error**: se publicaron
frases mutiladas en las cartas 736, 737 y 739 ("...no va dirigida a los apóstoles,
sino a dureza de la respuesta..."). Detectado el 12-ago-2026.
"""
import re, shutil, zipfile
from pathlib import Path
docx_path = Path(docx_path)
with zipfile.ZipFile(docx_path) as z:
piezas = {n: z.read(n) for n in z.namelist()}
xml = piezas.get("word/document.xml", b"").decode("utf-8", "replace")
nuevo, n = re.subn(r"</?w:smartTag(?:Pr)?\b[^>]*>|<w:attr\b[^>]*/>", "", xml)
if not n:
return 0
piezas["word/document.xml"] = nuevo.encode("utf-8")
tmp = docx_path.with_suffix(".docx.tmp")
with zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED) as z:
for nombre, datos in piezas.items():
z.writestr(nombre, datos)
shutil.move(str(tmp), str(docx_path))
return n
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("uso: python doc_convert.py path/al/archivo.doc", file=sys.stderr)
sys.exit(2)
res = doc_to_docx(Path(sys.argv[1]), force="--force" in sys.argv)
print(f"OK: {res}" if res else "FALLO (¿Word/pywin32?)")
sys.exit(0 if res else 1)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+69
View File
@@ -0,0 +1,69 @@
# `.doc` originales de Fray Marcos
Los 30 ficheros `.doc` (Word binario antiguo) tal y como los envía Fray Marcos por correo a
`ediciones@feadulta.com`, sin tocar. Subidos a petición de Rafa en el **issue #209**, para poder
reproducir y diffear desde este lado el problema de los `<w:smartTag>`.
## Por qué están aquí
`python-docx` **no lee el texto que va dentro de un `<w:smartTag>`**: lo salta sin dar error. Los `.doc`
de Fray Marcos arrastran esas etiquetas heredadas de versiones viejas de Word envolviendo expresiones
como «la Iglesia» o «la Cananea», así que al convertirlos se publicaban frases con palabras borradas en
silencio. Está corregido en `scripts/doc_convert.py` con `quitar_smarttags()`.
Ojo: la cadena `smartTag` **no aparece en el binario `.doc`**; surge al convertirlo a `.docx`, que es
formato OOXML. Para verlas hay que convertir primero.
## Cómo reproducir
```bash
python scripts/doc_convert.py "tests/fixtures/fray-marcos/739_8r_Marcos_d 20 la Cananea.doc"
```
Requiere Word instalado (la conversión va por COM). `doc_convert.py` desenvuelve los smartTag y hace el
reemplazo con reintentos, porque Dropbox bloquea el fichero unos segundos justo después de que Word lo
cree (WinError 1224).
## Alcance del problema (barrido cerrado en el #209)
De los 30 `.doc` revisados, 20 traían smartTag y sumaban 46 fragmentos envueltos, pero solo **3
artículos publicados quedaron dañados** (posts `53981`, `55078` y `55659`), ya reparados en producción.
Los comentarios de febrero a junio están intactos porque se publicaron por la vía de la migración de
Joomla, no desde el `.docx`; solo quedó expuesto lo publicado por Mixbot desde julio.
## Inventario
El prefijo numérico es el número de carta; el resto es el nombre original del fichero.
| carta | semana | fichero original |
|---:|---|---|
| 713 | semana_VI_TO | `713_8r_Marcos_d 06 plenitud de ley.doc` |
| 714 | semana_I_Cuaresma | `714_8r_Marcos_Cuar 1 tentaciones.doc` |
| 715 | semana_II_Cuaresma | `715_8r_Marcos_Cuar 2 Transfigurac.doc` |
| 716 | semana_III_Cuaresma | `716_8r_Marcos_Cuar 3 Samaritana.doc` |
| 717 | semana_IV_Cuaresma | `717_8r_Marcos_Cuar 4 ciego de naci.doc` |
| 718 | semana_V_Cuaresma | `718_8r_Marcos_Cuar 5 Lázaro.doc` |
| 719 | semana_Domingo_Ramos | `719_8r_Marcos_Cuar 6 Ramos.doc` |
| 720 | semana_Santa | `720_8r_Marcos_JUEVES SANTO.doc` |
| 720 | semana_Santa | `720_8r_Marcos_Pasc 1 resucitó.doc` |
| 720 | semana_Santa | `720_8r_Marcos_VIERNES SANTO.doc` |
| 721 | semana_II_Pascua | `721_8r_Marcos_Pasc 2 Tomás.doc` |
| 722 | semana_III_Pascua | `722_8r_Marcos_Pasc 3 Emaús.doc` |
| 723 | semana_IV_Pascua | `723_8r_Marcos_Pasc 4 pastor modelo.doc` |
| 724 | semana_V_Pascua | `724_8r_Marcos_Pasc 5 camino,verdad,vida.doc` |
| 725 | semana_VI_Pascua | `725_8r_Marcos_Pasc 6 El Paráclito.doc` |
| 726 | semana_VII_Pascua | `726_8r_Marcos_Pasc 7 ascensión.doc` |
| 727 | semana_Pentecostes | `727_8r_Marcos_PENTECOSTÉS.doc` |
| 728 | semana_Trinidad | `728_8r_Marcos_TRINIDAD.doc` |
| 729 | semana_Corpus | `729_8r_Marcos_CORPUS.doc` |
| 730 | semana_11_TO | `730_8r_Marcos_d 11 misión de los 12.doc` |
| 731 | semana_12_TO | `731_8r_Marcos_d 12 no tengas miedo.doc` |
| 732 | semana_13_TO | `732_8r_Marcos_d 13 amor a Dios o família.doc` |
| 733 | semana_14_TO | `733_8r_Marcos_d 14 sencillez.doc` |
| 734 | semana_15_TO | `734_8r_Marcos_d 15 sembrador.doc` |
| 735 | semana_16_TO | `735_8r_Marcos_d 16 cizaña.doc` |
| 736 | semana_17_TO | `736_8r_Marcos_d 17 tesoro y perla.doc` |
| 737 | semana_18_TO | `737_8r_Marcos_d 18 panes y peces.doc` |
| 738 | semana_19_TO | `738_8r_Marcos_d 19 Qué poca fe.doc` |
| 739 | semana_20_TO | `739_8r_Marcos_d 20 la Cananea.doc` |
| 740 | semana_21_TO | `740_8r_Marcos_d 21 quién es Jesús.doc` |