Wordpress

WordPress headless: architetture e vantaggi per siti web moderni

WordPress headless: architetture e vantaggi per siti web moderni
LT
Luca Terribili
Autore

WordPress headless è un'architettura che separa il sistema di gestione dei contenuti dal frontend che li presenta agli utenti. WordPress continua a occuparsi di articoli, pagine, utenti e contenuti multimediali, mentre un'applicazione separata si occupa di generare l'interfaccia pubblica.

Questo approccio consente di utilizzare WordPress come CMS senza essere obbligati a utilizzare i suoi temi PHP per visualizzare i contenuti. Il frontend può essere sviluppato con Next.js, React, Vue o altre tecnologie, mentre la comunicazione tra i due sistemi avviene attraverso un'API.

La separazione offre opportunità interessanti, ma introduce anche nuove responsabilità: occorre gestire il rendering delle pagine, la cache, la pubblicazione dei contenuti, le anteprime e l'autenticazione delle operazioni riservate.

In questa guida realizzeremo una prima integrazione concreta tra WordPress e Next.js utilizzando la REST API nativa del CMS. Vedremo come recuperare gli articoli pubblicati, visualizzarli nel frontend e distinguere le richieste pubbliche da quelle che richiedono autenticazione.

Che cos'è un'architettura WordPress headless

In una configurazione WordPress tradizionale, il CMS gestisce sia i contenuti sia la loro presentazione. Il backend permette di scrivere gli articoli, mentre il tema PHP genera le pagine HTML che vengono inviate al browser.

In un'architettura headless, invece, le due responsabilità vengono separate.

WordPress rimane il sistema di gestione dei contenuti, ma il frontend è realizzato da un'applicazione indipendente. Quest'ultima recupera i dati attraverso un'interfaccia di programmazione, normalmente la REST API integrata in WordPress oppure un'API GraphQL fornita da un plugin.

L'architettura può essere rappresentata così:

Redattore
    |
    v
WordPress
    |
    | REST API / JSON
    v
Applicazione Next.js
    |
    v
HTML generato e interfaccia pubblica

Il redattore continua a utilizzare il pannello amministrativo di WordPress. L'applicazione Next.js recupera invece i contenuti e li trasforma nelle pagine che i visitatori vedono.

La REST API è inclusa nel core di WordPress dalla versione 4.7, pubblicata nel dicembre 2016. Non è quindi necessario installare un plugin aggiuntivo per recuperare i normali articoli pubblici. Per utilizzare GraphQL, invece, è generalmente necessario installare e configurare un'estensione dedicata.

La documentazione ufficiale è disponibile all'indirizzo:

https://developer.wordpress.org/rest-api/

Vantaggi e limiti di WordPress headless

Prima di iniziare lo sviluppo, è importante capire quali problemi questa architettura risolve e quali, invece, introduce.

Flessibilità del frontend

Separando la presentazione dal CMS, possiamo sviluppare un'interfaccia personalizzata con le tecnologie più adatte al progetto.

Next.js, per esempio, permette di utilizzare React e di scegliere tra diverse strategie di rendering, tra cui rendering lato server, generazione statica e aggiornamento dei contenuti attraverso la cache.

Lo stesso backend WordPress può alimentare un sito web, un'applicazione mobile o altri sistemi che consumano la sua API. Ogni frontend può avere un'interfaccia diversa senza dover duplicare necessariamente il sistema di gestione dei contenuti.

Prestazioni e caching

Un frontend disaccoppiato può essere distribuito su un'infrastruttura ottimizzata per servire pagine HTML, risorse statiche e contenuti memorizzati nella cache.

Questo può ridurre il carico sul backend WordPress e migliorare i tempi di risposta, soprattutto quando le pagine pubbliche vengono generate in anticipo o servite da una rete CDN.

Non significa, però, che un sito headless sia automaticamente più veloce di un sito WordPress tradizionale. Il risultato dipende dalla strategia di rendering, dalle chiamate API, dalla cache, dall'infrastruttura e dalla quantità di JavaScript eseguito nel browser.

