curl -I https://exemple.fr/wp-json/wpm/v1/rapport-a11y — cette simple requête d’en-têtes révèle le problème en une ligne : ni ETag, ni Cache-Control dans la réponse. Un script de supervision externe, exécuté toutes les dix minutes pour surveiller le score d’accessibilité d’un parc de pages, retélécharge donc l’intégralité du rapport JSON à chaque passage, qu’il ait changé ou non.
Cette recette HTTP corrige le point d’entrée REST WordPress qui expose ce rapport, sans toucher à la génération du rapport lui-même : le calcul du score, les anomalies détectées et leur format restent identiques. Seule la couche de mise en cache HTTP change.
Le endpoint tel qu’il existe
Le rapport est exposé via un endpoint REST personnalisé, enregistré dans le plugin interne de l’agence :
add_action( 'rest_api_init', function () {
register_rest_route( 'wpm/v1', '/rapport-a11y', array(
'methods' => 'GET',
'callback' => 'wpm_rest_rapport_a11y',
'permission_callback' => '__return_true',
) );
} );
function wpm_rest_rapport_a11y( \WP_REST_Request $requete ) {
$rapport = wpm_generer_rapport_a11y();
return new \WP_REST_Response( $rapport, 200 );
}
Chaque appel recalcule et renvoie le rapport complet, sans aucune information permettant au client de savoir si le contenu a réellement changé depuis le dernier appel. Le script de supervision, de son côté, se contente d’un appel GET classique toutes les dix minutes, sans condition.
Ajouter un ETag basé sur le contenu du rapport
Un ETag est une empreinte du contenu de la réponse. Le calculer à partir d’un hachage du rapport sérialisé permet de détecter, sans regénérer quoi que ce soit côté script client, si le contenu a changé :
function wpm_rest_rapport_a11y( \WP_REST_Request $requete ) {
$rapport = wpm_generer_rapport_a11y();
$corps = wp_json_encode( $rapport );
$etag = '"' . md5( $corps ) . '"';
$reponse = new \WP_REST_Response( $rapport, 200 );
$reponse->header( 'ETag', $etag );
$reponse->header( 'Cache-Control', 'private, max-age=60, must-revalidate' );
$etag_recu = $requete->get_header( 'if_none_match' );
if ( $etag_recu === $etag ) {
$reponse->set_status( 304 );
$reponse->set_data( null );
}
return $reponse;
}

Ce que gagne le script de supervision
Le script externe doit à présent conserver l’ETag reçu à chaque appel réussi, et le renvoyer dans l’en-tête If-None-Match de la requête suivante :
etag_precedent=$(cat /var/supervision/etag-a11y.txt 2>/dev/null)
reponse=$(curl -s -D - -o /tmp/rapport.json \
-H "If-None-Match: ${etag_precedent}" \
https://exemple.fr/wp-json/wpm/v1/rapport-a11y)
if echo "$reponse" | grep -q "HTTP/1.1 304"; then
echo "Rapport inchangé, aucun traitement nécessaire."
else
nouvel_etag=$(echo "$reponse" | grep -i '^etag:' | cut -d' ' -f2)
echo "$nouvel_etag" > /var/supervision/etag-a11y.txt
# traitement du nouveau rapport dans /tmp/rapport.json
fi
Quand le rapport n’a pas changé, le serveur répond 304 Not Modified avec un corps vide : le script de supervision économise la bande passante liée au transfert du JSON complet, et surtout évite de déclencher inutilement son propre traitement en aval, potentiellement coûteux si celui-ci alerte une équipe à chaque nouveau rapport reçu.
Le rôle de Cache-Control en complément
L’en-tête Cache-Control: private, max-age=60, must-revalidate ajoute une seconde couche : pendant soixante secondes après un appel, un cache HTTP intermédiaire ou le navigateur peut réutiliser la réponse sans même émettre de requête conditionnelle. La directive private signale que la réponse ne doit pas être partagée entre différents clients par un cache mutualisé, ce qui reste pertinent tant que le endpoint n’est pas strictement public au sens de la vie privée. La directive must-revalidate impose qu’une fois la fraîcheur expirée, le client revalide obligatoirement auprès du serveur plutôt que de continuer à servir une version potentiellement périmée.
Variantes selon le contexte
Pour un rapport recalculé une seule fois par heure via une tâche planifiée, plutôt qu’à chaque requête, l’ETag peut se baser directement sur l’horodatage de dernière génération plutôt que sur un hachage complet du contenu, ce qui évite de sérialiser le rapport juste pour calculer l’empreinte :
$derniere_generation = get_option( 'wpm_rapport_a11y_horodatage' );
$etag = '"' . md5( (string) $derniere_generation ) . '"';
Pour un endpoint interrogé par plusieurs scripts de supervision différents, avec des fréquences distinctes, la valeur max-age mérite d’être ajustée à la fréquence la plus courte parmi les consommateurs connus, afin qu’aucun ne reçoive une réponse mise en cache plus longtemps que ce qu’il tolère.
En résumé
Un rapport JSON destiné à un robot de supervision bénéficie exactement des mêmes mécanismes HTTP qu’une page web classique : ETag pour détecter un contenu inchangé sans le retransmettre, Cache-Control pour fixer une durée de fraîcheur raisonnable. Le gain ne se mesure pas seulement en bande passante économisée, mais aussi en charge évitée côté script consommateur, qui ne traite plus un rapport identique au précédent toutes les dix minutes.