Via WordPress: rifare il sito statico con Claude Code, a costo zero

/Architetture software/di Gianluca Epifani

Via WordPress: rifare il sito statico con Claude Code, a costo zero

Premessa

Se avete un sito vetrina, un blog o un piccolo sito istituzionale su WordPress, probabilmente lo aggiornate poche volte l’anno e intanto pagate un hosting, ricevete avvisi di aggiornamento per tema e plugin, e qualcuno prova a entrare in /wp-login.php ogni notte. Questo sito era esattamente così dal 2018.

L’ho rifatto statico in un paio di giorni, e la parte interessante non è il risultato: è quanto poco ho scritto io. Claude Code ha scaricato i contenuti dal vecchio sito, ha costruito il nuovo, ha scritto il form, i redirect, la pagina 404 e la checklist di verifica. Io ho preso le decisioni, ho fatto i passaggi nella dashboard del provider e ho controllato.

Questo post è la procedura, scritta per chi vuole rifarla. La tesi è semplice: se decidete gli strumenti prima, e li scrivete in un file che Claude legge, il lavoro lo fa lui. Se invece lasciate che li scelga lui a ogni passo, otterrete un sito diverso a ogni sessione.

Per chi ha senso

Funziona bene per siti che cambiano quando lo decidete voi: una manciata di pagine, un blog, un form contatti, immagini. Non ha senso per un sito aggiornato ogni giorno da più persone con plugin, gallerie e widget, né per un e-commerce. Lì WordPress (o comunque un sito dinamico) resta una scelta obbligata.

Gli strumenti, decisi prima

Questa è la lista che ho usato io e che consiglio come punto di partenza. Ogni card indica le alternative valide, perché la scelta giusta dipende da due cose che cambiano da sito a sito: dove sta il DNS e dove sta la posta.

1. Hosting: un Worker Cloudflare con asset statici. Il sito è una cartella di file; il Worker è la piccola funzione che li serve e gestisce le poche cose dinamiche (il form, i redirect fra apex e www). Piano gratuito, nessun server.

2. Generatore: Next.js con export statico. L’ho scelto perché un sito pubblico necessita di SEO… e il SEO non va tanto d’accordo con pagine in javascript renderizzate client side (quello che accade con una web-app realizzata con un framework javascript come SPA). Alla build produce HTML, CSS e JS puri; in produzione non gira Node.

3. Contenuti: file JSON tipizzati nel repository, non un database. I testi delle pagine, gli articoli (con il loro HTML pulito), i dati del sito stanno in pochi file JSON con uno schema TypeScript. I componenti non contengono una sola stringa: se manca un campo, la build fallisce invece di mostrare una pagina vuota. Il database di WordPress non serve più.

4. Form contatti: Email Routing di Cloudflare. È la funzione che inoltra la posta del dominio a una casella esterna, e permette a un Worker di inviare email, gratis, purché il destinatario sia un indirizzo verificato lì. Per un form contatti è esattamente il caso. Niente servizio esterno, niente chiave API.

5. DNS: la zona su Cloudflare. Si cambiano i nameserver presso il registrar e da quel momento i record si gestiscono da Cloudflare. Serve per il Worker con dominio proprio, per Email Routing e per HTTPS forzato.

6. Codice su GitHub. Repository privato va benissimo. Il deploy parte dal computer con un comando, o da GitHub Actions se volete pubblicare senza aprire il terminale.

Cosa dire a Claude Code, nell’ordine

0. Il brief, in un file che resta

Prima di tutto fate scrivere a Claude un CLAUDE.md alla radice del progetto. Lo rilegge a ogni sessione: tutto ciò che sta lì non dovrete ripeterlo. Il mio, ridotto all’essenziale:

markdown
# <dominio> — da WordPress a sito statico

## Obiettivo
Replicare il sito WordPress come sito statico su un Worker Cloudflare,
con form contatti via Email Routing, contenuti in JSON tipizzati.
Poi switch del dominio e spegnimento del WordPress.