Un tema WordPress ben realizzato, con caching e ottimizzazione adeguati, può essere molto performante.

Sicurezza

Separare frontend e backend permette di isolare alcuni componenti e di applicare politiche di accesso differenti. Il frontend pubblico può, per esempio, consumare soltanto dati pubblici, mentre le operazioni amministrative rimangono riservate a richieste autenticate.

La separazione non rende automaticamente sicuro il sistema. WordPress deve comunque essere aggiornato e protetto, le API devono applicare i controlli di autorizzazione appropriati e le credenziali non devono essere esposte al browser.

Un'applicazione Next.js vulnerabile può comunque compromettere dati, sessioni o servizi collegati. L'architettura introduce confini di sicurezza utili, ma non sostituisce le normali misure di protezione.

Complessità e funzionalità da ricostruire

Il principale svantaggio è la maggiore complessità operativa.

Con un tema tradizionale, WordPress gestisce direttamente numerosi aspetti della presentazione. In un'architettura headless, invece, lo sviluppatore deve progettare il frontend e integrare le funzionalità necessarie.

Tra gli elementi che potrebbero richiedere un'implementazione aggiuntiva troviamo:

  • Anteprime dei contenuti non ancora pubblicati.
  • Ricerca e filtri personalizzati.
  • Paginazione e navigazione.
  • Gestione delle immagini e dei metadati SEO.
  • Aggiornamento della cache dopo la pubblicazione.
  • Redirect e gestione degli URL.
  • Integrazione con plugin che presuppongono la presenza di un tema WordPress.

Anche l'editor a blocchi Gutenberg può continuare a essere utilizzato nel backend, ma la visualizzazione finale dei blocchi deve essere supportata dal frontend. Le anteprime possono essere realizzate attraverso un flusso dedicato, non sono necessariamente perdute, ma non funzionano automaticamente come in un tema tradizionale.

Per un blog aziendale semplice, un tema WordPress ben configurato potrebbe quindi essere la soluzione più economica e facile da mantenere. Headless diventa interessante quando i vantaggi del disaccoppiamento giustificano la complessità aggiuntiva.

Esplorare la REST API di WordPress

La REST API espone risorse attraverso endpoint HTTP e restituisce normalmente dati in formato JSON.

Se WordPress è installato su https://cms.example.com, l'endpoint per recuperare gli articoli pubblici è:

https://cms.example.com/wp-json/wp/v2/posts

Possiamo verificarlo direttamente dal terminale:

curl -sS \
  'https://cms.example.com/wp-json/wp/v2/posts?per_page=5' \
  | python -m json.tool

Sostituisci cms.example.com con il dominio reale dell'installazione WordPress.

La risposta contiene un array di oggetti JSON. Ogni articolo può includere identificativo, titolo, contenuto, estratto, data di pubblicazione, slug e altri campi.

Per esempio, possiamo richiedere soltanto alcuni campi:

curl -sS \
  'https://cms.example.com/wp-json/wp/v2/posts?per_page=5&_fields=id,slug,date,title,excerpt,link' \
  | python -m json.tool

Il parametro per_page controlla il numero di risultati richiesti, mentre _fields permette di limitare i campi restituiti.

Altri endpoint disponibili includono:

RisorsaEndpoint
Articoli/wp-json/wp/v2/posts
Pagine/wp-json/wp/v2/pages
Categorie/wp-json/wp/v2/categories
Tag/wp-json/wp/v2/tags
Media/wp-json/wp/v2/media

La REST API offre anche parametri per filtrare, ordinare e paginare i risultati. Per esempio, page=2 consente di richiedere la seconda pagina dei risultati, mentre per_page=10 limita la risposta a dieci elementi.

La documentazione completa degli endpoint è disponibile qui:

https://developer.wordpress.org/rest-api/reference/

Configurare il progetto Next.js

Per il frontend utilizzeremo Next.js con App Router e componenti server.

