# Bien gérer les objets WP_Error renvoyés par WP_Http dans une extension

> wp_remote_get() ne lève jamais d'exception : il renvoie un WP_Error silencieux. Voici comment le détecter, le journaliser et le remonter sans le laisser filer.

- Auteur : WordPress Développement
- Publié le : 2022-10-06
- Mis à jour le : 2022-10-06
- Catégorie : Extensions
- URL : https://www.wpmoderne.fr/extensions/gerer-wp-error-wp-http-extension/

## L’essentiel

- is_wp_error() avant tout traitement
- get_error_message() pour journaliser proprement
- Ne jamais transformer un WP_Error en tableau vide

La documentation du Plugin Handbook le rappelle sans détour : de nombreuses fonctions de l'API WordPress ne renvoient ni `false`, ni `null`, ni une exception en cas d'échec, mais un objet `WP_Error`. C'est exactement ce qui se passe avec `wp_remote_get()` et `wp_remote_post()` lorsqu'une requête HTTP sortante échoue : timeout, DNS injoignable, certificat SSL invalide. Le code continue de s'exécuter, et si l'extension ne vérifie rien, elle traite un objet d'erreur comme s'il s'agissait d'une réponse valide.

Ce comportement n'est pas un défaut de conception, c'est un choix assumé de WordPress pour rester compatible avec des environnements PHP anciens où les exceptions n'étaient pas systématiquement utilisées. Mais pour un développeur d'extension qui appelle une API tierce (paiement, CRM, service de messagerie), cela veut dire une seule chose : chaque appel à l'API HTTP doit être suivi d'une vérification explicite, sans exception.

## Reconnaître un WP_Error avant qu'il ne casse tout

La fonction `is_wp_error()` est le seul point de passage obligé. Elle doit être appelée immédiatement après chaque requête sortante, avant toute tentative de lecture du corps de la réponse :

```
$response = wp_remote_post( 'https://api.exemple-crm.test/v2/contacts', array(
    'timeout' => 8,
    'body'    => wp_json_encode( $payload ),
    'headers' => array( 'Content-Type' => 'application/json' ),
) );

if ( is_wp_error( $response ) ) {
    error_log( 'Extension Contacts : ' . $response->get_error_message() );
    return false;
}

$code = wp_remote_retrieve_response_code( $response );
if ( 200 !== (int) $code ) {
    error_log( 'Extension Contacts : réponse HTTP ' . $code );
    return false;
}
```

Sans ce garde-fou, `wp_remote_retrieve_body( $response )` renverrait une chaîne vide sur un WP_Error, ce qui masque totalement l'origine du problème et transforme une panne réseau en bug silencieux dans la logique métier.

## Journaliser sans perdre l'information utile

> L'essentiel à retenir : is_wp_error() avant tout traitement ; get_error_message() pour journaliser proprement ; Ne jamais transformer un WP_Error en tableau vide

Un `WP_Error` peut contenir plusieurs erreurs empilées, chacune avec son propre code. La méthode `get_error_messages()` (au pluriel) renvoie un tableau complet, alors que `get_error_message()` ne renvoie que le premier message. Pour un journal d'extension digne de ce nom, mieux vaut boucler sur les codes :

- `$wp_error->get_error_codes()` pour lister tous les codes d'erreur présents
- `$wp_error->get_error_message( $code )` pour récupérer le message associé à un code précis
- `$wp_error->get_error_data( $code )` pour accéder aux données de contexte, souvent le tableau de réponse brut de WP_Http

C'est cette dernière méthode qui est trop souvent ignorée : `get_error_data()` contient parfois la réponse HTTP complète, utile pour distinguer une erreur de timeout d'une erreur de certificat.

## Propager l'erreur plutôt que l'avaler

Une extension bien construite ne doit pas se contenter d'un `error_log()` et d'un `return false` muet. Si la fonction appelante peut elle-même renvoyer un `WP_Error`, il faut le laisser remonter tel quel, quitte à l'enrichir :

```
function mon_extension_envoyer_contact( $payload ) {
    $response = wp_remote_post( /* ... */ );

    if ( is_wp_error( $response ) ) {
        return new WP_Error(
            'crm_indisponible',
            'Le CRM distant n’a pas répondu : ' . $response->get_error_message(),
            array( 'payload' => $payload )
        );
    }

    return true;
}
```

Cette approche permet à l'appelant, qu'il s'agisse d'un formulaire d'administration ou d'une tâche planifiée, de décider lui-même comment réagir : réessayer, notifier l'administrateur, ou simplement afficher un message clair à l'utilisateur.

## S'appuyer sur le hook http_api_debug pour un diagnostic global

Pour ne pas semer des `is_wp_error()` partout dans le code, l'action `http_api_debug` offre un point d'observation centralisé sur toutes les requêtes sortantes de WordPress, y compris celles d'autres extensions :

```
add_action( 'http_api_debug', function( $response, $context, $class, $args, $url ) {
    if ( is_wp_error( $response ) && str_contains( $url, 'exemple-crm.test' ) ) {
        error_log( sprintf( 'HTTP KO vers %s : %s', $url, $response->get_error_message() ) );
    }
}, 10, 5 );
```

Ce hook reçoit cinq arguments, dont l'URL appelée et la classe utilisée pour le transport. Il est particulièrement utile pour diagnostiquer, en production, des échecs intermittents sans avoir à modifier le code de chaque appel.

## Les pièges les plus fréquents

Le premier piège consiste à tester uniquement le code HTTP sans tester `is_wp_error()` en amont : sur un WP_Error, `wp_remote_retrieve_response_code()` renvoie une chaîne vide, ce qui peut passer silencieusement une condition mal écrite. Le second piège est de convertir systématiquement l'erreur en exception PHP sans contexte, perdant ainsi les codes d'erreur natifs de WordPress. Le troisième, plus insidieux, consiste à réessayer indéfiniment un appel en boucle sans backoff, ce qui peut transformer une panne ponctuelle du service distant en surcharge du serveur WordPress lui-même.

> Sur nos extensions qui interrogent des API tierces, ajouter systématiquement un bloc `is_wp_error()` juste après l'appel a fait disparaître la quasi-totalité des tickets « la synchronisation ne fonctionne plus » sans qu'on sache pourquoi.

## En résumé

Un objet `WP_Error` n'est ni un `false`, ni une exception : c'est une structure de données à part entière qui mérite d'être inspectée, journalisée avec ses codes complets, puis propagée jusqu'à l'endroit où une décision peut réellement être prise. Ignorer cette étape revient à masquer, pour l'équipe de support, l'origine exacte d'une panne qui aurait pu être diagnostiquée en quelques secondes.
