# Un bloc et Stripe Checkout : un bouton de paiement sans WooCommerce

> Encaisser un paiement ponctuel ne justifie pas toujours d'installer WooCommerce. Voici comment construire un bloc dynamique qui ouvre une session Stripe Checkout.

- Auteur : WordPress Développement
- Publié le : 2023-01-18
- Mis à jour le : 2023-01-18
- Catégorie : Blocs Gutenberg
- URL : https://www.wpmoderne.fr/blocs/stripe-checkout-bloc-paiement-sans-woocommerce/

## L’essentiel

- Une session Checkout créée côté serveur uniquement
- Le bloc ne stocke jamais de clé secrète côté client
- Redirection gérée par l'URL renvoyée par Stripe

Faut-il installer WooCommerce pour vendre un billet d'entrée à 35 € une fois par mois ? Pour beaucoup de sites (association, cabinet, organisateur d'événement ponctuel), la réponse est non : la boutique complète, ses tables de commandes, ses e-mails transactionnels et ses réglages de TVA représentent un poids disproportionné face à un besoin d'encaissement simple. Un bloc dynamique dédié, qui ouvre une session Stripe Checkout hébergée, couvre largement ce cas.

L'idée tient en une phrase : le bloc affiche un bouton, un clic déclenche un appel REST vers WordPress, ce point de terminaison crée une session Stripe côté serveur et renvoie une URL de redirection vers la page de paiement hébergée par Stripe. Aucune donnée bancaire ne transite jamais par le serveur WordPress ni par le navigateur du visiteur en dehors du domaine Stripe.

## Structurer le bloc

Le bloc est un bloc dynamique classique, déclaré via `block.json` avec un attribut `priceId` (l'identifiant du prix Stripe, créé au préalable dans le tableau de bord Stripe) et un attribut `buttonLabel` modifiable dans l'éditeur.

```
{
  "apiVersion": 3,
  "name": "acme/stripe-checkout-button",
  "title": "Bouton Stripe Checkout",
  "category": "widgets",
  "attributes": {
    "priceId": { "type": "string", "default": "" },
    "buttonLabel": { "type": "string", "default": "Payer maintenant" }
  },
  "render": "file:./render.php"
}
```

Côté éditeur, un simple `InspectorControls` avec un champ `TextControl` suffit pour saisir l'identifiant de prix. Pas besoin de logique React complexe : c'est côté serveur que tout se joue.

## Créer la session côté serveur

La création de session s'effectue via le SDK PHP officiel de Stripe, installé par Composer (`composer require stripe/stripe-php`). Un point de terminaison REST dédié reçoit l'identifiant de prix et retourne l'URL de la session :

> L'essentiel à retenir : Une session Checkout créée côté serveur uniquement ; Le bloc ne stocke jamais de clé secrète côté client ; Redirection gérée par l'URL renvoyée par Stripe

```
add_action( 'rest_api_init', function() {
    register_rest_route( 'acme/v1', '/checkout-session', [
        'methods'  => 'POST',
        'callback' => 'acme_create_checkout_session',
        'permission_callback' => '__return_true',
        'args' => [
            'price_id' => [ 'required' => true, 'type' => 'string' ],
        ],
    ] );
} );

function acme_create_checkout_session( WP_REST_Request $request ) {
    \Stripe\Stripe::setApiKey( getenv( 'STRIPE_SECRET_KEY' ) );

    $session = \Stripe\Checkout\Session::create( [
        'mode' => 'payment',
        'line_items' => [ [
            'price' => $request->get_param( 'price_id' ),
            'quantity' => 1,
        ] ],
        'success_url' => home_url( '/merci/?session_id={CHECKOUT_SESSION_ID}' ),
        'cancel_url' => home_url( '/paiement-annule/' ),
    ] );

    return rest_ensure_response( [ 'url' => $session->url ] );
}
```

La clé secrète Stripe ne doit jamais être écrite en dur dans le code source du plugin : elle est chargée depuis une variable d'environnement ou une constante définie dans `wp-config.php`, hors du dossier public.

## Le rendu du bloc et son script de vue

Le fichier `render.php` affiche un bouton HTML classique, avec un attribut `data-price-id` qui reprend la valeur enregistrée par l'éditeur. Le script de vue, chargé via `viewScript` dans `block.json`, écoute le clic et appelle `apiFetch` :

```
document.querySelectorAll( '.wp-block-acme-stripe-checkout-button button' )
  .forEach( ( button ) => {
    button.addEventListener( 'click', async () => {
      button.disabled = true;
      const response = await fetch( '/wp-json/acme/v1/checkout-session', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify( { price_id: button.dataset.priceId } ),
      } );
      const data = await response.json();
      window.location.href = data.url;
    } );
  } );
```

## Sécuriser et vérifier le paiement après coup

La redirection vers `success_url` n'est qu'une indication visuelle : elle ne prouve pas que le paiement a réellement abouti, un visiteur pouvant très bien arrêter sa navigation avant confirmation. La vérification fiable passe par un webhook Stripe (`checkout.session.completed`), reçu sur un second point de terminaison REST, qui valide la signature de la requête avec `\Stripe\Webhook::constructEvent()` avant d'enregistrer quoi que ce soit.

- Ne jamais considérer une redirection de succès comme une preuve de paiement.
- Toujours vérifier la signature du webhook avec le secret dédié fourni par Stripe.
- Journaliser chaque session créée (identifiant, prix, date) pour pouvoir réconcilier avec le tableau de bord Stripe en cas de litige.

> Pour un encaissement ponctuel, je préfère systématiquement une session Checkout hébergée à une intégration Elements personnalisée : moins de code à maintenir, et la conformité PCI DSS reste entièrement du côté de Stripe.

## Notre verdict

Ce bloc n'a pas vocation à remplacer WooCommerce dès qu'apparaissent des besoins de catalogue, de factures récurrentes ou de gestion de stock. Mais pour un encaissement isolé — une adhésion, un billet, un don ponctuel — il évite l'installation d'une extension e-commerce complète pour trois lignes de configuration. Le tout tient dans un seul appel API côté serveur, ce qui limite considérablement la surface d'attaque et la maintenance à long terme.
