Udstedelse af Open Badges fra WordPress (uden et tungt plugin)
Udsted Open Badges fra ethvert WordPress-kursus/LMS-plugin (LearnDash, LifterLMS, Tutor) ved at kalde Badges Ninja API'et ved gennemførelse — intet separat badge-plugin at installere.
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.
Hvis du kører kurser på WordPress, kender du allerede rutinen: nogen gennemfører et modul i LearnDash, LifterLMS eller Tutor LMS, LMS’et markerer det som “fuldført”, og så… sker der ikke noget, der kan verificeres. Måske sender du en PDF på mail. Måske installerer du et dedikeret WordPress badge-plugin, der tilføjer sine egne databasetabeller, sit eget billedbibliotek og sin egen idé om, hvad et “badge” er — én, som ingen uden for din side kan verificere.
Der findes en enklere vej. WordPress-kursusplugins udløser allerede en action hook, i det øjeblik nogen gennemfører et kursus. Du kan opsnappe den hook og lave ét HTTP-kald til Badges Ninja API’et. Intet ekstra plugin, ingen ekstra hosting, intet proprietært badge-format — bare et standardkompatibelt Open Badge v2.0-akkreditiv, som din modtager kan verificere hvor som helst, tilføje til LinkedIn og downloade som PDF.
Dette indlæg gennemgår mønsteret én gang og viser derefter det specifikke hook for LearnDash, LifterLMS og Tutor LMS.
Hvorfor ikke bare bruge et WordPress badge-plugin?
Dedikerede WordPress badge-plugins løser et snævrere problem, end de ser ud til at løse. De er gode til at vise et billede på en “mine resultater”-side inde på din side. De er som regel meget svagere til de ting, der faktisk betyder noget for et akkreditiv:
- Portabilitet. Et badge, der kun findes som en shortcode på din WordPress-side, er ikke et akkreditiv — det er en dekoration. I det øjeblik modtageren skifter job, skifter indbakke, eller din side går ned, forsvinder “beviset” med det.
- Verificering. Alle bør kunne tjekke, at et akkreditiv er ægte, uden at logge ind på din WordPress-administration. Open Badge v2.0 giver dig en offentlig verificerings-URL og maskinlæsbar JSON-LD som en del af designet.
- Vedligeholdelsesflade. Hvert WordPress-plugin er endnu en ting at patche, endnu en databasetabel at sikkerhedskopiere, endnu et fejlpunkt under en kerneopdatering.
At kalde en ekstern API ved kursusgennemførelse omgår alle tre. WordPress forbliver ansvarlig for det, det er god til — indholdslevering og fremskridtssporing — og selve akkreditivet lever i et system, der er bygget specifikt til at udstede, verificere og dele det.
Mønsteret: ét hook, ét HTTP-kald
Alle større WordPress LMS-plugins udløser en handling, når en bruger gennemfører et kursus. Integrationen er altid de samme tre trin:
- Hook ind i gennemførelseshandlingen for dit specifikke LMS.
- Slå modtagerens identitet op (eller opret den) — som regel bare deres WordPress-kontos e-mail og visningsnavn.
- Kald
POST /awardspå Badges Ninja API’et medwp_remote_post(), og send badge-ID’et og modtageroplysningerne med.
Du skal først bruge en API-nøgle. Generér én fra dit dashboard under API Keys — se API keys guide for hele gennemgangen. Nøgler vises kun én gang ved oprettelse, så gem den i wp-config.php som en konstant i stedet for i databasen:
define( 'BADGES_NINJA_API_KEY', 'bws_your_32_hex_key_here' );
define( 'BADGES_NINJA_BADGE_ID', 'your-badge-id' );

