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 ───────────────┴────────────────────────────────┘ ▼ BrowserWordPress
Sezione intitolata “WordPress”Fa solo due cose:
- Redazione: pagine, CPT, metabox, media library, impostazioni sito.
- 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.
La build Astro
Sezione intitolata “La build Astro”Gira su Node, in locale o in GitHub Actions. Per ogni collezione:
- chiama un endpoint REST;
- valida la risposta con Zod (
unknown→ dato tipizzato); - risolve gli ID delle immagini in URL (una richiesta batch per collezione);
- mappa il dato WordPress nel modello di dominio usato dai componenti;
- 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.
Il browser
Sezione intitolata “Il browser”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.
L’hosting
Sezione intitolata “L’hosting”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.
Dove sta cosa nel repository
Sezione intitolata “Dove sta cosa nel repository”| 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 |
Il flusso di una pagina
Sezione intitolata “Il flusso di una pagina”Esempio: /eventi/[slug].
src/pages/eventi/[slug].astroesportagetStaticPaths().getCollection("eventi")legge lo store già popolato dal loader.- Per ogni evento genera una pagina statica con hero, dettagli, agenda e CTA.
- Il browser riceve HTML; nessuna richiesta a WordPress.
Il contenuto è “cotto” nella build. Per questo serve il rebuild quando cambia.
Perché separare domain da cms
Sezione intitolata “Perché separare domain da cms”- I componenti non conoscono WordPress: ricevono un
Evento, unaTariffa, unaFaq. - 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.
Cosa non c’è (per scelta)
Sezione intitolata “Cosa non c’è (per scelta)”- 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).