# Une redirection ignorée à cause d’une ligne vide avant `<?php` en functions.php

> Un appel à wp_redirect() placé au bon endroit, mais qui ne redirige jamais, sans la moindre erreur PHP visible. Le coupable est un caractère invisible avant la balise d'ouverture.

- Auteur : WordPress Développement
- Publié le : 2023-02-23
- Mis à jour le : 2023-02-23
- Catégorie : Thèmes
- URL : https://www.wpmoderne.fr/themes/ligne-vide-avant-php-functions-redirection-ignoree/

## L’essentiel

- Un caractère avant <?php envoie une sortie avant les en-têtes HTTP
- wp_redirect() échoue silencieusement si les en-têtes sont déjà envoyés
- WP_DEBUG seul ne révèle pas ce type d'échec

Pourquoi un appel à `wp_redirect()`, placé au bon endroit dans un hook `template_redirect`, ne redirige-t-il jamais l'utilisateur, sans la moindre trace d'erreur dans les journaux ni dans l'écran habituellement bavard de WordPress ? Le code semble correct, la condition qui déclenche la redirection est bien atteinte, un `error_log()` placé juste avant confirme même que la ligne est exécutée. Et pourtant, la page continue de s'afficher normalement.

Ce scénario, rencontré sur un thème classique dont le fichier `functions.php` avait été modifié par plusieurs personnes au fil des mois, cache une cause précise et redoutablement discrète : un ou plusieurs caractères présents avant la balise d'ouverture `<?php`, ou après la balise de fermeture `?>` en fin de fichier.

## Le symptôme : une redirection qui s'exécute mais ne redirige rien

Le code incriminé ressemble à ceci, et n'a rien d'anormal en apparence :

```
add_action( 'template_redirect', function () {
    if ( is_page( 'ancienne-page' ) ) {
        wp_redirect( home_url( '/nouvelle-page/' ), 301 );
        exit;
    }
} );
```

La fonction `is_page()` retourne bien `true`, l'instruction `exit` est atteinte, mais le navigateur affiche malgré tout le contenu de la page d'origine, parfois précédé d'un espace blanc supplémentaire en haut de la fenêtre.

## Le diagnostic : des en-têtes HTTP déjà envoyés

`wp_redirect()` repose sur la fonction PHP native `header()`, qui doit impérativement être appelée avant tout envoi de contenu au navigateur. Or, dès qu'un caractère — un espace, une ligne vide, un caractère invisible d'encodage BOM (*byte order mark*) — se trouve en dehors des balises `<?php ?>` d'un fichier chargé avant le hook `template_redirect`, PHP considère ce caractère comme du contenu à afficher et l'envoie immédiatement au navigateur. Une fois cette sortie effectuée, les en-têtes HTTP sont considérés comme déjà envoyés, et tout appel ultérieur à `header()` échoue silencieusement : PHP ne lève une erreur « headers already sent » que si l'affichage des erreurs est activé, et cette erreur n'apparaît pas toujours dans les journaux si `display_errors` est désactivé en production.

> L'essentiel à retenir : Un caractère avant <?php envoie une sortie avant les en-têtes HTTP ; wp_redirect() échoue silencieusement si les en-têtes sont déjà envoyés ; WP_DEBUG seul ne révèle pas ce type d'échec

## Retrouver le caractère fautif

Le suspect le plus fréquent est une ligne vide laissée après la balise `?>` à la fin du fichier `functions.php`, ou un espace introduit avant `<?php` lors d'un copier-coller depuis un éditeur de texte qui a conservé un caractère invisible. Un moyen fiable de le confirmer consiste à activer temporairement l'affichage des erreurs et à observer le message qui précède l'échec :

```
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', true );
```

Le message attardé ressemble à : `Warning: Cannot modify header information - headers already sent by (output started at .../functions.php:1)`. Le numéro de ligne indiqué — souvent la ligne 1 — pointe directement vers le fichier et l'endroit où la sortie a commencé.

## Le correctif : supprimer la balise de fermeture PHP

La pratique recommandée dans les standards de codage de WordPress consiste à ne jamais fermer la balise PHP à la fin d'un fichier qui ne contient que du code PHP, précisément pour éviter ce genre d'incident :

```
<?php
// Fin du fichier functions.php, sans balise de fermeture ni ligne vide après.
add_action( 'template_redirect', function () {
    // ...
} );
```

Il faut également vérifier qu'aucun caractère BOM n'a été enregistré en tête de fichier, ce qui arrive fréquemment avec certains éditeurs configurés en encodage UTF-8 avec BOM plutôt qu'en UTF-8 sans BOM. La plupart des éditeurs modernes permettent de choisir explicitement l'encodage de sauvegarde dans leurs préférences.

## Prévenir la récidive avec un outil d'analyse statique

Un outil comme PHP_CodeSniffer, configuré avec les règles du projet WordPress Coding Standards, détecte automatiquement la présence de code en dehors des balises PHP et peut être intégré à une étape de vérification avant chaque déploiement. Cela évite qu'un futur copier-coller, effectué par une autre personne de l'équipe, ne reproduise le même incident sur un autre fichier du thème.

- Supprimer systématiquement la balise de fermeture `?>` dans les fichiers 100 % PHP.
- Enregistrer les fichiers en UTF-8 sans BOM.
- Vérifier avec un éditeur hexadécimal ou `xxd` en cas de doute persistant sur les premiers octets du fichier.

## En résumé

Une redirection qui s'exécute sans effet, sans message d'erreur visible en production, mérite de vérifier en priorité l'état des en-têtes HTTP avant de remettre en cause la logique métier du code. Le caractère fautif est souvent invisible à l'œil nu dans un éditeur classique, mais son effet est systématique : tant qu'il subsiste avant la première balise `<?php` d'un fichier chargé tôt dans le cycle de WordPress, aucune fonction basée sur `header()` ne pourra fonctionner correctement sur les pages concernées.
