Come ho costruito un archivio strutturato del caso Garlasco con PHP, Google News e schema markup

Quando un caso giudiziario italiano torna sotto i riflettori, le ricerche su Google esplodono per giorni. “Caso garlasco” oggi vale oltre 100.000 ricerche al mese in Italia. Le notizie però sono frammentate su decine di testate: ANSA, Repubblica, Corriere, Sky TG24, Mediaset, AGI, Adnkronos. Chi cerca un quadro d’insieme deve aprire venti tab.

Ho deciso di costruire un sito-archivio che aggregasse tutto in modo strutturato: cronologia, personaggi, prove, processi, news live. Tutto self-hosted, con PHP vanilla, senza CMS, in circa 8 ore di lavoro. Il sito è online a CasoGarlasco.it ed è indicizzato in prima pagina di Google per query competitive entro 24 ore dal lancio.

Questo articolo è il case study tecnico di come l’ho costruito. Niente fluff, solo decisioni architetturali concrete e codice.

La sfida tecnica

Un sito-archivio su un caso giudiziario aperto deve risolvere quattro problemi diversi:

  1. Aggregare news in tempo reale da decine di fonti, senza scraping abusivo
  2. Strutturare dati storici (cronologia, personaggi, prove) in modo che siano editabili facilmente
  3. Performance da prima pagina Google: load time sotto 1.5s, schema markup completo, mobile-first
  4. Rispetto legale assoluto: presunzione di innocenza, attribuzione delle fonti, niente diffamazione

Quattro problemi che, presi insieme, scoraggerebbero la maggior parte degli sviluppatori dal partire. Vediamo come li ho affrontati.

Stack tecnico (volutamente minimale)

  • HTML/CSS/JS vanilla per il frontend (zero framework)
  • PHP 8 per i due endpoint server (news proxy + scanner)
  • JSON come database (un singolo data.json aggiornato a mano)
  • Leaflet.js per la mappa interattiva
  • OpenStreetMap + CartoDB Dark per i tile mappa (gratis, dark mode)
  • Google Fonts: Fraunces + JetBrains Mono + Inter
  • Cloudflare Web Analytics (cookieless, no banner cookie)

Nessuna dipendenza npm. Nessun framework. Nessun database. Tutto deploy via FTP. Il sito intero pesa meno di 100 KB caricato.

Questa scelta non è nostalgica: è strategica. Meno dipendenze = meno breakage, e per un progetto solitario che voglio mantenere per anni, ogni dipendenza è un debito tecnico futuro. PHP 8 è installato su ogni hosting low-cost, Leaflet è stabile da una decade, e i JSON sono editabili con qualsiasi editor.

Architettura: due endpoint, un file dati, un frontend

Il sito è una single-page application con dieci sezioni navigabili tramite anchor link. Tutta la logica server è in due file PHP da poche centinaia di righe ciascuno:

news.php — Il proxy Google News

Google News offre un feed RSS pubblico ma per query specifiche. Il problema è che chiamarlo direttamente dal browser viene bloccato da CORS, e i servizi pubblici di aggregazione (rss2json, AllOrigins) hanno rate limit aggressivi.

La soluzione: un proxy PHP che fa la richiesta server-side, parsa il feed con simplexml, cacha il risultato per 10 minuti su filesystem, e serve un JSON pulito al frontend.

php

$query = '(garlasco OR "Andrea Sempio" OR "Chiara Poggi" OR "Alberto Stasi" OR "Mario Venditti")';
$url = 'https://news.google.com/rss/search?' . http_build_query([
    'q'    => $query,
    'hl'   => 'it',
    'gl'   => 'IT',
    'ceid' => 'IT:it',
]);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT        => 15,
    CURLOPT_USERAGENT      => 'Mozilla/5.0 (compatible; CasoGarlascoBot/1.0)',
]);
$xml = curl_exec($ch);

Il cache filesystem (news-cache.json) è semplice e robusto: se la modifica è recente meno di 10 minuti, servo quel file. Altrimenti faccio una nuova chiamata e aggiorno il file con rename atomico per evitare race condition.

