« Pourquoi installer une boutique complète pour vendre une seule chose ? » C’est la question posée par l’artisane à l’origine de ce projet : un atelier de poterie, une session par mois, douze places, un seul tarif. Installer WooCommerce pour ce cas précis aurait ajouté des tables en base de données, des réglages de TVA, des statuts de commande, pour un besoin qui tient en une phrase : encaisser une inscription et confirmer la place réservée.
Le choix s’est porté sur un bloc dynamique intégrant directement le bouton PayPal Checkout, sans passerelle de paiement supplémentaire, avec une vérification de la transaction effectuée côté serveur avant toute confirmation.
Charger le SDK PayPal au bon moment
Le script du SDK PayPal ne doit pas être chargé sur toutes les pages du site, mais uniquement là où le bloc est présent, ce que wp_enqueue_script permet de conditionner facilement à l’intérieur du render_callback du bloc :
function atelier_enregistrer_bloc_paiement() {
register_block_type( __DIR__ . '/bloc-paiement', array(
'render_callback' => 'atelier_rendre_bloc_paiement',
) );
}
add_action( 'init', 'atelier_enregistrer_bloc_paiement' );
function atelier_rendre_bloc_paiement( $attributs ) {
wp_enqueue_script(
'paypal-sdk',
'https://www.paypal.com/sdk/js?client-id=' . esc_attr( ATELIER_PAYPAL_CLIENT_ID ) . '¤cy;=EUR',
array(),
null,
true
);
return '<div id="paypal-bouton-atelier" data-tarif="' . esc_attr( $attributs['tarif'] ) . '"></div>';
}
Initialiser le bouton côté client
Le SDK expose un objet global une fois chargé, à partir duquel on construit le bouton et on définit ce qui se passe à l’approbation du paiement :
document.addEventListener('DOMContentLoaded', function () {
const conteneur = document.getElementById('paypal-bouton-atelier');
if (!conteneur || typeof paypal === 'undefined') {
return;
}
paypal.Buttons({
createOrder: function (data, actions) {
return actions.order.create({
purchase_units: [{ amount: { value: conteneur.dataset.tarif } }],
});
},
onApprove: function (data, actions) {
return actions.order.capture().then(function (details) {
return fetch('/wp-json/atelier/v1/confirmer-inscription', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ orderID: data.orderID }),
});
});
},
}).render('#paypal-bouton-atelier');
});

Ne jamais faire confiance au navigateur pour confirmer un paiement
Le point le plus important de ce montage n’est pas le bouton lui-même, mais la route REST /atelier/v1/confirmer-inscription : elle revérifie la transaction directement auprès de l’API PayPal côté serveur, avant d’enregistrer l’inscription. Faire confiance à un simple appel client indiquant « paiement réussi » ouvrirait la porte à une inscription sans paiement réel :
function atelier_confirmer_inscription( $requete ) {
$order_id = sanitize_text_field( $requete->get_param( 'orderID' ) );
$reponse = wp_remote_get(
"https://api-m.paypal.com/v2/checkout/orders/{$order_id}",
array( 'headers' => array( 'Authorization' => 'Bearer ' . atelier_obtenir_jeton_paypal() ) )
);
$commande = json_decode( wp_remote_retrieve_body( $reponse ), true );
if ( 'COMPLETED' !== $commande['status'] ) {
return new WP_Error( 'paiement_non_confirme', 'Le paiement n\'a pas pu être confirmé.', array( 'status' => 402 ) );
}
atelier_enregistrer_inscription( $order_id );
return array( 'confirme' => true );
}
Ce que ce montage ne couvre pas
Les remboursements ne sont volontairement pas traités par ce bloc : l’artisane les gère manuellement depuis son tableau de bord PayPal en cas de désistement, ce qui reste rare sur un atelier mensuel à douze places. Automatiser ce flux aurait ajouté une complexité disproportionnée par rapport au volume réel de demandes.
- Pas de gestion de stock complexe : le nombre de places restantes est un simple champ personnalisé décrémenté à la confirmation ;
- Pas de facture générée automatiquement, un reçu PayPal standard suffisant pour ce type d’activité ;
- Pas de compte utilisateur créé, l’inscription reposant uniquement sur l’adresse e-mail associée à la transaction PayPal.
Un bouton de paiement direct dans un bloc suffit largement tant que le catalogue tient en une ligne ; c’est la vérification côté serveur qui fait la différence entre un gadget et un système fiable.
En résumé
Pour un produit unique vendu à intervalle régulier, intégrer PayPal Checkout directement dans un bloc dynamique évite l’installation d’une boutique complète, à condition de ne jamais faire confiance au navigateur seul pour confirmer la transaction. La vérification côté serveur, via l’API PayPal, reste la garantie que chaque inscription correspond à un paiement réellement abouti.