curl -I https://exemple.test/rapports/2023-06.pdf — sur un site construit avec un thème hybride, une telle requête ne doit jamais atteindre le rendu d’un template de bloc. Pourtant, sans intervention explicite, WordPress tente de la faire correspondre à sa hiérarchie de templates, échoue, et affiche la page 404 générée par le thème plutôt que le fichier attendu. La question se pose dès qu’un site doit répondre à une requête d’une manière qui sort du rendu habituel d’un article ou d’une page.
Définition : où se situe la main du Site Editor
Le rendu porté par le Site Editor n’intervient qu’après que WordPress a résolu la requête principale via la classe WP et sa méthode main(), qui détermine notamment quel post, quelle archive ou quelle page 404 correspond à l’URL demandée. Ce n’est qu’ensuite que le mécanisme de résolution de template hybride entre en jeu pour choisir le fichier .html à assembler. Intercepter une requête « avant » le Site Editor signifie donc intervenir avant cette résolution, pas après.
Fonctionnement interne : parse_request en premier

Le hook parse_request s’exécute tôt dans ce cycle, avec accès aux variables de requête déjà extraites des règles de réécriture. C’est l’endroit adapté pour court-circuiter entièrement le comportement par défaut :
add_action( 'parse_request', function ( WP $wp ) {
if ( isset( $wp->query_vars['rapport'] ) ) {
$chemin = get_theme_file_path( 'rapports/' . basename( $wp->query_vars['rapport'] ) . '.pdf' );
if ( file_exists( $chemin ) ) {
header( 'Content-Type: application/pdf' );
readfile( $chemin );
exit;
}
}
} );
Une variable de requête personnalisée comme rapport doit être déclarée au préalable via le filtre query_vars, et une règle de réécriture associée via add_rewrite_rule(), pour que l’URL propre soit correctement traduite en variables internes avant même d’atteindre parse_request.
Le cas plus courant de template_redirect
Pour une redirection simple, sans besoin d’accéder aussi tôt aux variables de requête brutes, le hook template_redirect suffit : il s’exécute juste avant que WordPress ne choisisse le fichier de template à charger, ce qui reste avant tout rendu de bloc.
add_action( 'template_redirect', function () {
if ( is_page( 'ancien-catalogue' ) ) {
wp_safe_redirect( home_url( '/catalogue/' ), 301 );
exit;
}
} );
Cas d’usage fréquents
- servir un fichier généré dynamiquement (export CSV, image redimensionnée à la volée) sans créer de type de contenu dédié ;
- rediriger une ancienne URL vers sa nouvelle forme après une restructuration du site, sans passer par une extension de redirection ;
- renvoyer un statut HTTP spécifique, par exemple 410 pour un contenu définitivement retiré, avant que le thème n’affiche sa page d’erreur générique.
Pièges à connaître
Le premier piège tient aux règles de réécriture elles-mêmes : une règle ajoutée via add_rewrite_rule() ne devient active qu’après un vidage du cache de réécriture, déclenché en visitant une fois la page des réglages de permaliens ou via wp_rewrite->flush_rules(). Sans ce vidage, la requête personnalisée n’atteint jamais parse_request avec la bonne variable, et le correctif semble ne produire aucun effet.
Le second piège concerne l’ordre d’exécution vis-à-vis d’une extension de cache. Un fichier servi via readfile() puis exit contourne le rendu normal de la page, ce qui peut aussi contourner les en-têtes de cache habituellement ajoutés plus tard dans le cycle : il faut alors les ajouter explicitement dans le hook d’interception lui-même, sans compter sur ceux du thème.
Nous testons toujours une interception de requête avec le cache de page désactivé dans un premier temps, pour être certains que c’est bien notre code qui répond et non une version mise en cache de l’ancien comportement.
Ce qu’il faut retenir
Le Site Editor ne « prend la main » qu’à un moment précis et relativement tardif du cycle de requête : tout ce qui doit s’exécuter avant lui dispose de points d’entrée classiques, hérités des thèmes traditionnels, qui restent parfaitement valables dans un thème hybride. La difficulté n’est pas technique, elle est de repérer lequel de ces deux hooks correspond au niveau d’intervention réellement nécessaire.