Émettre des Open Badges depuis WordPress (sans plugin lourd)
Émettez des Open Badges depuis n'importe quel plugin de cours ou de LMS WordPress (LearnDash, LifterLMS, Tutor) en appelant l'API Badges Ninja à la fin du cours — sans installer de plugin de badge séparé.
Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure.
Si vous gérez des cours sur WordPress, vous connaissez déjà le scénario : quelqu’un termine un module dans LearnDash, LifterLMS ou Tutor LMS, le LMS le marque comme « terminé », et ensuite… rien de vérifiable ne se passe. Peut-être envoyez-vous un PDF par e-mail. Peut-être installez-vous un plugin de badge WordPress dédié, qui ajoute ses propres tables de base de données, sa propre bibliothèque d’images, et sa propre idée de ce qu’est un « badge » — une idée que personne en dehors de votre site ne peut vérifier.
Il existe un chemin plus simple. Les plugins de cours WordPress déclenchent déjà un hook d’action au moment où quelqu’un termine un cours. Vous pouvez intercepter ce hook et effectuer un seul appel HTTP vers l’API Badges Ninja. Pas de plugin supplémentaire, pas d’hébergement supplémentaire, pas de format de badge propriétaire — juste un identifiant Open Badge v2.0 conforme aux normes, que votre destinataire peut vérifier n’importe où, ajouter à LinkedIn et télécharger en PDF.
Cet article présente d’abord le principe général, puis montre le hook spécifique pour LearnDash, LifterLMS et Tutor LMS.
Pourquoi ne pas simplement utiliser un plugin de badge WordPress ?
Les plugins de badge WordPress dédiés résolvent un problème plus restreint qu’il n’y paraît. Ils sont doués pour afficher une image sur une page « mes réalisations » à l’intérieur de votre site. Ils sont généralement beaucoup plus faibles sur les aspects qui comptent réellement pour un identifiant :
- Portabilité. Un badge qui n’existe que sous forme de shortcode sur votre site WordPress n’est pas un identifiant — c’est une décoration. Dès que le destinataire change d’emploi, change de boîte mail, ou que votre site tombe en panne, la « preuve » disparaît avec lui.
- Vérification. N’importe qui devrait pouvoir vérifier qu’un identifiant est authentique sans se connecter à votre back-office WordPress. Open Badge v2.0 fournit par conception une URL de vérification publique et un JSON-LD lisible par machine.
- Surface de maintenance. Chaque plugin WordPress est une chose de plus à corriger, une table de base de données de plus à sauvegarder, un point de défaillance de plus lors d’une mise à jour du cœur.
Appeler une API externe à la fin d’un cours contourne ces trois problèmes. WordPress reste responsable de ce qu’il fait bien — la diffusion de contenu et le suivi de la progression — tandis que l’identifiant lui-même vit dans un système conçu spécifiquement pour l’émettre, le vérifier et le partager.
Le principe : un hook, un appel HTTP
Chaque grand plugin de LMS WordPress déclenche une action lorsqu’un utilisateur termine un cours. L’intégration se résume toujours aux trois mêmes étapes :
- Accrochez-vous à l’action de complétion propre à votre LMS.
- Recherchez (ou créez) l’identité du destinataire — généralement juste son e-mail et son nom d’affichage de compte WordPress.
- Appelez
POST /awardssur l’API Badges Ninja avecwp_remote_post(), en passant l’ID du badge et les informations du destinataire.
Il vous faudra d’abord une clé API. Générez-en une depuis votre tableau de bord, sous API Keys — consultez le guide des clés API pour la marche à suivre complète. Les clés ne s’affichent qu’une seule fois, à leur création : stockez-la donc dans wp-config.php sous forme de constante plutôt que dans la base de données :
define( 'BADGES_NINJA_API_KEY', 'bws_your_32_hex_key_here' );
define( 'BADGES_NINJA_BADGE_ID', 'your-badge-id' );

