Open Badges aus WordPress ausstellen (ohne aufgeblähtes Plugin)
Stelle Open Badges aus jedem WordPress-Kurs-/LMS-Plugin (LearnDash, LifterLMS, Tutor) aus, indem du bei Kursabschluss die Badges Ninja API aufrufst — kein separates Badge-Plugin nötig.
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.
Wenn du Kurse auf WordPress betreibst, kennst du das Spiel bereits: Jemand schließt ein Modul in LearnDash, LifterLMS oder Tutor LMS ab, das LMS markiert es als „abgeschlossen”, und dann … passiert nichts Überprüfbares. Vielleicht schickst du eine PDF per E-Mail. Vielleicht installierst du ein dediziertes WordPress-Badge-Plugin, das eigene Datenbanktabellen, eine eigene Bildbibliothek und eine eigene Vorstellung davon mitbringt, was ein „Abzeichen” ist — eines, das niemand außerhalb deiner Seite überprüfen kann.
Es gibt einen einfacheren Weg. WordPress-Kurs-Plugins lösen bereits in dem Moment, in dem jemand einen Kurs abschließt, einen Action-Hook aus. Du kannst diesen Hook abfangen und einen einzigen HTTP-Aufruf an die Badges Ninja API machen. Kein zusätzliches Plugin, kein zusätzliches Hosting, kein proprietäres Badge-Format — nur eine standardkonforme Open-Badge-v2.0-Credential, die dein Empfänger überall verifizieren, zu LinkedIn hinzufügen und als PDF herunterladen kann.
Dieser Beitrag führt einmal durch das Muster und zeigt dann den konkreten Hook für LearnDash, LifterLMS und Tutor LMS.
Warum nicht einfach ein WordPress-Badge-Plugin verwenden?
Dedizierte WordPress-Badge-Plugins lösen ein engeres Problem, als es zunächst scheint. Sie sind gut darin, ein Bild auf einer „Meine Erfolge”-Seite innerhalb deiner Website anzuzeigen. Bei den Dingen, die für eine Credential wirklich zählen, sind sie meist deutlich schwächer:
- Portabilität. Ein Abzeichen, das nur als Shortcode auf deiner WordPress-Seite existiert, ist keine Credential — es ist eine Dekoration. Sobald der Empfänger den Job wechselt, sein Postfach wechselt oder deine Website ausfällt, verschwindet der „Nachweis” mit.
- Verifizierung. Jeder sollte überprüfen können, ob eine Credential echt ist, ohne sich in dein WordPress-Admin einzuloggen. Open Badge v2.0 bietet dir von Haus aus eine öffentliche Verifizierungs-URL und maschinenlesbares JSON-LD.
- Wartungsaufwand. Jedes WordPress-Plugin ist ein weiteres Ding, das gepatcht werden muss, eine weitere Datenbanktabelle, die gesichert werden muss, ein weiterer möglicher Ausfallpunkt bei einem Core-Update.
Der Aufruf einer externen API bei Kursabschluss umgeht alle drei Probleme. WordPress bleibt für das zuständig, worin es gut ist — Content-Auslieferung und Fortschrittsverfolgung —, und die Credential selbst lebt in einem System, das speziell dafür gebaut wurde, sie auszustellen, zu verifizieren und zu teilen.
Das Muster: ein Hook, ein HTTP-Aufruf
Jedes wichtige WordPress-LMS-Plugin löst eine Action aus, wenn ein Nutzer einen Kurs abschließt. Die Integration besteht immer aus denselben drei Schritten:
- In die Abschluss-Action einklinken für dein spezifisches LMS.
- Die Identität des Empfängers nachschlagen (oder anlegen) — normalerweise einfach die E-Mail-Adresse und der Anzeigename seines WordPress-Kontos.
POST /awardsauf der Badges Ninja API mitwp_remote_post()aufrufen und dabei die Badge-ID sowie die Empfängerdaten übergeben.
Zuerst brauchst du einen API-Schlüssel. Erzeuge einen in deinem Dashboard unter API Keys — die vollständige Anleitung findest du im API-Keys-Guide. Schlüssel werden nur einmal bei der Erstellung angezeigt, speichere ihn deshalb als Konstante in wp-config.php statt in der Datenbank:
define( 'BADGES_NINJA_API_KEY', 'bws_your_32_hex_key_here' );
define( 'BADGES_NINJA_BADGE_ID', 'your-badge-id' );