Behold denne nøgle på serversiden. Alt i denne guide kører i PHP på din WordPress-server — wp_remote_post() er et serverside-kald, og wp-config.php sendes aldrig til browseren. Det er præcis, hvad du vil have: nøglen rejser server-til-server over HTTPS, og ingen besøgende på siden kan læse den. Flyt aldrig dette kald ind i klientside-JavaScript — et fetch()-kald fra browseren med nøglen indlejret ville eksponere den for enhver via browserens udviklerværktøjer. To vaner er værd at bevare: sørg for, at din host serverer wp-config.php som udført PHP (aldrig som ren tekst, og lad ikke en wp-config.php.bak-kopi ligge i webroden), og opret en dedikeret API-nøgle til denne integration, så du kan tilbagekalde den uafhængigt, hvis den nogensinde bliver kompromitteret — uden at ødelægge dine andre værktøjer.
En delt hjælpefunktion holder hvert LMS-hook enkelt:
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 );
}
Modtagerens e-mail bliver SHA-256-hashet på serversiden, så snart den når frem til Badges Ninja, og svar-payloaden indeholder tildelingens verificerings-URL — praktisk, hvis du vil vise et “se dit akkreditiv”-link direkte i WordPress, efter kaldet er lykkedes.
LearnDash
LearnDash udløser learndash_course_completed med et enkelt array-argument, der indeholder user og 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 );
} );
At gemme badge-ID’et som kursus-metadata (i stedet for én global BADGES_NINJA_BADGE_ID-konstant) er det rigtige valg, når du har mere end ét kursus — hvert kursus knyttes til sit eget badge-design.
LifterLMS
LifterLMS udløser lifterlms_course_completed med $user_id og $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 udløser tutor_course_complete_after med kursus-ID’et, og du henter den aktuelle bruger fra sessionen:
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 );
} );
Hvis din Tutor LMS-opsætning udløser gennemførelse fra en baggrundsproces (f.eks. via automatisk bedømmelse af en quiz), skal du erstatte get_current_user_id() med det bruger-ID, dit specifikke hook giver — tjek payloaden med error_log( print_r( func_get_args(), true ) ) én gang under opsætningen for at bekræfte argumenterne.
Design badget, før du kobler hooket til
Før noget af dette udløses, skal du bruge et badge at uddele. Den visuelle designer klarer dette, uden at du behøver en designer ansat — 80+ formskabeloner, brugerdefinerede farver, ikonbibliotek og logo-upload, alt sammen med snap-to-grid. Hvis du er ny til designeren, gennemgår Design dit første verificerbare digitale certifikat, hvordan du vælger en skabelon og udgiver noget, modtagerne rent faktisk vil dele.
Når badget findes, henter du dets ID fra dashboardet (eller via GET /badges) og sætter det ind i kursets brugerdefinerede felt.
Hvad modtageren faktisk får
Dette er den del, et hjemmelavet WordPress badge-plugin ikke kan gengive. Når POST /awards lykkes, får modtageren:
- En unik verificerings-URL, som alle kan åbne — ingen WordPress-login påkrævet — der viser, at akkreditivet er ægte, hvem der udstedte det, og hvornår.
- En QR-kode og et A4 PDF-certifikat, genereret automatisk.
- En Tilføj til LinkedIn-profil-knap, hvis din udsteder har et LinkedIn-organisations-ID sat — se Tilføj en LinkedIn “Føj til profil”-knap for engangsopsætningen.
- Adgang til deres egen modtagerportal på
badges.ninja/me, via magic-link-login — ingen adgangskode at glemme, ingen separat konto at administrere på din WordPress-side. - Standardkompatibel Open Badge v2.0 JSON-LD, så enhver OB-bevidst verifikator (ikke kun Badges Ninja) kan validere det.
Intet af dette er WordPress’ opgave at bygge, og intet af det bør kun leve inde i din WordPress-database.
Håndtering af fejl på en elegant måde
Kursus-gennemførelseshooks udløses under en live sideforespørgsel, og et langsomt eller mislykket API-kald bør ikke blokere elevens “tillykke”-skærm. To praktiske justeringer, når du er kommet forbi et proof of concept:
Lad ikke en mislykket tildeling blokere UI’et. Hjælpefunktionen ovenfor logger allerede og returnerer false i stedet for at kaste en fejl — LearnDash, LifterLMS og Tutor fortsætter alle deres normale gennemførelsesflow, uanset hvad badges_ninja_issue_award() returnerer.
Sæt det i kø i stedet for at kalde det direkte, i stor skala. Hvis du kører store hold gennem ét kursus på én gang (en holdstartdato, en frigivelse af webinar-optagelse), så udløs en planlagt WP-Cron-begivenhed fra hooket i stedet for at kalde API’et synkront:
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 );
Dette spreder belastningen og forhindrer, at en enkelt langsom forespørgsel bliver elevens problem. Ved reelt store batches (et helt tidligere hold, migreret på én gang), spring WordPress-hook-vejen helt over og brug bulk-tildelinger via CSV — upload én gang, så pagineres udstedelsen server-side af platformen med indbygget pause/genoptag.
En note om idempotens
Hvis dit LMS nogensinde udløser sit gennemførelseshook mere end én gang for den samme bruger (et almindeligt LearnDash-særtilfælde med gentagne quizforsøg, eller en Tutor LMS-gensynkronisering), vil du ikke tildele det samme badge to gange. Den enkleste beskyttelse er et WordPress user-meta-flag, du sætter lige efter et vellykket kald:
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 );
}
Hvis du udsteder i reel volumen og ønsker, at dette håndteres centralt i stedet for pr. side, så se på webhook-drevet hændelseshåndtering eller den fulde API-hurtigstart for request/response-formerne på tværs af alle endpoints.
Når dette mønster vokser fra ét kursus
Eksemplerne ovenfor forudsætter ét badge pr. kursus. Når du begynder at køre stablelige akkreditiver — et spor-badge, der låses op efter flere kursus-badges, eller et afsluttende badge, der afhænger af flere forudsætninger — så flyt kortlægningen af “hvilket badge, for hvilken gennemførelse” ud af post-metadata og over i en lille opslagstabel, eller drevet af en regnearksbaseret automatisering (Airtable eller Google Sheets), der udløser det samme POST /awards-kald. Selve API-kaldet ændrer sig ikke; det er kun det, der afgør, hvornår det skal foretages, der gør.
Fejlfinding af integrationen
En håndfuld problemer står for det meste af den friktion, folk støder på, når de kobler dette op for første gang:
Hooket udløses aldrig. Bekræft, at du hooker ind i den rigtige handling for din plugin-versions faktiske version — især LearnDash har ændret navnene på gennemførelseshooks på tværs af større udgivelser (ældre installationer er nogle gange stadig afhængige af, at learndash_course_completed udløses fra en anden kodesti end nyere gør). Tilføj et midlertidigt error_log() øverst i dit callback og hold øje med wp-content/debug.log, mens du gennemfører et testkursus som en engangsbruger.
wp_remote_post() timer ud. Delte hostingmiljøer blokerer nogle gange udgående HTTPS til ukendte hosts eller sætter et loft for request-timeouts under de 15 sekunder, der er sat ovenfor. Hvis kald konsekvent timer ud, så tjek med din host, om udgående forbindelser til api.badges.ninja er tilladt, og bekræft, at din PHP curl-udvidelse har aktuelle CA-certifikater — en forældet certifikatpakke er en almindelig lydløs fejl på ældre shared-hosting-stacks.
400 Bad Request. Payloaden mangler et påkrævet felt eller har den forkerte form. POST /awards forventer badgeId, et indlejret recipient-objekt med name og email samt et issuedOn-tidsstempel — hjælpefunktionen ovenfor sender netop det. Den mest almindelige faldgrube er modtagerens navn: det skal være mindst 5 tegn, så et WordPress-visningsnavn som “Jo” bliver afvist. Fald tilbage til kontoens fulde navn (eller e-mailens lokale del), når visningsnavnet er for kort.
401 Unauthorized. API-nøgle-konstanten indlæses ikke, eller den blev regenereret, efter at konstanten blev sat. Nøgler vises kun én gang ved oprettelse og kan ikke hentes igen — hvis du har mistet overblikket over, hvilken nøgle der er aktiv, så slet den forældede og udsted en ny i stedet for at gætte.
Badge udstedt, men til det forkerte badge-design. Dette er næsten altid en forældet badges_ninja_badge_id post-metaværdi, der er tilbage fra testning. Fordi kortlægningen ligger på kursus-posten, er det let at glemme, at du har ændret den, efter du har duplikeret et kursus til et nyt hold — værd at tjekke hurtigt, hver gang du kloner et kursus.
Dobbelte tildelinger til samme person. Dækket ovenfor med user-meta-beskyttelsen, men værd at gentage: LMS-gennemførelseshooks er ikke garanteret at udløses præcis én gang. Behandl “allerede tildelt” som et normalt tilfælde, du tjekker for, ikke et særtilfælde, du ignorerer.
Ofte stillede spørgsmål
Virker dette med WooCommerce-kursuspakker? Ja — hvis et pakkekøb skal udløse et badge uafhængigt af kursusgennemførelse (f.eks. et “certificeret medlem”-badge til alle, der køber en bestemt pakke), så hook ind i woocommerce_order_status_completed i stedet for en LMS-gennemførelseshandling, og slå badge-ID’et op fra produkt-metadata i stedet for et kursus.
Kan modtagere få badget uden en WordPress-konto? Ja, og det er hele pointen. Tildelingen er knyttet til deres e-mailadresse i Badges Ninja, ikke til en WordPress-brugerpost. Hvis din side tillader gæstekøb eller anonym quizgennemførelse, skal du bare sørge for, at du opsamler en rigtig e-mailadresse til at sende med ind i badges_ninja_issue_award().
Hvad hvis jeg vil gennemgå tildelinger, før de sendes ud? Undlad at udløse kaldet direkte fra gennemførelseshooket. Skriv i stedet den ventende tildeling (bruger, kursus, tidsstempel) til en brugerdefineret tabel eller posttype, og udsted den fra en planlagt opgave eller en admin-knap “Godkend & tildel”, der kalder den samme hjælpefunktion efter behov.
Skal jeg have et separat badge pr. kursus, eller kan ét badge dække flere? Begge dele virker. Nogle udstedere opretter ét badge pr. kursus for detaljeringsgrad; andre opretter ét samlet “programgennemførelse”-badge og tildeler det først, når alle påkrævede kurser er gennemført, ved at tjekke forudsætningernes gennemførelse inde i hooket, før API’et kaldes.
Klar til at udstede dit første verificerbare akkreditiv? Start gratis på badges.ninja — visuel designer, offentlig verificeringsside, PDF-certifikat, Open Badge v2.0-output. Intet kreditkort påkrævet.
Sådan blev denne artikel til
Nogle indlæg på denne blog udarbejdes med hjælp fra en AI-assistent og gennemgås, faktatjekkes og redigeres af Badges Ninja-teamet inden udgivelse. Alle kodeeksempler og priser verificeres mod det live produkt. Læs mere om vores redaktionelle proces og AI-proces på vores side om vores redaktionelle proces .

Om forfatteren
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.