Se non hai ancora creato il progetto, puoi iniziare con:

npx create-next-app@latest wp-headless
cd wp-headless
npm run dev

Durante la configurazione puoi scegliere TypeScript e App Router. Le opzioni disponibili dipendono dalla versione di create-next-app.

Il server di sviluppo sarà normalmente disponibile su http://localhost:3000.

Configurare l'indirizzo del CMS

Nella directory principale del progetto crea un file .env.local:

WORDPRESS_API_URL=https://cms.example.com/wp-json/wp/v2

Sostituisci il dominio con quello del tuo WordPress.

La variabile non deve avere il prefisso NEXT_PUBLIC_, perché in questo esempio viene utilizzata esclusivamente dal server Next.js. Le variabili con quel prefisso possono essere incluse nel bundle client e non sono adatte a conservare segreti.

Il file .env.local non deve essere pubblicato nel repository se contiene informazioni riservate.

In questo esempio l'URL dell'API è una configurazione, non una credenziale. Non utilizzeremo password per recuperare gli articoli pubblici.

Recuperare gli articoli dal backend WordPress

Creiamo il file app/lib/wordpress.ts:

const apiUrl = process.env.WORDPRESS_API_URL;

if (!apiUrl) {
  throw new Error("La variabile WORDPRESS_API_URL non è configurata.");
}

export type WordPressPost = {
  id: number;
  slug: string;
  date: string;
  link: string;
  title: {
    rendered: string;
  };
  excerpt: {
    rendered: string;
  };
};

export async function getPosts(): Promise<WordPressPost[]> {
  const response = await fetch(
    `${apiUrl}/posts?per_page=10&_fields=id,slug,date,link,title,excerpt`,
    {
      next: {
        revalidate: 60,
      },
    }
  );

  if (!response.ok) {
    throw new Error(
      `Errore REST API WordPress: HTTP ${response.status}`
    );
  }

  return response.json();
}

Questa funzione esegue una richiesta HTTP al backend WordPress e converte la risposta JSON in un array di articoli.

Il tipo WordPressPost descrive soltanto i campi utilizzati nell'esempio. Il modello completo della REST API contiene molti altri attributi.

L'opzione revalidate: 60 richiede a Next.js di aggiornare i dati memorizzati nella cache secondo la strategia di revalidazione configurata. Non è un aggiornamento garantito esattamente ogni sessanta secondi: il comportamento dipende dal sistema di caching e dalle richieste successive.

Inoltre, la cache del frontend non si aggiorna necessariamente nello stesso istante in cui un redattore pubblica un articolo. Per un sito editoriale, questa scelta può essere adeguata; per esigenze di pubblicazione immediata, si può integrare un sistema di invalidazione della cache tramite webhook o revalidazione mirata.

Visualizzare gli articoli nel frontend

Ora possiamo utilizzare la funzione appena creata in una pagina Next.js.

Creiamo app/page.tsx:

import { getPosts } from "./lib/wordpress";

export default async function HomePage() {
  const posts = await getPosts();

  return (
    <main>
      <h1>Ultimi articoli</h1>

      {posts.length === 0 ? (
        <p>Non sono disponibili articoli pubblicati.</p>
      ) : (
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              <article>
                <h2>
                  <a href={`/blog/${post.slug}`}>
                    {post.title.rendered.replace(/<[^>]*>/g, "")}
                  </a>
                </h2>

                <time dateTime={post.date}>
                  {new Date(post.date).toLocaleDateString("it-IT")}
                </time>

                <div
                  dangerouslySetInnerHTML={{
                    __html: post.excerpt.rendered,
                  }}
                />
              </article>
            </li>
          ))}
        </ul>
      )}
    </main>
  );
}

La pagina è un Server Component asincrono. Next.js esegue la richiesta al backend sul server e utilizza i dati per generare la risposta HTML.

