Salta ai contenuti

Architettura

Il template ha quattro attori. Tenerli separati è la regola che rende il resto prevedibile.

┌──────────────┐ REST JSON ┌────────────────────────┐ file ┌──────────────┐
│ WordPress │ ──────────────► │ Build Astro (Node) │ ─────────► │ Hosting │
│ admin + API │ │ Zod → mapper → store │ │ statico │
└──────────────┘ └────────────────────────┘ └──────────────┘
│ ▲ │
│ salvataggio contenuto │ repository_dispatch │ HTTPS
└──────────── webhook ───────────────┴────────────────────────────────┘
▼
Browser

Fa solo due cose:

  1. Redazione: pagine, CPT, metabox, media library, impostazioni sito.
  2. API: espone i contenuti in REST (/wp-json/...), in sola lettura per il pubblico.

Non renderizza il sito. Non ha un tema attivo usato dal frontend. Non è raggiungibile dal browser dell’utente finale se non per l’admin.

Gira su Node, in locale o in GitHub Actions. Per ogni collezione:

  1. chiama un endpoint REST;
  2. valida la risposta con Zod (unknown → dato tipizzato);
  3. risolve gli ID delle immagini in URL (una richiesta batch per collezione);
  4. mappa il dato WordPress nel modello di dominio usato dai componenti;
  5. scrive l’entry nello store del Content Layer.

Poi renderizza le pagine in HTML e produce CSS, JS delle isole, sitemap e asset. Se un contratto è rotto e ENABLE_HTML_FALLBACK=false, la build fallisce: meglio un deploy rosso che un sito con dati sbagliati.

Riceve HTML già pronto. Scarica JavaScript solo per le isole interattive (form contatti, filtri eventi, carosello partner, banner cookie, mappa con consenso). Nessuna chiamata al database, nessun CMS a runtime.

Serve file statici. Può essere un hosting FTP/FTPS tradizionale (il workflow incluso), Netlify, Cloudflare Pages, un bucket S3 o qualsiasi CDN. Non serve PHP né MySQL.

Percorso Responsabilità
src/data/site.ts identità, navigazione, CTA, fallback contatti
src/styles/tokens.css colori, font, motion: unica fonte di stile
src/pages/ rotte e struttura delle pagine
src/components/ sezioni Astro e isole Preact
src/domain/ modelli puliti usati dai componenti
src/cms/wordpress/ client REST, loader, schema Zod, mapper per CPT
src/content.config.ts collezioni = CPT WordPress
src/lib/ env, impostazioni sito, date eventi, consenso
wordpress/mu-plugins/ backend WordPress: CPT, impostazioni, contatti, webhook
tests/ Vitest + fixture JSON del contratto dati
guide/ questa guida (Starlight)
.github/workflows/ quality, deploy del sito, pubblicazione guida

Esempio: /eventi/[slug].

  1. src/pages/eventi/[slug].astro esporta getStaticPaths().
  2. getCollection("eventi") legge lo store già popolato dal loader.
  3. Per ogni evento genera una pagina statica con hero, dettagli, agenda e CTA.
  4. Il browser riceve HTML; nessuna richiesta a WordPress.

Il contenuto è “cotto” nella build. Per questo serve il rebuild quando cambia.

  • I componenti non conoscono WordPress: ricevono un Evento, una Tariffa, una Faq.
  • Se domani il CMS cambia, si riscrive solo src/cms/.
  • Gli schema Zod descrivono il contratto esterno; i modelli descrivono ciò che serve alla UI.

Questa separazione costa un file di mapper per CPT ed è la ragione per cui il codice resta leggibile quando i CPT diventano dieci.

  • Database nel frontend: nessuna connessione, nessun ORM.
  • API runtime: nessun endpoint che il browser chiama per i contenuti.
  • Tema WordPress: WordPress non produce HTML pubblico.
  • Cache applicativa: ogni build rifà le stesse richieste; è economico e prevedibile (vedi Build e concorrenza).