Contexto: Sesión del 10-ago-2026 en ~/Documents/trabajo-ago-26/ (functions-php.txt + widget.html). Tema: widget de noticias (tabs Automotriz/Fundación/Qardeal + De Cero a 100) y bridge RSS para FreshRSS.

Qué se hizo (orden)

  1. Bug Fundación corregido (functions-php.txt)

    • $domain = $source === 'https://fundaciongrupoandrade.org'; era comparación booleana (siempre false) → $api_url quedaba sin dominio. Fix: $domain = 'https://fundaciongrupoandrade.org';
  2. Credenciales Hostux a config

    • El RSS de automotriz tenía credenciales en claro (user=test56&token=andrade2026).
    • Ahora lee constantes GA_HOSTUX_RSS_USER / GA_HOSTUX_RSS_TOKEN de wp-config.php, con fallback define() dentro del endpoint para no romper si no se definieron.
  3. Widget: ocultar pestañas sin contenido (widget.html)

    • Al cargar consulta TODAS las fuentes en paralelo (fetch con r.ok check).
    • Pestaña sin posts (vacío o error) → display:none.
    • Si solo 1 funciona, se oculta la barra completa. Si 0, solo mensaje vacío.
    • Nada de refetch al hacer click (usa la copia ya descargada).
  4. Diagnóstico De Cero a 100

    • www.deceroacien.com.mx/rss/un_foto.html → 404. El sitio migró a Next.js (Editor 80).
    • admin.deceroacien.com.mx/rss/un_foto.html → 200 pero CONGELADO (última entrada 14-jul-2026).
    • Fuente fresca real: https://www.deceroacien.com.mx/sitemaps/news.xml (sitemap Google News, ~14 entradas con título, fecha, URL e imagen).
  5. Bridge RSS para FreshRSS (endpoint nuevo en functions-php.txt)

    • GET /wp-json/ga-blog/v1/feed/deceroacien → convierte news.xml a RSS 2.0 (title, link, guid, pubDate, media:content) con caché 4h.
    • Sirve XML via rest_pre_serve_request (header Content-Type: application/rss+xml).
    • URL para FreshRSS: https://TUSITIO/wp-json/ga-blog/v1/feed/deceroacien
    • ?force=true para refrescar.
  6. Imágenes de De Cero a 100 (descubrimiento clave)

    • www.../u/fotografias/... (feed viejo) → 403 (WAF).
    • img.editor80.com/... (sitemap) → 404.
    • assets.deceroacien.com.mx/... → 200 (fuente real).
    • El path real viaja EN BASE64 en el último segmento de la URL del sitemap: https://img.editor80.com/<sig>/rs:fill:.../<B64> → base64_decode → fotografias/2026/4/29/55831.jpg
    • Helper ga_deceroacien_image($url): decodifica y normaliza a https://assets.deceroacien.com.mx/<path>.
  7. Nueva fuente del widget: deceroacien

    • Rama elseif ($source === 'deceroacien') en ga_blog_fetch_source: parsea news.xml, toma 6 items, imágenes con ga_deceroacien_image().
    • Pestaña “De Cero a 100” agregada en widget.html.
  8. Caché fallback (nunca ver vacío)

    • Por fuente: ga_blog_cache_v6_<src> (12h) + ga_blog_cache_fallback_v6_<src> (30 días).
    • Bridge: ga_feed_deceroacien_v1 (4h) + ga_feed_deceroacien_fallback_v1 (30 días).
    • Prioridad: caché fresco → fetch vivo → copia de respaldo → vacío solo si nunca hubo datos.
    • ?force=true borra SOLO la caché fresca; el respaldo sobrevive.

Cómo probar

https://tusitio.com/wp-json/ga-blog/v1/fuente/automotriz?force=true
https://tusitio.com/wp-json/ga-blog/v1/fuente/fundacion?force=true
https://tusitio.com/wp-json/ga-blog/v1/fuente/qardeal?force=true
https://tusitio.com/wp-json/ga-blog/v1/fuente/deceroacien?force=true
https://tusitio.com/wp-json/ga-blog/v1/feed/deceroacien?force=true   (para FreshRSS)

Pendientes / notas

  • No hay PHP local en la Mac para hacer php -l (lint manual pendiente).
  • Qardeal: verificado que sitemap.xml es urlset plano con URLs /blog/ (funciona).
  • Si una imagen puntual de deceroacien falla: plan B = extraer og:image del artículo.
  • Opcional: flag stale en la respuesta para marcar contenido de respaldo en el widget.
  • wp-config.php debe llevar (opcional, hay fallback):
    define( 'GA_HOSTUX_RSS_USER', 'test56' );
    define( 'GA_HOSTUX_RSS_TOKEN', 'andrade2026' );