Prima il risultato
In 28 giorni, baccalaureat.sn è passato a 2.150 clic (+80%) e 31.800 impressioni (+82%) dalla ricerca Google, superando le soglie di 1.800 e poi 2.000 clic. Ecco il lavoro che ha prodotto questi numeri.
1. Il rendering lato server, base di tutto
Il blocco iniziale: la piattaforma era una SPA React, quasi invisibile a Googlebot (HTML vuoto al caricamento). La migrazione verso Symfony + Turbo ha cambiato tutto — ogni pagina restituisce ora HTML completo, indicizzabile immediatamente.
Verifica semplice di ciò che vede il crawler:
curl -A "Googlebot" https://baccalaureat.sn/annales | grep -c "annale-card"
# renvoie un nombre > 0 : le contenu est bien present dans le HTML servi,
# pas seulement injecte en JS apres coup
2. Pagine mirate all'intento di ricerca
Gli studenti cercano query precise: «annales bac S1 Sénégal», «statistiques bac 2024». Ho creato pagine dedicate per serie, per materia, per anno — ciascuna ottimizzata per il suo intento.
#[Route('/annales/{serie}', name: 'annales_serie')]
public function parSerie(string $serie, AnnaleRepository $repo): Response
{
    $annales = $repo->findBySerie($serie);

    return $this->render('annales/serie.html.twig', [
        'serie'     => $serie,
        'annales'   => $annales,
        'metaTitle' => "Annales {$serie} · Baccalauréat Sénégal",
        'metaDesc'  => "Toutes les épreuves série {$serie} du bac sénégalais, par matière et par année.",
    ]);
}
3. Dati strutturati JSON-LD
I dati strutturati aiutano Google a comprendere il contenuto e sbloccano i risultati arricchiti.
{# templates/annales/show.html.twig #}
{% set jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'LearningResource',
    'name': annale.matiere ~ ' - ' ~ annale.serie ~ ' - ' ~ annale.annee,
    'educationalLevel': annale.serie,
    'inLanguage': 'fr',
    'datePublished': annale.createdAt|date('c'),
} %}
<script type="application/ld+json">{{ jsonLd|json_encode|raw }}</script>
4. Sitemap dinamica e robots
Una sitemap generata dal database, mantenuta aggiornata automaticamente, aiuta Google a scoprire ogni pagina.
#[Route('/sitemap.xml', name: 'sitemap', defaults: ['_format' => 'xml'])]
public function sitemap(AnnaleRepository $repo): Response
{
    $urls = [];
    foreach ($repo->findAllPublished() as $a) {
        $urls[] = [
            'loc'     => $this->generateUrl('annale_show', ['slug' => $a->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
            'lastmod' => $a->getUpdatedAt()->format('c'),
        ];
    }
    $response = $this->render('sitemap.xml.twig', ['urls' => $urls]);
    $response->headers->set('Content-Type', 'application/xml');
    return $response;
}
5. Misurare e iterare
La Search Console è il cruscotto della SEO. Si vedono quali pagine salgono (la home: +386%, gli annales: +440%), quali stagnano, e su quali query posizionarsi in seguito. La SEO non è un one-shot, è un ciclo.
Cosa porto a casa
  • Il rendering lato server è un prerequisito non negoziabile per contenuti che devono rankare.
  • Una pagina = un intento di ricerca preciso. La granularità paga.
  • I dati strutturati JSON-LD aiutano Google a comprendere e arricchire la visualizzazione.
  • Sitemap dinamica: ogni nuovo contenuto viene scoperto in fretta.
  • La Search Console guida l'iterazione: si segue ciò che sale, si rafforza.