Conservez cette clé côté serveur. Tout ce qui est décrit dans ce guide s’exécute en PHP sur votre serveur WordPress — wp_remote_post() est un appel côté serveur, et wp-config.php n’est jamais envoyé au navigateur. C’est exactement ce que l’on souhaite : la clé circule de serveur à serveur via HTTPS, et aucun visiteur du site ne peut la lire. Ne déplacez jamais cet appel vers du JavaScript côté client : un fetch() exécuté depuis le navigateur avec la clé intégrée l’exposerait à quiconque via les outils de développement de son navigateur. Deux habitudes à conserver : assurez-vous que votre hébergeur sert wp-config.php comme du PHP exécuté (jamais en texte brut), et ne laissez pas traîner de copie wp-config.php.bak dans le webroot ; créez également une clé API dédiée pour cette intégration, afin de pouvoir la révoquer indépendamment en cas de compromission — sans casser vos autres outils.
Une fonction d’assistance partagée permet de garder chaque hook de LMS léger :
function badges_ninja_issue_award( $recipient_email, $recipient_name, $badge_id ) {
$response = wp_remote_post( 'https://api.badges.ninja/awards', array(
'headers' => array(
'X-Api-Key' => BADGES_NINJA_API_KEY,
'Content-Type' => 'application/json',
),
'body' => wp_json_encode( array(
'badgeId' => $badge_id,
'recipient' => array(
'name' => $recipient_name, // must be at least 5 characters
'email' => $recipient_email,
),
'issuedOn' => round( microtime( true ) * 1000 ), // epoch milliseconds
) ),
'timeout' => 15,
) );
if ( is_wp_error( $response ) ) {
error_log( 'Badges Ninja award failed: ' . $response->get_error_message() );
return false;
}
$code = wp_remote_retrieve_response_code( $response );
if ( $code >= 400 ) {
error_log( 'Badges Ninja award failed with HTTP ' . $code . ': ' . wp_remote_retrieve_body( $response ) );
return false;
}
return json_decode( wp_remote_retrieve_body( $response ), true );
}
L’e-mail du destinataire est haché en SHA-256 côté serveur dès qu’il atteint Badges Ninja, et la réponse renvoyée inclut l’URL de vérification de l’attribution — pratique si vous souhaitez afficher directement dans WordPress un lien « voir votre identifiant » une fois l’appel réussi.
LearnDash
LearnDash déclenche learndash_course_completed avec un unique argument tableau contenant user et course :
add_action( 'learndash_course_completed', function( $data ) {
$user = $data['user'];
$course = $data['course'];
// Map LearnDash course ID → your Badges Ninja badge ID.
// A simple approach: store the badge ID in a course custom field.
$badge_id = get_post_meta( $course->ID, 'badges_ninja_badge_id', true );
if ( ! $badge_id ) {
return; // no badge configured for this course
}
badges_ninja_issue_award( $user->user_email, $user->display_name, $badge_id );
} );
Stocker l’ID du badge en tant que méta de cours (plutôt qu’une unique constante globale BADGES_NINJA_BADGE_ID) devient le bon choix dès que vous avez plus d’un cours — chaque cours correspond alors à son propre design de badge.
LifterLMS
LifterLMS déclenche lifterlms_course_completed avec $user_id et $course_id :
add_action( 'lifterlms_course_completed', function( $user_id, $course_id ) {
$user = get_userdata( $user_id );
$badge_id = get_post_meta( $course_id, 'badges_ninja_badge_id', true );
if ( ! $user || ! $badge_id ) {
return;
}
badges_ninja_issue_award( $user->user_email, $user->display_name, $badge_id );
}, 10, 2 );
Tutor LMS
Tutor LMS déclenche tutor_course_complete_after avec l’ID du cours, et vous récupérez l’utilisateur courant depuis la session :
add_action( 'tutor_course_complete_after', function( $course_id ) {
$user_id = get_current_user_id();
$user = get_userdata( $user_id );
$badge_id = get_post_meta( $course_id, 'badges_ninja_badge_id', true );
if ( ! $user || ! $badge_id ) {
return;
}
badges_ninja_issue_award( $user->user_email, $user->display_name, $badge_id );
} );
Si votre installation Tutor LMS déclenche la complétion depuis un processus en arrière-plan (par exemple via une correction automatique de quiz), remplacez get_current_user_id() par l’ID utilisateur que fournit votre hook spécifique — vérifiez la charge utile avec error_log( print_r( func_get_args(), true ) ) une fois lors de la configuration, pour confirmer les arguments.
Concevoir le badge avant de brancher le hook
Avant que tout cela ne se déclenche, il vous faut un badge à décerner. Le designer visuel permet de s’en occuper sans avoir besoin d’un designer dans l’équipe — plus de 80 modèles de formes, couleurs personnalisées, bibliothèque d’icônes et upload de logo, le tout avec accrochage à la grille. Si vous découvrez le designer, Concevoir votre premier certificat numérique vérifiable vous guide du choix d’un modèle jusqu’à la production de quelque chose que les destinataires auront réellement envie de partager.
Une fois le badge créé, récupérez son ID depuis le tableau de bord (ou via GET /badges) et placez-le dans le champ personnalisé de votre cours.
Ce que le destinataire obtient réellement
C’est là que réside ce qu’un plugin de badge WordPress maison ne peut pas reproduire. Lorsque POST /awards réussit, le destinataire obtient :
- une URL de vérification unique que n’importe qui peut ouvrir — sans connexion WordPress requise — montrant que l’identifiant est authentique, qui l’a émis et quand ;
- un QR code et un certificat PDF au format A4, générés automatiquement ;
- un bouton « Ajouter à mon profil LinkedIn », si votre émetteur a défini un identifiant d’organisation LinkedIn — voir Ajouter un bouton « Ajouter à mon profil » LinkedIn pour la configuration à effectuer une seule fois ;
- l’accès à son propre portail destinataire sur
badges.ninja/me, via une connexion par lien magique — pas de mot de passe à oublier, pas de compte séparé à gérer sur votre site WordPress ; - un JSON-LD Open Badge v2.0 conforme aux normes, que n’importe quel vérificateur compatible OB (pas seulement Badges Ninja) peut valider.
Rien de tout cela n’est le travail de WordPress, et rien de tout cela ne devrait vivre uniquement dans votre base de données WordPress.
Gérer les échecs avec élégance
Les hooks de complétion de cours se déclenchent pendant une requête de page en direct, et un appel API lent ou en échec ne doit pas bloquer l’écran de « félicitations » de l’apprenant. Deux ajustements pratiques une fois passée la preuve de concept :
Ne laissez pas un échec d’attribution bloquer l’interface. La fonction d’assistance ci-dessus enregistre déjà l’erreur et renvoie false plutôt que de lever une exception — LearnDash, LifterLMS et Tutor poursuivent tous leur flux de complétion normal, quel que soit ce que renvoie badges_ninja_issue_award().
Mettez en file d’attente plutôt que d’appeler en ligne, à grande échelle. Si vous faites passer de larges cohortes par un même cours en une seule fois (une date de démarrage de cohorte, le déblocage d’une rediffusion de webinaire), déclenchez un événement planifié WP-Cron depuis le hook plutôt que d’appeler l’API de manière synchrone :
add_action( 'learndash_course_completed', function( $data ) {
wp_schedule_single_event( time() + 30, 'badges_ninja_deferred_award', array(
$data['user']->user_email,
$data['user']->display_name,
get_post_meta( $data['course']->ID, 'badges_ninja_badge_id', true ),
) );
} );
add_action( 'badges_ninja_deferred_award', 'badges_ninja_issue_award', 10, 3 );
Cela répartit la charge et empêche qu’une seule requête lente ne devienne le problème de l’apprenant. Pour des lots véritablement importants (une cohorte entière migrée en une seule fois), évitez complètement le chemin du hook WordPress et utilisez les attributions en masse via CSV — chargez une seule fois, et la plateforme pagine l’émission côté serveur, avec pause et reprise intégrées.
Une remarque sur l’idempotence
Si votre LMS déclenche parfois son hook de complétion plus d’une fois pour le même utilisateur (un cas limite courant chez LearnDash avec les reprises de quiz, ou une resynchronisation Tutor LMS), vous ne voulez pas décerner le même badge deux fois. La protection la plus simple est un indicateur de méta-utilisateur WordPress que vous définissez juste après un appel réussi :
if ( get_user_meta( $user_id, 'badges_ninja_awarded_' . $course_id, true ) ) {
return; // already issued
}
$result = badges_ninja_issue_award( $user->user_email, $user->display_name, $badge_id );
if ( $result ) {
update_user_meta( $user_id, 'badges_ninja_awarded_' . $course_id, true );
}
Si vous émettez à grand volume et souhaitez gérer cela de manière centralisée plutôt que site par site, consultez le traitement d’événements piloté par webhooks ou le guide de démarrage rapide de l’API complet pour les formats de requête et de réponse de chaque point de terminaison.
Quand ce principe dépasse un seul cours
Les exemples ci-dessus supposent un badge par cours. Une fois que vous gérez des identifiants empilables — un badge de parcours qui se débloque après plusieurs badges de cours, ou une pierre angulaire qui dépend de plusieurs prérequis —, sortez la correspondance « quel badge, pour quelle complétion » des méta-données de l’article pour la placer dans une petite table de correspondance, ou pilotez-la depuis une automatisation adossée à un tableur (Airtable ou Google Sheets) qui déclenche le même appel POST /awards. L’appel API lui-même ne change pas ; seul change ce qui décide du moment où l’effectuer.
Résoudre les problèmes d’intégration
Une poignée de problèmes explique la majorité des difficultés rencontrées lors d’une première mise en place.
Le hook ne se déclenche jamais. Vérifiez que vous vous accrochez à la bonne action pour la version réelle de votre plugin — LearnDash en particulier a changé les noms de ses hooks de complétion au fil des versions majeures (certaines installations plus anciennes reposent parfois encore sur un learndash_course_completed déclenché depuis un chemin de code différent des versions plus récentes). Ajoutez un error_log() temporaire en tête de votre callback et surveillez wp-content/debug.log pendant que vous terminez un cours de test avec un utilisateur jetable.
wp_remote_post() expire. Les environnements d’hébergement mutualisé bloquent parfois le trafic HTTPS sortant vers des hôtes inconnus, ou limitent les délais d’expiration des requêtes en dessous des 15 secondes définies ci-dessus. Si les appels expirent systématiquement, vérifiez auprès de votre hébergeur si les connexions sortantes vers api.badges.ninja sont autorisées, et assurez-vous que l’extension PHP curl dispose de certificats CA à jour — un ensemble de certificats obsolète est une cause fréquente d’échec silencieux sur les infrastructures d’hébergement mutualisé plus anciennes.
400 Bad Request. La charge utile omet un champ requis ou a une forme incorrecte. POST /awards attend badgeId, un objet recipient imbriqué contenant name et email, ainsi qu’un horodatage issuedOn — la fonction d’assistance ci-dessus envoie exactement cela. Le piège le plus courant concerne le name du destinataire : il doit compter au moins 5 caractères, ce qui fait qu’un nom d’affichage WordPress comme « Jo » est rejeté. Repliez-vous sur le nom complet du compte (ou la partie locale de l’e-mail) lorsque le nom d’affichage est trop court.
401 Unauthorized. La constante de clé API ne se charge pas, ou elle a été régénérée après avoir été définie dans la constante. Les clés ne s’affichent qu’une seule fois à la création et ne peuvent pas être récupérées à nouveau — si vous ne savez plus quelle clé est active, supprimez l’ancienne et émettez-en une nouvelle plutôt que de deviner.
Le badge est émis, mais avec le mauvais design. C’est presque toujours dû à une valeur obsolète de la méta d’article badges_ninja_badge_id, restée d’un test précédent. Comme cette correspondance vit sur l’article du cours, il est facile d’oublier qu’on l’a modifiée après avoir dupliqué un cours pour une nouvelle cohorte — cela vaut la peine de vérifier rapidement à chaque duplication d’un cours.
Attributions en double pour la même personne. Couvert plus haut par la protection via méta-utilisateur, mais cela mérite d’être répété : rien ne garantit que les hooks de complétion du LMS se déclenchent exactement une seule fois. Traitez le cas « déjà attribué » comme un cas normal à vérifier, et non comme un cas limite à ignorer.
Questions fréquentes
Cela fonctionne-t-il avec les lots de cours WooCommerce ? Oui — si l’achat d’un lot doit déclencher un badge indépendamment de la complétion d’un cours (par exemple un badge « membre certifié » pour quiconque achète un lot spécifique), accrochez-vous à woocommerce_order_status_completed plutôt qu’à une action de complétion du LMS, et récupérez l’ID du badge depuis la méta du produit plutôt que depuis un cours.
Les destinataires peuvent-ils obtenir le badge sans compte WordPress ? Oui, et c’est précisément l’intérêt. L’attribution est liée à leur adresse e-mail dans Badges Ninja, pas à un enregistrement utilisateur WordPress. Si votre site autorise le paiement en tant qu’invité ou la complétion anonyme de quiz, assurez-vous simplement de capturer une adresse e-mail réelle à transmettre à badges_ninja_issue_award().
Et si je veux valider les attributions avant qu’elles ne soient envoyées ? Ne déclenchez pas l’appel directement depuis le hook de complétion. Écrivez plutôt l’attribution en attente (utilisateur, cours, horodatage) dans une table personnalisée ou un type de contenu, et émettez-la depuis une tâche planifiée ou un bouton d’administration « Approuver et attribuer » qui appelle la même fonction d’assistance à la demande.
Faut-il un badge distinct par cours, ou un seul badge peut-il en couvrir plusieurs ? Les deux fonctionnent. Certains émetteurs créent un badge par cours pour plus de granularité ; d’autres créent un unique badge de « complétion du programme » et ne l’attribuent qu’une fois tous les cours requis terminés, en vérifiant l’achèvement des prérequis dans le hook avant d’appeler l’API.
Prêt à émettre votre premier identifiant vérifiable ? Commencez gratuitement sur badges.ninja — designer visuel, page de vérification publique, certificat PDF, sortie Open Badge v2.0. Aucune carte bancaire requise.
Comment cet article a été créé
Certains articles de ce blog sont rédigés avec l'aide d'un assistant IA, puis relus, vérifiés et édités par l'équipe Badges Ninja avant publication. Chaque exemple de code et chaque prix est vérifié sur le produit réel. Pour en savoir plus sur notre processus éditorial et d'IA, consultez notre page sur le processus éditorial .

À propos de l'auteur
Nacho Coll
Founder & Engineer at Badges Ninja
Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure. Writes about the Open Badges spec, credential verification, and running a credentialing platform serverless on AWS, from the operator side of the wire.
Plus de Nacho Coll
- Open Badges et Salesforce : émettre des certifications vérifiables depuis des déclencheurs CRM1 oct. 2026 · 10min de lecture
- Émettre des Open Badges via l’API REST de Badges Ninja : guide de démarrage rapide28 sept. 2026 · 11min de lecture
- Intégrer la vérification de badges à votre site web (sans iframe, sans SDK)24 sept. 2026 · 11min de lecture
