Un front headless doit-il vraiment recevoir la même image, dans le même format, quel que soit le navigateur qui la consommera ensuite ? La question mérite d’être posée dès qu’un projet découplé sert des images à plusieurs types de clients — une application mobile, un site web, un générateur de miniatures pour les réseaux sociaux — sans toujours pouvoir compter sur eux pour effectuer la conversion de format eux-mêmes.
Le problème
La médiathèque de WordPress conserve les images dans leur format d’origine, généralement JPEG ou PNG selon ce que l’auteur a importé. L’API REST expose ce fichier tel quel via source_url, sans jamais reformater automatiquement le contenu pour le client qui le demande. Un front headless qui a besoin de WebP ou d’AVIF pour des raisons de poids doit donc soit convertir lui-même côté client (rarement possible), soit s’appuyer sur un service tiers de transformation d’image, soit demander au serveur WordPress de le faire à sa place, au moment de la requête.
La recette : une route de conversion à la volée

add_action( 'rest_api_init', function () {
register_rest_route( 'medias/v1', '/convertir/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'convertir_image_webp',
'args' => array(
'id' => array( 'validate_callback' => 'is_numeric' ),
),
) );
} );
function convertir_image_webp( $request ) {
$id = (int) $request->get_param( 'id' );
$chemin = get_attached_file( $id );
if ( ! $chemin || ! file_exists( $chemin ) ) {
return new WP_Error( 'image_introuvable', 'Aucune image pour cet identifiant.', array( 'status' => 404 ) );
}
$editeur = wp_get_image_editor( $chemin );
if ( is_wp_error( $editeur ) ) {
return $editeur;
}
$destination = wp_upload_dir()['path'] . '/' . $id . '.webp';
$resultat = $editeur->save( $destination, 'image/webp' );
if ( is_wp_error( $resultat ) ) {
return $resultat;
}
header( 'Content-Type: image/webp' );
header( 'Cache-Control: public, max-age=31536000' );
readfile( $resultat['path'] );
exit;
}
La fonction wp_get_image_editor() retourne une instance de WP_Image_Editor_GD ou WP_Image_Editor_Imagick selon les extensions PHP disponibles sur le serveur. Sa méthode save() accepte un second argument précisant le type MIME cible, ce qui déclenche la conversion réelle du format sans que le développeur ait à manipuler directement la bibliothèque GD ou Imagick sous-jacente.
Éviter de reconvertir à chaque appel
Sans précaution, cette route reconvertit l’image à chaque requête, ce qui gaspille du CPU pour un résultat identique à chaque fois. Une vérification simple de l’existence du fichier de destination avant de relancer la conversion règle l’essentiel du problème :
- Vérifier si le fichier
.webpexiste déjà dans le dossier de téléversement avant de reconvertir - Ne régénérer le fichier que si l’image source a été modifiée depuis (comparaison de date de modification)
- Laisser un CDN ou un cache de reverse proxy absorber les requêtes suivantes grâce à l’en-tête
Cache-Control
Variantes utiles
La même route peut accepter un paramètre largeur pour redimensionner l’image avant conversion, via $editeur->resize( $largeur, null, false ) appelé avant save(). Elle peut aussi accepter un paramètre format pour choisir entre WebP et AVIF selon ce que le client sait afficher, information généralement déduite de l’en-tête Accept envoyé par le navigateur plutôt que d’un paramètre explicite.
Sur nos projets, cette route de conversion reste réservée aux images dont le format d’origine n’a pas pu être anticipé au moment de l’import ; pour tout le reste, générer directement les tailles au format WebP dès l’upload évite de faire porter ce coût de calcul à chaque requête front.
En résumé
Convertir une image à la volée via une route REST personnalisée permet à un front headless de recevoir exactement le format qu’il sait afficher, sans dépendre d’un traitement côté client ni d’un service tiers. La méthode s’appuie entièrement sur l’API WP_Image_Editor déjà présente dans le cœur de WordPress, à condition de soigner la mise en cache du résultat pour ne pas transformer chaque affichage en nouvelle conversion.