Risultato: il frontend chiama news.php ogni 5 minuti dal browser. Google News viene contattato al massimo 6 volte all’ora (ogni 10 minuti di cache). Sostenibile per qualsiasi hosting low-cost.

update.php — Lo scanner intelligente

Qui c’è la parte interessante. Lo scanner ogni 2 ore (via cron) prende i 30 articoli più recenti, e per ognuno:

  1. Estrae le persone tracciate (Andrea Sempio, Alberto Stasi, Mario Venditti, ecc.) tramite pattern matching sul titolo + description
  2. Estrae gli eventi giudiziari (udienza, sentenza, perquisizione, perizia, revisione, ecc.)
  3. Categorizza la news in processo, indagine, perizie, corruzione, famiglia, intercettazioni
  4. Deduplica confrontando con l’archivio esistente
  5. Scrive in news-archive.json un payload arricchito (titolo, fonte, data, link, persone, eventi, categoria)

Il regex per le persone è case-insensitive e cerca varianti:

php

$peopleMap = [
    'andrea sempio'       => 'Andrea Sempio',
    'alberto stasi'       => 'Alberto Stasi',
    'mario venditti'      => 'Mario Venditti',
    // ...
];
foreach ($peopleMap as $key => $name) {
    if (strpos($full, $key) !== false) {
        $foundPeople[$name] = true;
    }
}

La categorizzazione automatica usa pattern di parole chiave:

php

function categorize($text) {
    $t = strtolower($text);
    if (preg_match('/\b(sentenza|condanna|cassazione|revisione)\b/u', $t)) return 'processo';
    if (preg_match('/\b(dna|impronta|perizia|consulenza)\b/u', $t)) return 'perizie';
    if (preg_match('/\b(interrogator|indagat|perquisizion)\b/u', $t)) return 'indagine';
    // ...
    return 'cronaca';
}

Lezione importante: lo scanner non aggiorna mai automaticamente data.json (la cronologia ufficiale del sito). Su un caso giudiziario aperto, ogni affermazione del sito è un potenziale rischio diffamazione. Lo scanner suggerisce in incoming.json, ma le decisioni editoriali restano umane. Solo la rassegna stampa (news-archive.json) è automatica, perché è rassegna pura: titolo + link alla fonte originale.

Il problema legale (e perché è una feature)

Un sito su un caso giudiziario in corso è un campo minato:

  • Diffamazione: Sempio è indagato, non condannato. Ogni affermazione che lo collega all’omicidio in modo non-attribuito è rischio causa civile + penale
  • Segreto istruttorio: leak di atti riservati possono configurare reato
  • Diritto d’autore: foto, video, audio da TV/giornali sono protetti
  • Privacy: la famiglia della vittima ha fatto causa a testate per uso non autorizzato di foto

Ho risolto con tre regole rigide impostate dall’inizio:

  1. Mai foto delle persone coinvolte. Solo SVG illustrativi e avatar generati con le iniziali del nome. Zero rischio copyright, zero rischio privacy
  2. Mai affermazioni dirette. Ogni voce della cronologia ha un campo fonti[] obbligatorio con almeno un link verificabile. Ogni card news mostra esplicitamente “Sky TG24 / 12 maggio 2026”
  3. Banner disclaimer permanente in cima a ogni pagina: “Presunzione di innocenza per tutti gli indagati”

Queste regole non sono burocrazia: sono protezione attiva. Un avvocato che valuta una causa diffamazione contro un sito vede questi elementi e quasi sempre rinuncia. La probabilità di vincere contro un sito che “non afferma” ma “riporta” è bassa.

Performance SEO: cosa premia Google

Il sito è online da 24 ore mentre scrivo questo articolo. Search Console mostra 49 impressioni sulle prime 24 ore, con posizione media 7.86 su query competitive tipo “caso garlasco” e “delitto garlasco” (posizione 5 in prima pagina). Per un dominio nuovo in tema YMHL, è risultato eccezionale.

Quattro elementi tecnici che hanno fatto la differenza:

1. Schema markup completo

Tre tipi di schema annidati in un singolo <script type="application/ld+json">:

  • WebSite: nome, URL, lingua, descrizione
  • NewsArticle: titolo, data pubblicazione, autore, publisher
  • FAQPage: 6 domande FAQ con risposte (le query più cercate su Google)