In questo modo, la chiamata al CMS non deve necessariamente partire dal browser del visitatore. Il frontend può recuperare i contenuti direttamente dal server Next.js, evitando di esporre configurazioni riservate al client.

Nell'esempio, il titolo viene trattato come testo eliminando eventuali tag HTML. L'estratto viene invece renderizzato come HTML, perché il campo excerpt.rendered della REST API può contenere markup.

Attenzione alla sicurezza: dangerouslySetInnerHTML deve essere utilizzato soltanto con HTML considerato attendibile e adeguatamente controllato. Se il contenuto può provenire da utenti non fidati o da integrazioni esterne, occorre applicare una strategia di sanitizzazione HTML appropriata. Il fatto che un dato provenga da WordPress non rende automaticamente innocuo qualsiasi markup.

Questo esempio mostra una lista di articoli. Per completare un vero blog occorre implementare anche le pagine di dettaglio, i percorsi per gli slug, la gestione dei contenuti non trovati e gli eventuali metadati SEO.

Gestire l'autenticazione della REST API

Non tutte le richieste alla REST API richiedono autenticazione.

Gli articoli pubblici possono normalmente essere letti senza credenziali. Le operazioni che modificano contenuti, accedono a dati privati o richiedono privilegi specifici devono invece essere autenticate e autorizzate.

WordPress mette a disposizione diversi meccanismi, tra cui:

  • Autenticazione tramite cookie e nonce per richieste effettuate nel contesto di un utente autenticato in WordPress.
  • Application Passwords per applicazioni e integrazioni che devono autenticarsi tramite HTTPS.
  • Sistemi aggiuntivi, quando richiesti dall'architettura o dalle esigenze del progetto.

Per un'integrazione server-to-server, le Application Passwords sono spesso una soluzione pratica. Si generano dal profilo dell'utente WordPress e possono essere revocate senza modificare la password principale.

La documentazione ufficiale descrive il funzionamento e le modalità di utilizzo:

https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

Esempio di richiesta autenticata

Supponiamo di dover leggere contenuti privati o effettuare un'operazione autorizzata. In un ambiente protetto, possiamo memorizzare le credenziali in variabili d'ambiente:

WORDPRESS_USER=utente_api
WORDPRESS_APP_PASSWORD=password_applicazione

Non inserire credenziali reali nel codice sorgente o in un repository pubblico. In produzione, utilizza il sistema di gestione dei segreti fornito dall'infrastruttura.

Una richiesta autenticata lato server può essere effettuata con fetch:

const username = process.env.WORDPRESS_USER;
const appPassword = process.env.WORDPRESS_APP_PASSWORD;

if (!username || !appPassword) {
  throw new Error("Credenziali WordPress mancanti.");
}

const authorization =
  "Basic " +
  Buffer.from(`${username}:${appPassword}`).toString("base64");

const response = await fetch(
  "https://cms.example.com/wp-json/wp/v2/posts?context=edit",
  {
    headers: {
      Authorization: authorization,
    },
    cache: "no-store",
  }
);

if (!response.ok) {
  throw new Error(`Richiesta autenticata fallita: ${response.status}`);
}

const posts = await response.json();

Questo frammento è un esempio di richiesta server-side e non deve essere copiato in un componente client. L'autenticazione Basic codifica le credenziali in Base64, ma non le cifra: la protezione del trasporto dipende da HTTPS. Le Application Passwords devono essere gestite come segreti e avere soltanto i privilegi necessari.

L'endpoint con context=edit è utile per illustrare una richiesta autenticata, ma l'accesso effettivo dipende dalle autorizzazioni dell'utente e dalla risorsa richiesta.

Per un semplice blog pubblico non serve autenticare la lettura degli articoli. Aggiungere credenziali dove non sono necessarie aumenta la complessità e il rischio senza fornire un vantaggio concreto.

Anteprime, pubblicazione e aggiornamento della cache

Uno degli aspetti più delicati di WordPress headless è il flusso editoriale.

