Une agence de transport routier m’a demandé d’intégrer, dans une extension maison, la récupération de statuts de livraison depuis l’API d’un prestataire logistique. Premier réflexe d’un développeur PHP habitué à cURL en direct : écrire un appel curl_init et passer à autre chose. Mauvaise idée sur WordPress, pour une raison très concrète : certains hébergeurs restreignent ou interceptent les appels cURL bruts, alors que la HTTP API du cœur, elle, reste toujours disponible et surveillée par la stack WordPress elle-même.
Voici comment j’ai structuré cet appel avec wp_remote_get, en traitant sérieusement les timeouts, les erreurs et la journalisation.
Un appel HTTP correctement paramétré
wp_remote_get() accepte un second argument, un tableau d’arguments qui contrôle le comportement de la requête. Ignorer ce tableau et se contenter des valeurs par défaut est la source la plus fréquente de bugs difficiles à reproduire en local.
function transport_recuperer_statut_livraison( $numero_colis ) {
$reponse = wp_remote_get(
'https://api.prestataire-logistique.test/v2/colis/' . rawurlencode( $numero_colis ),
array(
'timeout' => 15,
'headers' => array(
'Authorization' => 'Bearer ' . transport_recuperer_cle_api(),
'Accept' => 'application/json',
),
'user-agent' => 'TransportKaolin/1.0; ' . home_url(),
)
);
return $reponse;
}
Le délai par défaut de 5 secondes convient pour une API rapide et locale, mais devient un problème réel face à un prestataire tiers dont les temps de réponse dépassent parfois 8 ou 10 secondes en heure de pointe. Sans ajustement, l’appel échoue silencieusement par timeout, alors que l’API elle-même fonctionnait très bien.
Distinguer une erreur réseau d’une erreur HTTP
wp_remote_get ne lève jamais d’exception : en cas d’échec de connexion, de DNS ou de timeout, elle retourne un objet WP_Error. Mais attention, un code de statut HTTP 404 ou 500 renvoyé par le serveur distant n’est pas une erreur au sens de WP_Error : la requête a bien abouti, c’est le serveur distant qui a répondu négativement.

function transport_traiter_reponse_livraison( $numero_colis ) {
$reponse = transport_recuperer_statut_livraison( $numero_colis );
if ( is_wp_error( $reponse ) ) {
transport_journaliser_erreur( 'connexion', $reponse->get_error_message() );
return false;
}
$code = wp_remote_retrieve_response_code( $reponse );
if ( 200 !== $code ) {
transport_journaliser_erreur( 'http_' . $code, wp_remote_retrieve_body( $reponse ) );
return false;
}
$donnees = json_decode( wp_remote_retrieve_body( $reponse ), true );
if ( null === $donnees ) {
transport_journaliser_erreur( 'json_invalide', wp_remote_retrieve_body( $reponse ) );
return false;
}
return $donnees;
}
Ces trois contrôles distincts — erreur de connexion, code HTTP inattendu, corps de réponse invalide — correspondent à trois causes racines très différentes. Les confondre dans un unique if ( ! $reponse ) rend le débogage bien plus long le jour où l’intégration se met à échouer en silence.
Journaliser sans polluer les logs
Un appel HTTP externe échoue tôt ou tard : panne temporaire du prestataire, certificat expiré, changement d’API non annoncé. Sans journalisation, ces incidents passent inaperçus jusqu’à ce qu’un client signale que « les statuts ne se mettent plus à jour depuis trois semaines ».
function transport_journaliser_erreur( $type, $detail ) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
return;
}
error_log( sprintf( '[Transport Kaolin] %s : %s', $type, is_string( $detail ) ? $detail : wp_json_encode( $detail ) ) );
}
Pour ce client, j’ai complété cette journalisation basique par un compteur d’échecs consécutifs stocké en option : au-delà de dix échecs d’affilée, un courriel d’alerte partait automatiquement vers l’équipe technique. Un détail simple, mais qui a permis de détecter un renouvellement de certificat SSL manqué côté prestataire avant que les clients finaux ne s’en plaignent.
Mettre en cache les réponses coûteuses
Interroger l’API à chaque chargement de page aurait ralenti inutilement le site et risqué de dépasser les quotas du prestataire. Un transient de courte durée a suffi à absorber la charge sans introduire de retard perceptible pour l’utilisateur final.
function transport_recuperer_statut_avec_cache( $numero_colis ) {
$cle = 'transport_statut_' . md5( $numero_colis );
$statut = get_transient( $cle );
if ( false === $statut ) {
$statut = transport_traiter_reponse_livraison( $numero_colis );
if ( false !== $statut ) {
set_transient( $cle, $statut, 10 * MINUTE_IN_SECONDS );
}
}
return $statut;
}
Dix minutes de cache représentaient, pour ce prestataire, un compromis raisonnable entre fraîcheur de l’information et charge sur son API, discuté et validé directement avec leur équipe technique.
Pour aller plus loin
La HTTP API de WordPress propose aussi wp_remote_post(), wp_remote_request() pour les méthodes personnalisées, et un filtre http_request_timeout pour ajuster globalement le délai d’attente sans toucher à chaque appel individuellement. Elle reste, encore aujourd’hui, la façon la plus fiable de communiquer avec un service tiers depuis une extension, précisément parce qu’elle s’adapte automatiquement au transport disponible sur l’hébergement (cURL, streams PHP, ou autre) sans que le code de l’extension ait à s’en soucier.