Halte diesen Schlüssel serverseitig. Alles in dieser Anleitung läuft in PHP auf deinem WordPress-Server — wp_remote_post() ist ein serverseitiger Aufruf, und wp-config.php wird niemals an den Browser gesendet. Genau das willst du: Der Schlüssel reist Server-zu-Server über HTTPS, und kein Website-Besucher kann ihn auslesen. Verschiebe diesen Aufruf niemals in clientseitiges JavaScript — ein fetch() aus dem Browser mit dem eingebetteten Schlüssel würde ihn jedem über die Entwicklertools des Browsers zugänglich machen. Zwei Gewohnheiten lohnen sich: Stelle sicher, dass dein Host wp-config.php als ausgeführtes PHP ausliefert (niemals als Klartext, und lass keine wp-config.php.bak-Kopie im Webroot liegen), und lege einen dedizierten API-Schlüssel für diese Integration an, damit du ihn im Kompromittierungsfall unabhängig widerrufen kannst — ohne deine anderen Tools zu beeinträchtigen.
Eine gemeinsam genutzte Helper-Funktion hält jeden LMS-Hook schlank:
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 );
}
Die E-Mail-Adresse des Empfängers wird serverseitig SHA-256-gehasht, sobald sie bei Badges Ninja ankommt, und die Rückgabe enthält die Verifizierungs-URL der Award — praktisch, wenn du direkt in WordPress nach erfolgreichem Aufruf einen „Deine Credential ansehen”-Link anzeigen willst.
LearnDash
LearnDash löst learndash_course_completed mit einem einzelnen Array-Argument aus, das user und course enthält:
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 );
} );
Die Badge-ID als Kurs-Metadaten zu speichern (statt einer einzigen globalen BADGES_NINJA_BADGE_ID-Konstante) ist die richtige Entscheidung, sobald du mehr als einen Kurs hast — jeder Kurs ordnet sich seinem eigenen Badge-Design zu.
LifterLMS
LifterLMS löst lifterlms_course_completed mit $user_id und $course_id aus:
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 löst tutor_course_complete_after mit der Kurs-ID aus, und du holst den aktuellen Nutzer aus der 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 );
} );
Wenn dein Tutor-LMS-Setup den Abschluss aus einem Hintergrundprozess auslöst (z. B. über eine automatische Quiz-Bewertung), tausche get_current_user_id() gegen die Nutzer-ID aus, die dein spezifischer Hook liefert — prüfe die Payload einmalig während des Setups mit error_log( print_r( func_get_args(), true ) ), um die Argumente zu bestätigen.
Das Badge entwerfen, bevor du den Hook verdrahtest
Bevor irgendetwas davon feuert, brauchst du ein Badge, das du vergeben kannst. Der visuelle Designer deckt das ab, ohne dass du einen Designer im Team brauchst — über 80 Formvorlagen, individuelle Farben, eine Icon-Bibliothek und Logo-Upload, alles mit Snap-to-Grid. Wenn du neu im Designer bist, führt dich Dein erstes verifizierbares digitales Zertifikat gestalten durch die Auswahl einer Vorlage und das Ausliefern von etwas, das Empfänger tatsächlich teilen wollen.
Sobald das Badge existiert, hole dir seine ID aus dem Dashboard (oder über GET /badges) und trage sie in das Custom Field deines Kurses ein.
Was der Empfänger tatsächlich bekommt
Das ist der Teil, den ein selbstgebautes WordPress-Badge-Plugin nicht nachbilden kann. Wenn POST /awards erfolgreich ist, erhält der Empfänger:
- Eine eindeutige Verifizierungs-URL, die jeder öffnen kann — kein WordPress-Login nötig — die zeigt, dass die Credential echt ist, wer sie ausgestellt hat und wann.
- Einen QR-Code und ein A4-PDF-Zertifikat, automatisch generiert.
- Einen „Zu LinkedIn-Profil hinzufügen”-Button, falls dein Aussteller eine LinkedIn-Organisations-ID hinterlegt hat — siehe Einen LinkedIn-„Zum Profil hinzufügen”-Button einrichten für die einmalige Einrichtung.
- Zugang zum eigenen Empfänger-Portal unter
badges.ninja/meper Magic-Link-Anmeldung — kein Passwort zum Vergessen, kein separates Konto, das auf deiner WordPress-Seite verwaltet werden muss. - Standardkonformes Open-Badge-v2.0-JSON-LD, sodass jeder OB-fähige Verifizierer (nicht nur Badges Ninja) es validieren kann.
Nichts davon ist Aufgabe von WordPress, und nichts davon sollte ausschließlich in deiner WordPress-Datenbank leben.
Fehler elegant abfangen
Kursabschluss-Hooks feuern während eines laufenden Seitenaufrufs, und ein langsamer oder fehlgeschlagener API-Aufruf sollte nicht den „Herzlichen Glückwunsch”-Bildschirm des Lernenden blockieren. Zwei praktische Anpassungen, sobald du über den Proof of Concept hinausgehst:
Lass eine fehlgeschlagene Award-Vergabe nicht die UI blockieren. Die obige Helper-Funktion loggt bereits und gibt false zurück, statt eine Exception zu werfen — LearnDash, LifterLMS und Tutor setzen ihren normalen Abschluss-Flow unabhängig davon fort, was badges_ninja_issue_award() zurückgibt.
Bei Größenordnung: einreihen statt inline aufrufen. Wenn du große Kohorten gleichzeitig durch einen einzelnen Kurs schleust (ein Kohorten-Startdatum, die Freischaltung einer Webinar-Aufzeichnung), löse stattdessen aus dem Hook ein WP-Cron-Event aus, statt die API synchron aufzurufen:
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 );
Das verteilt die Last und verhindert, dass eine einzelne langsame Anfrage zum Problem des Lernenden wird. Bei wirklich großen Stapeln (eine ganze vergangene Kohorte, die in einem Rutsch migriert wird) überspringe den WordPress-Hook-Weg komplett und nutze Massenvergabe per CSV — einmal hochladen, und die Plattform paginiert die Ausstellung serverseitig mit eingebauter Pause/Fortsetzen-Funktion.
Eine Anmerkung zur Idempotenz
Wenn dein LMS seinen Abschluss-Hook jemals mehr als einmal für denselben Nutzer feuert (ein häufiger LearnDash-Sonderfall bei Quiz-Wiederholungen, oder eine Tutor-LMS-Neusynchronisierung), willst du nicht dasselbe Badge doppelt vergeben. Der einfachste Schutz ist ein WordPress-User-Meta-Flag, das du direkt nach einem erfolgreichen Aufruf setzt:
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 );
}
Wenn du in echtem Volumen ausstellst und das zentral statt pro Website gehandhabt haben willst, wirf einen Blick auf webhook-gesteuerte Ereignisverarbeitung oder den vollständigen API-Schnellstart für die Request-/Response-Formate über alle Endpunkte hinweg.
Wenn dieses Muster über einen einzelnen Kurs hinauswächst
Die obigen Beispiele gehen von einem Badge pro Kurs aus. Sobald du stapelbare Credentials betreibst — ein Track-Badge, das sich nach mehreren Kurs-Badges freischaltet, oder ein Abschluss-Badge, das von mehreren Voraussetzungen abhängt — verlagere die „welches Badge für welchen Abschluss”-Zuordnung aus den Post-Metadaten in eine kleine Lookup-Tabelle, oder steuere sie über eine tabellenbasierte Automatisierung (Airtable oder Google Sheets), die denselben POST /awards-Aufruf auslöst. Der API-Aufruf selbst ändert sich nicht — nur das, was entscheidet, wann er ausgeführt wird.
Fehlerbehebung bei der Integration
Eine Handvoll Probleme ist für den Großteil der Reibung verantwortlich, auf die Leute beim ersten Verdrahten stoßen:
Der Hook feuert nie. Vergewissere dich, dass du die richtige Action für die tatsächliche Version deines Plugins einhängst — insbesondere LearnDash hat die Namen der Abschluss-Hooks über größere Releases hinweg geändert (ältere Installationen verlassen sich manchmal noch darauf, dass learndash_course_completed über einen anderen Codepfad feuert als bei neueren Versionen). Füge oben in deinem Callback ein temporäres error_log() ein und beobachte wp-content/debug.log, während du als Wegwerf-Testnutzer einen Testkurs abschließt.
wp_remote_post() läuft in ein Timeout. Shared-Hosting-Umgebungen blockieren manchmal ausgehendes HTTPS zu unbekannten Hosts oder begrenzen Request-Timeouts unter die oben gesetzten 15 Sekunden. Wenn Aufrufe konsequent in ein Timeout laufen, frage bei deinem Host nach, ob ausgehende Verbindungen zu api.badges.ninja erlaubt sind, und stelle sicher, dass deine PHP-curl-Erweiterung aktuelle CA-Zertifikate hat — ein veraltetes Zertifikatsbündel ist ein häufiger stiller Fehler auf älteren Shared-Hosting-Stacks.
400 Bad Request. Der Payload fehlt ein Pflichtfeld oder hat die falsche Form. POST /awards erwartet badgeId, ein verschachteltes recipient-Objekt mit name und email sowie einen issuedOn-Zeitstempel — die obige Helper-Funktion sendet genau das. Der häufigste Stolperstein ist der Name des Empfängers: Er muss mindestens 5 Zeichen lang sein, sodass ein WordPress-Anzeigename wie „Jo” abgelehnt wird. Weiche auf den vollständigen Namen des Kontos (oder den lokalen Teil der E-Mail-Adresse) aus, wenn der Anzeigename zu kurz ist.
401 Unauthorized. Die API-Schlüssel-Konstante wird nicht geladen, oder der Schlüssel wurde neu erzeugt, nachdem die Konstante gesetzt wurde. Schlüssel werden nur einmal bei der Erstellung angezeigt und können nicht erneut abgerufen werden — wenn du den Überblick verloren hast, welcher Schlüssel aktiv ist, lösche den alten und stelle einen neuen aus, statt zu raten.
Badge ausgestellt, aber mit dem falschen Design. Das liegt fast immer an einem veralteten badges_ninja_badge_id-Post-Metadatenwert, der von Tests übrig geblieben ist. Da die Zuordnung im Kurs-Post lebt, vergisst man leicht, dass man sie nach dem Duplizieren eines Kurses für eine neue Kohorte geändert hat — ein kurzer Check lohnt sich, wann immer du einen Kurs klonst.
Doppelte Awards für dieselbe Person. Oben mit dem User-Meta-Schutz abgedeckt, aber es lohnt sich, es zu wiederholen: LMS-Abschluss-Hooks sind nicht garantiert genau einmal auszulösen. Behandle „bereits vergeben” als normalen Fall, den du prüfst, nicht als Randfall, den du ignorierst.
Häufig gestellte Fragen
Funktioniert das mit WooCommerce-Kursbundles? Ja — wenn ein Bundle-Kauf unabhängig vom Kursabschluss ein Badge auslösen soll (z. B. ein „zertifiziertes Mitglied”-Badge für jeden, der ein bestimmtes Bundle kauft), hänge dich stattdessen in woocommerce_order_status_completed statt in eine LMS-Abschluss-Action ein und schlage die Badge-ID in den Produkt-Metadaten statt in einem Kurs nach.
Können Empfänger das Badge ohne WordPress-Konto bekommen? Ja, und das ist genau der Punkt. Die Award ist an ihre E-Mail-Adresse in Badges Ninja gebunden, nicht an einen WordPress-Nutzerdatensatz. Wenn deine Website Gastbestellungen oder anonymen Quiz-Abschluss erlaubt, stelle nur sicher, dass du eine echte E-Mail-Adresse erfasst, die du an badges_ninja_issue_award() übergibst.
Was, wenn ich Awards prüfen möchte, bevor sie rausgehen? Löse den Aufruf nicht direkt aus dem Abschluss-Hook aus. Schreibe stattdessen die ausstehende Award (Nutzer, Kurs, Zeitstempel) in eine benutzerdefinierte Tabelle oder einen Post-Type und stelle sie über eine geplante Aufgabe oder einen Admin-„Genehmigen & Vergeben”-Button aus, der auf Abruf dieselbe Helper-Funktion aufruft.
Brauche ich ein separates Badge pro Kurs, oder kann eines mehrere abdecken? Beides funktioniert. Manche Aussteller erstellen ein Badge pro Kurs für Granularität; andere erstellen ein einziges „Programm abgeschlossen”-Badge und vergeben es erst, wenn jeder erforderliche Kurs abgeschlossen ist, indem sie den Abschluss der Voraussetzungen innerhalb des Hooks prüfen, bevor sie die API aufrufen.
Bereit, deine erste verifizierbare Credential auszustellen? Kostenlos starten auf badges.ninja — visueller Designer, öffentliche Verifizierungsseite, PDF-Zertifikat, Open-Badge-v2.0-Ausgabe. Keine Kreditkarte erforderlich.
Wie dieser Artikel entstanden ist
Einige Beiträge in diesem Blog werden mithilfe eines KI-Assistenten entworfen und anschließend vom Badges-Ninja-Team geprüft, faktengecheckt und redigiert, bevor sie veröffentlicht werden. Jedes Codebeispiel und jeder Preis wird mit dem Live-Produkt abgeglichen. Mehr über unseren Redaktions- und KI-Prozess erfährst du auf unserer Seite zum Redaktionsprozess .

Über den Autor
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.
Mehr von Nacho Coll
- Salesforce Open Badges: Verifizierbare Credentials per CRM-Trigger ausstellen1. Okt. 2026 · 9Min. Lesezeit
- Open Badges über die Badges-Ninja-REST-API ausstellen: Quickstart28. Sept. 2026 · 9Min. Lesezeit
- Badge-Verifizierung auf deiner Website einbetten (ohne Iframe, ohne SDK)24. Sept. 2026 · 9Min. Lesezeit