## Strumenti (decisi, non proporre alternative)
- Next.js con export statico, URL con slash finale come su WordPress.
- Contenuti in src/content/data/*.json con tipi TypeScript; i componenti
  non contengono testi.
- Worker con asset statici; dinamico solo /api/contact.
- Form: binding send_email verso <indirizzo verificato>.
- DNS: zona su Cloudflare. Sottodominio di prova: new.<dominio>.

## Regole
- Sito statico: niente route handler, niente server action.
- Colori e font sono token in globals.css, mai hard-coded.
- Commit per file, mai `git add -A`.
- Prima del deploy: typecheck, lint, build.
- Annota qui sotto gli errori trovati e le decisioni prese, man mano.

L’ultima riga vale più di tutte: Claude aggiorna il file con quello che scopre (un’API che rifiuta una richiesta, una pagina del vecchio sito che era testo demo) e la sessione successiva riparte da lì invece che da zero.

1. L’inventario del sito vecchio

Scarica tutto dal sito WordPress: pagine, articoli e media via REST API (/wp-json/wp/v2/pages, posts, media), più l’HTML delle pagine. Fai l’inventario: pagine con i loro URL, articoli con date e URL, menu, form, immagini, redirect esistenti. Poi interroga il DNS del dominio (A, CNAME, MX, TXT, mail, smtp, imap, autoconfig, autodiscover) e salva tutto in un file.

Nel mio caso l’inventario ha rivelato che la pagina Contatti conteneva ancora il testo dimostrativo del tema, con un indirizzo di Los Angeles, e che il menu “Blog” puntava a una pagina inesistente. Sono cose che si decidono prima di scrivere codice: quali pagine tenere, quali rifare, quali buttare.

2. Il progetto nuovo e i contenuti

Crea il progetto Next.js con export statico. Estrai i testi dell’inventario in JSON tipizzati. Per gli articoli prendi l’HTML renderizzato, togli classi del page builder, script e srcset assoluti, e tienilo in un campo html. Scarica le immagini e convertile in WebP ridimensionate. Replica le pagine con gli stessi URL (slash finale), più indice del blog, categorie, pagina 404, sitemap e robots.

Il risultato di questo passo è un sito che gira in locale, uguale al vecchio nei contenuti e migliore nella grafica, perché il tema non c’è più e i colori sono quattro token in un file CSS. Le immagini del mio sito sono passate da diversi megabyte a poco più di uno.

3. Il Worker, il form, i redirect

Scrivi il Worker che serve la cartella dell’export, reindirizza l’apex a www e gestisce /api/contact: valida nome, email e messaggio, campo esca per i bot, consenso privacy, invio con il binding send_email e replyTo sul mittente. Scrivi _redirects con i vecchi URL degli articoli (/anno/mese/giorno/slug/ → /blog/slug/), le categorie, il feed, e /wp-login.php, /wp-admin/*, /xmlrpc.php verso la home. Scrivi _headers con gli header di sicurezza e la cache lunga per gli asset.

Il Worker deve vedere tutte le richieste, non solo quelle sotto /api/: la prima versione lasciava passare i file prima del codice, e il redirect dall’apex non scattava mai perché la home esisteva come file. È il genere di cosa che finisce nel CLAUDE.md.

4. Sottodominio di prova e checklist

Fai il deploy su new.<dominio> e verifica con curl: tutte le pagine in 200, ogni redirect dei vecchi URL, una pagina inesistente in 404 con la pagina personalizzata, gli header, nessun link interno rotto. Fai screenshot desktop e mobile delle pagine principali.

Due difetti sono usciti solo da questo giro: i blocchi di codice sfondavano la pagina sotto i 640 pixel, e un link esterno puntava a un sito con il certificato rotto. Il form va provato con un messaggio vero, e la mail deve arrivare.

5. Il DNS, con Claude come guida

Questa parte si fa nella dashboard e nel pannello del registrar, non nel terminale: aggiunta della zona, confronto dei record importati con il file del passo 1, nameserver nuovi sul registrar, verifica dell’indirizzo di destinazione in Email Routing (arriva una mail, si clicca), eventuale catch-all. Claude non può farla al posto vostro, ma può dirvi cosa cliccare e controllare il risultato con dig a ogni passo. Per il mio dominio .it il cambio di nameserver è stato recepito in pochi minuti.

6. Lo switch

Il sito di prova è verificato. Prepara il deploy con www.<dominio> e <dominio> come domini personalizzati del Worker, e dimmi quali record DNS devo cancellare a mano prima.

Qui c’è l’unico momento delicato: il Worker con dominio proprio non si installa sopra record DNS che esistono già, l’API rifiuta la richiesta. I record A e CNAME del vecchio sito vanno cancellati a mano e, nei secondi fra la cancellazione e il deploy, il sito è irraggiungibile. Si fanno uno dietro l’altro, con il comando già pronto. Poi “Usa sempre HTTPS” sulla zona, e la stessa checklist del passo 4 sul dominio vero.

7. Spegnere WordPress

Prima un backup completo, da tenere: export XML, dump del database, cartella uploads. Poi si spegne. Da quel momento i bot che cercano /wp-login.php ricevono un redirect alla home, senza eseguire una riga di codice.

Cosa resta nelle vostre mani

Claude Code scrive il codice e vi guida nelle dashboard, ma alcune cose le fate voi, ed è giusto così:

  • gli account del provider cloud e di GitHub, e il login dei loro strumenti da riga di comando;
  • il registrar e i nameserver;
  • la verifica dell’email di destinazione e la cancellazione dei record DNS;
  • il deploy in produzione, che Claude prepara e voi lanciate;
  • ogni credenziale: chiavi e token si incollano da un terminale vero o nella dashboard, non nella chat.

Quanto costa

Il conto del nuovo sito, dominio a parte, è zero: Worker, Email Routing e GitHub stanno nei piani gratuiti, e i limiti di quei piani sono di un ordine di grandezza sopra il traffico di un sito come questo. Quello che ho tolto conta di più: un hosting a canone, un interprete PHP e un database accesi per servire pagine fisse, un tema e quattro plugin da aggiornare, una pagina di login esposta a chiunque.

Il costo vero è un paio di giorni di lavoro, quasi tutti spesi a decidere e a controllare. È il modo giusto di spenderli.