Lo schema FAQPage è particolarmente potente: Google mostra le risposte direttamente in SERP come rich snippet, aumentando il CTR del 10-20%.

2. Title e meta description ottimizzati per intent

html

<title>Caso Garlasco: cronologia, indagati e prove in tempo reale | CasoGarlasco.it</title>
<meta name="description" content="Caso Garlasco: cronologia completa dal 2007, indagati attuali (Andrea Sempio, Mario Venditti, Giuseppe Sempio), prove (DNA, impronta 33, scontrino Vigevano), tutti i gradi di giudizio. Aggiornato in tempo reale, solo fonti verificate." />

Il title contiene il keyword principale all’inizio, poi due keyword secondarie (“cronologia”, “indagati”). La meta description elenca tutti i nomi rilevanti (Google li usa per il ranking) e termina con un value proposition (“solo fonti verificate”).

3. Mobile-first responsive con dark mode

Lo stile usa CSS variables, dark mode di default, tipografia serif elegante (Fraunces) per i titoli + mono (JetBrains) per i terminali “in stile retrocomputing”. Tre media query gestiscono il responsive: 880px, 640px, e default.

Google Lighthouse Mobile: 96 su Performance, 100 su SEO, 100 su Accessibility.

4. Aggiornamento contenuto continuo

Il cron che gira ogni 2 ore aggiorna news-archive.json con nuove news. Anche se il sito è single-page e i contenuti principali (cronologia, personaggi) cambiano poco, Google vede che /news-archive.json cambia continuamente, e interpreta il sito come “attivo”.

L’idea che Google premi i siti con contenuto fresh è vera, ma con un caveat: il contenuto fresh deve essere rilevante e non spam. Una rassegna stampa categorizzata e taggata è rilevante. Un’auto-generazione di articoli AI sarebbe spam e verrebbe penalizzata.

I dettagli che fanno la differenza

Tre piccole scelte che hanno avuto impatto sproporzionato:

  • Banner disclaimer in cima (sopra l’header): segnale di seriosità sia agli utenti che a Google
  • Tag colorati per persona/evento nelle card news (chip ambra per persone, cyan per eventi): aumenta engagement e tempo sulla pagina
  • Filtri categoria in alto alla sezione news: trasforma il sito da aggregatore passivo a strumento di consultazione

Quest’ultimo è il “value add” che Google cerca quando valuta un aggregatore. Non bastano i link, serve l’organizzazione.

Cosa farei diversamente

Tre cose che cambierò nelle prossime settimane:

  1. Pagine dettaglio per ogni persona: ora i personaggi sono card in una grid. Diventare pagine standalone con URL canonici (/personaggi/andrea-sempio/) sbloccherebbe ranking individuale per ogni query “chi è X”
  2. BreadcrumbList schema: già pianificato, aggiungerò navigazione strutturata in JSON-LD
  3. Newsletter con pacchetto settimanale automatico: opt-in nativo, valore aggiuntivo per gli utenti, fonte di traffico ricorrente

Conclusioni: il vero ROI del minimal stack

Otto ore di lavoro. Zero costi fissi mensili (hosting a 30€/anno, dominio a 10€/anno). Niente CMS da aggiornare, niente plugin che si rompono, niente dipendenze npm da auditare. Il sito sopravvive a chiunque lo costruisca, perché chiunque sa leggere HTML e PHP.

Negli ultimi anni il discorso pubblico SEO si è spostato su tool complessi (headless CMS, frameworks edge, generative AI). La verità però è che la maggior parte dei siti piccoli/medi non ha bisogno di nulla di tutto ciò. Un PHP onesto, un JSON ben strutturato, un CSS curato, e schema markup completo battono regolarmente stack moderni mal configurati.

Il caso Garlasco è un esempio concreto di SEO tecnico ben fatto. Se vuoi vedere il progetto live, è a CasoGarlasco.it. Tutti i pattern descritti in questo articolo sono replicabili su qualsiasi tema verticale: un caso giudiziario, un trend di cronaca, un evento sportivo, una crisi sanitaria, una serie TV in corso.

L’opportunità c’è sempre: il problema è solo il tempo di esecuzione.

Articoli simili