L’ISR (Incremental Static Regeneration), introduite par Next.js dès sa version 9.5, permet à une page statique de se régénérer automatiquement après un délai défini, sans reconstruire l’intégralité du site. C’est un net progrès par rapport à un export statique classique, mais son fonctionnement par défaut reste passif : la régénération n’a lieu qu’après l’expiration du délai et seulement lorsqu’une requête arrive sur la page concernée.
Pour un site éditorial où la fraîcheur du contenu compte, ce comportement passif ne suffit pas toujours : un rédacteur qui publie un article s’attend à le voir apparaître immédiatement, pas après le délai de revalidation configuré. La solution : déclencher la revalidation à la demande, directement depuis WordPress, via un webhook au moment de la publication.
Le principe général
L’idée consiste à connecter deux systèmes indépendants par un appel HTTP : WordPress détecte qu’un article vient d’être publié ou modifié, et notifie immédiatement le frontend Next.js pour qu’il régénère la page concernée, sans attendre le délai de revalidation passive.
Côté WordPress : déclencher le webhook
Le hook save_post se déclenche à chaque enregistrement d’un article, y compris pour les brouillons. Il faut donc filtrer précisément les cas pertinents, généralement les publications au statut publish :
add_action( 'save_post', function( $post_id, $post, $update ) {
if ( $post->post_status !== 'publish' ) {
return;
}
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
return;
}
$reponse = wp_remote_post( 'https://frontend.exemple.fr/api/revalidate', array(
'timeout' => 5,
'body' => array(
'secret' => WEBHOOK_REVALIDATE_SECRET,
'slug' => $post->post_name,
),
) );
if ( is_wp_error( $reponse ) ) {
error_log( 'Échec du webhook de revalidation : ' . $reponse->get_error_message() );
}
}, 10, 3 );
Le secret partagé, défini en constante dans wp-config.php, empêche quiconque connaissant l’URL de la route de revalidation de déclencher des régénérations arbitraires sur votre frontend.

Côté Next.js : la route de revalidation
Sur le Pages Router de Next.js, une route API dédiée reçoit l’appel de WordPress, vérifie le secret, puis déclenche la régénération ciblée via res.revalidate() :
// pages/api/revalidate.js
export default async function handler( req, res ) {
if ( req.body.secret !== process.env.WEBHOOK_REVALIDATE_SECRET ) {
return res.status( 401 ).json( { message: 'Secret invalide' } );
}
try {
await res.revalidate( `/articles/${ req.body.slug }` );
await res.revalidate( '/' );
return res.json( { revalidated: true } );
} catch ( erreur ) {
return res.status( 500 ).send( 'Erreur lors de la revalidation' );
}
}
Notez que la revalidation cible explicitement deux pages ici : la page de l’article modifié, et la page d’accueil, qui affiche probablement les derniers articles publiés et doit donc aussi refléter le changement. C’est un point à ne pas négliger : la revalidation ne se propage pas automatiquement aux pages qui référencent indirectement le contenu modifié.
Gérer les cas d’échec
Un webhook peut échouer pour de multiples raisons : frontend temporairement indisponible, timeout réseau, erreur de configuration du secret. Il est important que cet échec ne bloque jamais la publication de l’article côté WordPress : c’est pour cette raison que l’appel utilise wp_remote_post avec un timeout court, et que l’échec est simplement journalisé plutôt que de faire échouer la publication elle-même.
- Toujours définir un
timeoutraisonnable sur l’appel HTTP sortant, pour ne jamais bloquer l’enregistrement de l’article - Journaliser les échecs pour pouvoir déclencher une revalidation manuelle en cas de problème récurrent
- Prévoir malgré tout une revalidation passive (délai
revalidateclassique) en filet de sécurité, au cas où le webhook échouerait silencieusement
Ne comptez jamais uniquement sur le webhook pour la fraîcheur du contenu. Gardez toujours un délai de revalidation passive en complément, ne serait-ce que pour rattraper les cas où le webhook n’a pas abouti, un réseau instable en environnement de production reste plus fréquent qu’on ne le pense.
Pour l’App Router : la même logique, une API différente
Depuis l’introduction de l’App Router, Next.js propose une fonction équivalente, revalidatePath, appelée depuis une route handler plutôt qu’une API Pages classique. Le principe de sécurisation par secret partagé reste identique ; seule la syntaxe change. Nous détaillerons cette approche dans un prochain article consacré spécifiquement à l’App Router.
En résumé
Combiner l’ISR passive de Next.js à une revalidation à la demande déclenchée par webhook depuis WordPress offre le meilleur compromis pour un site headless : la performance d’un contenu statique, avec une fraîcheur quasi immédiate au moment de la publication. La mise en place reste simple, à condition de sécuriser l’appel avec un secret partagé et de toujours prévoir un filet de sécurité en cas d’échec du webhook.