# HTTP API de WordPress : wp_remote_get, timeouts et gestion d’erreurs

> Appeler cURL directement depuis une extension WordPress marche, jusqu'au jour où l'hébergeur bloque la fonction. La HTTP API existe justement pour éviter ce genre de surprise.

- Auteur : Clément Hadrot
- Publié le : 2020-10-06
- Mis à jour le : 2020-10-06
- Catégorie : Extensions
- URL : https://wpmoderne.dev.wordpress-developpement.fr/extensions/http-api-wp-remote-get-timeouts-erreurs/

## L’essentiel

- wp_remote_get renvoie soit un tableau, soit un objet WP_Error, jamais une exception
- Le timeout par défaut est de 5 secondes, souvent trop court pour une API tierce lente
- Journaliser les erreurs évite de découvrir un blocage plusieurs semaines après

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.

> L'essentiel à retenir : wp_remote_get renvoie soit un tableau, soit un objet WP_Error, jamais une exception ; Le timeout par défaut est de 5 secondes, souvent trop court pour une API tierce lente ; Journaliser les erreurs évite de découvrir un blocage plusieurs semaines après

```
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.
