# Un bloc et Brevo : afficher un statut d’abonné newsletter en temps réel

> Un bloc dynamique interroge l'API Brevo pour afficher à un utilisateur connecté s'il est déjà abonné à la newsletter, sans jamais exposer la clé API côté navigateur.

- Auteur : WordPress Développement
- Publié le : 2023-11-26
- Mis à jour le : 2023-11-26
- Catégorie : Blocs Gutenberg
- URL : https://www.wpmoderne.fr/blocs/bloc-brevo-statut-abonne-newsletter-temps-reel/

## L’essentiel

- L'appel API se fait exclusivement côté serveur PHP
- Le statut est mis en cache court pour éviter un appel à chaque affichage
- Le bloc gère explicitement l'absence d'utilisateur connecté

`GET https://api.brevo.com/v3/contacts/{email}` : c'est la seule route nécessaire pour répondre à une demande récurrente sur les espaces membres — afficher à un utilisateur connecté s'il est déjà inscrit à la newsletter, sans lui faire remplir un formulaire qu'il a peut-être déjà validé six mois plus tôt. Un bloc dynamique placé dans l'espace personnel du site interroge l'API Brevo à la volée pour restituer ce statut.

La contrainte de sécurité est immédiate : la clé API Brevo (préfixée `xkeysib-`) ne doit jamais transiter côté navigateur. Tout l'appel réseau doit donc rester côté serveur PHP, le front-end du bloc ne recevant que le résultat déjà interprété (« abonné », « non abonné », « désinscrit »).

## Le rendu du bloc côté serveur

Le bloc est déclaré dynamique via `block.json`, avec un `render_callback` qui vérifie d'abord si un utilisateur est connecté avant de tenter le moindre appel réseau — inutile d'interroger Brevo pour un visiteur anonyme, dont on ne connaît pas l'adresse e-mail.

```
function acme_render_statut_newsletter( $attributes ) {
    if ( ! is_user_logged_in() ) {
        return '<p>Connectez-vous pour voir votre statut d’abonnement.</p>';
    }

    $user  = wp_get_current_user();
    $statut = acme_get_brevo_subscription_status( $user->user_email );

    return sprintf(
        '<p>Statut newsletter : %s</p>',
        esc_html( $statut )
    );
}
```

## Interroger l'API Brevo avec mise en cache

Interroger Brevo à chaque affichage de page pénaliserait à la fois la performance du site et le quota d'appels de l'API (300 requêtes par minute sur un plan standard, un plafond vite atteint si chaque visite d'espace membre déclenche un appel). La fonction utilitaire met donc en cache le résultat via l'API des transients, avec une durée courte pour rester raisonnablement à jour sans saturer le quota :

> L'essentiel à retenir : L'appel API se fait exclusivement côté serveur PHP ; Le statut est mis en cache court pour éviter un appel à chaque affichage ; Le bloc gère explicitement l'absence d'utilisateur connecté

```
function acme_get_brevo_subscription_status( string $email ): string {
    $cache_key = 'acme_brevo_statut_' . md5( $email );
    $cached    = get_transient( $cache_key );

    if ( false !== $cached ) {
        return $cached;
    }

    $response = wp_remote_get(
        'https://api.brevo.com/v3/contacts/' . rawurlencode( $email ),
        [
            'headers' => [
                'api-key' => BREVO_API_KEY,
                'Accept'  => 'application/json',
            ],
            'timeout' => 6,
        ]
    );

    if ( is_wp_error( $response ) ) {
        return 'statut indisponible';
    }

    $code = wp_remote_retrieve_response_code( $response );

    if ( 404 === $code ) {
        $statut = 'non abonné';
    } elseif ( 200 === $code ) {
        $body = json_decode( wp_remote_retrieve_body( $response ), true );
        $opted_out = $body['emailBlacklisted'] ?? false;
        $statut = $opted_out ? 'désinscrit' : 'abonné';
    } else {
        $statut = 'statut indisponible';
    }

    set_transient( $cache_key, $statut, 5 * MINUTE_IN_SECONDS );

    return $statut;
}
```

Le champ `emailBlacklisted` renvoyé par l'API Brevo distingue un contact qui existe mais s'est désinscrit d'un contact simplement absent de la base (code 404). Cette distinction compte pour l'affichage : un utilisateur désinscrit ne doit pas voir le même message qu'un utilisateur qui n'a jamais été inscrit, au risque de lui laisser penser qu'un nouveau formulaire d'inscription le réabonnera automatiquement sans action de sa part.

## Gérer les cas d'échec sans bloquer l'affichage

Un appel réseau externe peut toujours échouer — latence, incident chez Brevo, dépassement de quota (code 429). Le bloc doit dans tous les cas afficher quelque chose de cohérent plutôt qu'une page blanche ou une erreur PHP fatale :

- Le `timeout` de la requête est fixé à une valeur courte (6 secondes) pour ne pas ralentir tout l'affichage de la page en cas de lenteur du service distant.
- Un statut « indisponible » distinct de « non abonné » évite d'afficher une information fausse quand l'API n'a simplement pas répondu.
- Le cache conserve la dernière valeur connue un peu plus longtemps en cas d'échec répété, pour éviter d'afficher « indisponible » à chaque requête lors d'une panne prolongée côté Brevo.

> Pour ce type d'intégration, je considère qu'un appel API externe qui échoue ne doit jamais empêcher l'affichage du reste de la page : le bloc dégrade son propre contenu, jamais celui de la page qui l'entoure.

## En résumé

Ce bloc reste volontairement modeste dans son ambition : afficher un statut, pas gérer l'inscription elle-même ni déclencher une automatisation marketing. Cette limite assumée simplifie considérablement le code et le rend robuste aux pannes ponctuelles de l'API, tout en répondant précisément au besoin exprimé par l'équipe marketing du site.