In una configurazione tradizionale, WordPress e il tema condividono il sistema di anteprima. Con un frontend separato, l'anteprima deve essere collegata all'applicazione che genera le pagine.

Una soluzione tipica prevede:

  1. Un redattore richiede l'anteprima dal pannello WordPress.
  2. WordPress genera o attiva un collegamento di anteprima verso il frontend.
  3. Next.js verifica la richiesta e abilita una modalità di anteprima protetta.
  4. Il server Next.js recupera il contenuto non pubblicato utilizzando credenziali server-side.
  5. La pagina viene mostrata al redattore senza rendere pubblico il contenuto.

Il collegamento deve essere protetto e validato. Non è sufficiente esporre un endpoint che permetta a chiunque di leggere articoli in bozza.

Per i contenuti pubblicati, invece, si può utilizzare una strategia di caching. Una revalidazione periodica è semplice da configurare, mentre un webhook attivato alla pubblicazione o alla modifica di un contenuto permette di aggiornare in modo più mirato le pagine interessate.

La soluzione migliore dipende dalla frequenza di pubblicazione, dal traffico e dal livello di aggiornamento richiesto.

SEO e URL in un progetto headless

Separare il frontend dal CMS significa anche assumersi la responsabilità di diversi aspetti SEO.

L'applicazione Next.js deve generare correttamente titoli, descrizioni, canonical URL, dati strutturati quando appropriati, sitemap XML e direttive di indicizzazione. Deve inoltre gestire i codici di stato HTTP e i redirect.

È importante mantenere una corrispondenza stabile tra gli slug WordPress e gli URL del frontend. Se il sito cambia struttura, occorre predisporre redirect permanenti per gli URL modificati e verificare che le pagine eliminate restituiscano lo stato corretto.

Anche i metadati SEO memorizzati da plugin WordPress non sono necessariamente disponibili in tutti gli endpoint standard: in base al plugin e alla configurazione, potrebbe essere necessario esporli attraverso l'API o recuperarli con un'integrazione dedicata.

WordPress headless non migliora automaticamente il posizionamento sui motori di ricerca. La qualità dei contenuti, la struttura HTML, la velocità effettiva, l'accessibilità, i collegamenti interni e la corretta indicizzazione continuano a essere determinanti.

Quando scegliere WordPress headless

WordPress headless è una scelta sensata quando il progetto richiede un frontend fortemente personalizzato, più canali di distribuzione dei contenuti o un'architettura applicativa distinta dal CMS.

Può essere adatto a piattaforme editoriali complesse, prodotti digitali che integrano più fonti di dati e progetti nei quali il frontend deve evolvere indipendentemente dal backend.

È meno conveniente quando il sito è un blog tradizionale, una piccola vetrina aziendale o un progetto che sfrutta molte funzionalità già offerte dai temi e dai plugin WordPress.

In questi casi, il costo aggiuntivo per realizzare anteprime, ricerca, template, integrazioni SEO e gestione della cache potrebbe superare i benefici ottenuti.

La decisione dovrebbe quindi partire dai requisiti concreti, non dalla semplice preferenza per un framework moderno.

Conclusione

WordPress headless permette di mantenere WordPress come CMS e utilizzare un frontend indipendente per presentare i contenuti. La REST API offre un'interfaccia standard per recuperare articoli, pagine e altri dati, mentre Next.js consente di realizzare un'applicazione React con diverse strategie di rendering e caching.

Il vantaggio principale è la libertà architetturale, non una superiorità automatica in termini di prestazioni o sicurezza. Il prezzo da pagare è una maggiore complessità: il frontend deve occuparsi delle funzionalità che non vengono più gestite direttamente dal tema WordPress.

Prima di adottare questa soluzione, è quindi essenziale valutare le esigenze editoriali, le strategie di caching, le modalità di autenticazione, la gestione delle anteprime e i requisiti SEO. Una buona architettura headless non nasce dalla separazione in sé, ma dalla capacità di utilizzare questa separazione per risolvere problemi reali.

Vedi tutti →