Le WordPress d'aujourd'hui, décodé pour les développeurs

Blocs Gutenberg

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.

Par WordPress Développement • 18 janvier 2023 • 4 min de lecture • Aucun commentaire
Un bloc et Stripe Checkout : un bouton de paiement sans WooCommerce

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.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi