Wystawianie Open Badges z WordPressa (bez ciężkiej wtyczki)
Wystawiaj Open Badges z dowolnej wtyczki kursu/LMS na WordPressie (LearnDash, LifterLMS, Tutor), wywołując API Badges Ninja po ukończeniu kursu — bez instalowania osobnej wtyczki do odznak.
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.
Jeśli prowadzisz kursy na WordPressie, znasz ten schemat: ktoś kończy moduł w LearnDash, LifterLMS albo Tutor LMS, LMS oznacza go jako “ukończone”, a potem… nic weryfikowalnego się nie dzieje. Może wysyłasz PDF-a mailem. Może instalujesz dedykowaną wtyczkę do odznak na WordPressie, która dodaje własne tabele w bazie danych, własną bibliotekę obrazów i własną definicję tego, czym jest “odznaka” — taką, której nikt poza twoją stroną nie może zweryfikować.
Jest prostsza droga. Wtyczki kursów na WordPressie już wyzwalają hook akcji w momencie, gdy ktoś kończy kurs. Możesz przechwycić ten hook i wykonać jedno wywołanie HTTP do API Badges Ninja. Bez dodatkowej wtyczki, bez dodatkowego hostingu, bez własnościowego formatu odznaki — po prostu zgodne ze standardem poświadczenie Open Badge v2.0, które twój odbiorca może zweryfikować wszędzie, dodać do LinkedIn i pobrać jako PDF.
Ten wpis pokazuje ten wzorzec raz, a potem konkretny hook dla LearnDash, LifterLMS i Tutor LMS.
Dlaczego nie po prostu użyć wtyczki do odznak na WordPressie?
Dedykowane wtyczki do odznak na WordPressie rozwiązują węższy problem, niż mogłoby się wydawać. Są dobre w renderowaniu obrazka na stronie “moje osiągnięcia” wewnątrz twojej witryny. Zazwyczaj są znacznie słabsze w rzeczach, które naprawdę mają znaczenie dla poświadczenia:
- Przenośność. Odznaka, która istnieje wyłącznie jako shortcode na twojej stronie WordPress, nie jest poświadczeniem — jest dekoracją. Gdy tylko odbiorca zmieni pracę, zmieni skrzynkę mailową albo twoja strona padnie, “dowód” znika razem z nią.
- Weryfikacja. Każdy powinien móc sprawdzić, że poświadczenie jest prawdziwe, bez logowania się do panelu administracyjnego twojego WordPressa. Open Badge v2.0 z założenia daje publiczny adres URL weryfikacji i czytelny maszynowo JSON-LD.
- Powierzchnia utrzymania. Każda wtyczka WordPress to jedna dodatkowa rzecz do łatania, jedna dodatkowa tabela w bazie do kopii zapasowej, jeden dodatkowy punkt awarii przy aktualizacji rdzenia.
Wywołanie zewnętrznego API po ukończeniu kursu omija wszystkie trzy problemy naraz. WordPress pozostaje odpowiedzialny za to, w czym jest dobry — dostarczanie treści i śledzenie postępów — a samo poświadczenie żyje w systemie zbudowanym specjalnie do jego wystawiania, weryfikowania i udostępniania.
Wzorzec: jeden hook, jedno wywołanie HTTP
Każda większa wtyczka LMS na WordPressie wyzwala akcję, gdy użytkownik kończy kurs. Integracja to zawsze te same trzy kroki:
- Podepnij się pod akcję ukończenia dla twojego konkretnego LMS-a.
- Znajdź (lub utwórz) tożsamość odbiorcy — zwykle po prostu jego e-mail konta WordPress i nazwa wyświetlana.
- Wywołaj
POST /awardsw API Badges Ninja za pomocąwp_remote_post(), przekazując ID odznaki i dane odbiorcy.
Najpierw potrzebujesz klucza API. Wygeneruj go w panelu w sekcji API Keys — pełny przewodnik znajdziesz w przewodniku po kluczach API. Klucze są pokazywane tylko raz, przy tworzeniu, więc zapisz go w wp-config.php jako stałą, a nie w bazie danych:
define( 'BADGES_NINJA_API_KEY', 'bws_your_32_hex_key_here' );
define( 'BADGES_NINJA_BADGE_ID', 'your-badge-id' );

Trzymaj ten klucz po stronie serwera. Wszystko w tym przewodniku działa w PHP na twoim serwerze WordPress — wp_remote_post() to wywołanie po stronie serwera, a wp-config.php nigdy nie jest wysyłany do przeglądarki. Dokładnie tego chcesz: klucz podróżuje serwer-do-serwera przez HTTPS, a żaden odwiedzający strony nie może go odczytać. Nigdy nie przenoś tego wywołania do JavaScriptu po stronie klienta — fetch() z przeglądarki z kluczem wpisanym na sztywno ujawniłby go każdemu przez narzędzia deweloperskie przeglądarki. Warto trzymać się dwóch nawyków: upewnij się, że twój hosting serwuje wp-config.php jako wykonywany PHP (nigdy jako zwykły tekst, i nie zostawiaj kopii wp-config.php.bak w katalogu głównym witryny), oraz utwórz dedykowany klucz API dla tej integracji, żebyś mógł go niezależnie unieważnić, gdyby kiedykolwiek został skompromitowany — bez psucia innych narzędzi.
Wspólna funkcja pomocnicza sprawia, że każdy hook LMS jest cienki:
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 );
}
E-mail odbiorcy jest haszowany po stronie serwera algorytmem SHA-256, gdy tylko dotrze do Badges Ninja, a zwracany payload zawiera adres URL weryfikacji nagrody — przydatne, jeśli chcesz pokazać link “zobacz swoje poświadczenie” od razu w WordPressie po udanym wywołaniu.
LearnDash
LearnDash wyzwala learndash_course_completed z jednym argumentem tablicowym zawierającym user i 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 );
} );
Przechowywanie ID odznaki jako meta kursu (zamiast jednej globalnej stałej BADGES_NINJA_BADGE_ID) to właściwa decyzja, gdy masz więcej niż jeden kurs — każdy kurs mapuje się na własny projekt odznaki.
LifterLMS
LifterLMS wyzwala lifterlms_course_completed z $user_id i $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 wyzwala tutor_course_complete_after z ID kursu, a bieżącego użytkownika pobierasz z sesji:
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 );
} );
Jeśli twoja konfiguracja Tutor LMS wyzwala ukończenie z procesu w tle (np. przez automatyczne ocenianie quizu), zamień get_current_user_id() na ID użytkownika, które dostarcza twój konkretny hook — sprawdź payload za pomocą error_log( print_r( func_get_args(), true ) ) raz podczas konfiguracji, żeby potwierdzić argumenty.
Projektowanie odznaki przed podpięciem hooka
Zanim cokolwiek z tego się wyzwoli, potrzebujesz odznaki do przyznania. Kreator wizualny obejmuje to bez potrzeby zatrudniania projektanta — ponad 80 szablonów kształtów, niestandardowe kolory, biblioteka ikon i wgrywanie logo, wszystko z przyciąganiem do siatki. Jeśli dopiero zaczynasz z kreatorem, Projektowanie pierwszego weryfikowalnego certyfikatu cyfrowego przeprowadzi cię przez wybór szablonu i dostarczenie czegoś, co odbiorcy naprawdę będą chcieli udostępnić.
Gdy odznaka już istnieje, pobierz jej ID z panelu (albo przez GET /badges) i wstaw je do pola niestandardowego kursu.
Co odbiorca faktycznie dostaje
To jest część, której domowej roboty wtyczka do odznak na WordPressie nie potrafi powtórzyć. Gdy POST /awards się powiedzie, odbiorca dostaje:
- Unikalny adres URL weryfikacji, który każdy może otworzyć — bez logowania do WordPressa — pokazujący, że poświadczenie jest prawdziwe, kto je wystawił i kiedy.
- Kod QR i certyfikat PDF w formacie A4, generowane automatycznie.
- Przycisk Add to LinkedIn Profile, jeśli twój wystawca ma ustawiony identyfikator organizacji LinkedIn — zobacz Jak dodać przycisk LinkedIn “Add to Profile” dla jednorazowej konfiguracji.
- Dostęp do własnego portalu odbiorcy pod adresem
badges.ninja/me, przez logowanie magicznym linkiem — żadnego hasła do zapamiętania, żadnego osobnego konta do zarządzania na twojej stronie WordPress. - Zgodny ze standardem Open Badge v2.0 JSON-LD, dzięki czemu każdy weryfikator znający OB (nie tylko Badges Ninja) może to zwalidować.
Nic z tego nie jest zadaniem WordPressa do zbudowania i nic z tego nie powinno żyć wyłącznie w twojej bazie danych WordPress.
Obsługa błędów w elegancki sposób
Hooki ukończenia kursu wyzwalają się podczas żywego żądania strony, a wolne lub nieudane wywołanie API nie powinno blokować ekranu “gratulacje” dla kursanta. Dwie praktyczne poprawki, gdy wychodzisz poza proof of concept:
Nie pozwól, by nieudana nagroda blokowała UI. Powyższa funkcja pomocnicza już loguje i zwraca false zamiast rzucać wyjątek — LearnDash, LifterLMS i Tutor kontynuują swój normalny przepływ ukończenia niezależnie od tego, co zwróci badges_ninja_issue_award().
Kolejkuj zamiast wywoływać synchronicznie, przy większej skali. Jeśli przepuszczasz duże grupy przez jeden kurs naraz (data startu kohorty, odblokowanie nagrania webinaru), wyzwól zaplanowane zdarzenie WP-Cron z hooka, zamiast wywoływać API synchronicznie:
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 );
To rozkłada obciążenie i sprawia, że jedno wolne żądanie nie staje się problemem kursanta. Dla naprawdę dużych partii (cała przeszła kohorta, migrowana za jednym razem) pomiń całkowicie ścieżkę hooka WordPress i użyj masowego przyznawania nagród przez CSV — wgraj raz, a platforma paginuje wystawianie po stronie serwera, z wbudowaną pauzą i wznowieniem.
Uwaga o idempotencji
Jeśli twój LMS kiedykolwiek wyzwoli swój hook ukończenia więcej niż raz dla tego samego użytkownika (częsty przypadek brzegowy w LearnDash przy ponownym podejściu do quizu, albo resynchronizacji w Tutor LMS), nie chcesz przyznać tej samej odznaki dwa razy. Najprostszym zabezpieczeniem jest flaga w meta użytkownika WordPress, ustawiana zaraz po udanym wywołaniu:
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 );
}
Jeśli wystawiasz przy prawdziwej skali i chcesz obsłużyć to centralnie zamiast per-witryna, zajrzyj do obsługi zdarzeń opartej na webhookach albo pełnego szybkiego startu API, gdzie znajdziesz kształty żądań i odpowiedzi dla każdego endpointu.
Kiedy ten wzorzec wyrasta poza pojedynczy kurs
Powyższe przykłady zakładają jedną odznakę na kurs. Gdy zaczynasz obsługiwać poświadczenia warstwowe — odznakę ścieżki, która odblokowuje się po kilku odznakach kursów, albo odznakę wieńczącą, zależną od wielu wymagań wstępnych — przenieś mapowanie “która odznaka za jakie ukończenie” z meta wpisu do małej tabeli lookup, albo napędzaj to automatyzacją opartą na arkuszu (Airtable albo Google Sheets), która wywołuje to samo wywołanie POST /awards. Samo wywołanie API się nie zmienia; zmienia się tylko to, co decyduje, kiedy je wykonać.
Rozwiązywanie problemów z integracją
Garść problemów odpowiada za większość tarcia, na jakie ludzie trafiają, konfigurując to po raz pierwszy:
Hook nigdy się nie wyzwala. Potwierdź, że podpinasz się pod właściwą akcję dla faktycznej wersji swojej wtyczki — LearnDash w szczególności zmieniał nazwy hooków ukończenia między głównymi wydaniami (starsze instalacje czasem wciąż polegają na learndash_course_completed wyzwalanym z innej ścieżki kodu niż nowsze). Dodaj tymczasowy error_log() na początku swojego callbacka i obserwuj wp-content/debug.log, kończąc testowy kurs jako jednorazowy użytkownik.
wp_remote_post() przekracza limit czasu. Środowiska hostingu współdzielonego czasem blokują wychodzące HTTPS do nieznanych hostów albo ograniczają limit czasu żądania poniżej ustawionych powyżej 15 sekund. Jeśli wywołania stale przekraczają limit czasu, sprawdź u swojego hostingodawcy, czy połączenia wychodzące do api.badges.ninja są dozwolone, i potwierdź, że twoje rozszerzenie PHP curl ma aktualne certyfikaty CA — przestarzały pakiet certyfikatów to częsta cicha awaria na starszych stackach hostingu współdzielonego.
400 Bad Request. W payloadzie brakuje wymaganego pola albo ma zły kształt. POST /awards oczekuje badgeId, zagnieżdżonego obiektu recipient z name i email oraz znacznika czasu issuedOn — powyższa funkcja pomocnicza wysyła dokładnie to. Najczęstszym potknięciem jest nazwa odbiorcy: musi mieć co najmniej 5 znaków, więc nazwa wyświetlana WordPressa jak “Jo” zostaje odrzucona. Gdy nazwa wyświetlana jest za krótka, użyj zamiast niej pełnego imienia i nazwiska z konta (albo części lokalnej adresu e-mail).
401 Unauthorized. Stała klucza API się nie ładuje albo klucz został wygenerowany ponownie po ustawieniu stałej. Klucze są pokazywane tylko raz przy tworzeniu i nie da się ich odzyskać — jeśli zgubiłeś rozeznanie, który klucz jest aktywny, usuń nieaktualny i wystaw nowy, zamiast zgadywać.
Odznaka przyznana, ale do niewłaściwego projektu odznaki. To niemal zawsze nieaktualna wartość meta wpisu badges_ninja_badge_id, pozostała po testach. Ponieważ mapowanie żyje na wpisie kursu, łatwo zapomnieć, że ją zmieniłeś po zduplikowaniu kursu dla nowej kohorty — warto to szybko sprawdzić za każdym razem, gdy klonujesz kurs.
Zdublowane nagrody dla tej samej osoby. Omówione powyżej przy zabezpieczeniu meta użytkownika, ale warto powtórzyć: hooki ukończenia LMS nie mają gwarancji, że wyzwolą się dokładnie raz. Traktuj “już przyznano” jako normalny przypadek do sprawdzenia, a nie przypadek brzegowy do zignorowania.
Najczęściej zadawane pytania
Czy to działa z pakietami kursów WooCommerce? Tak — jeśli zakup pakietu ma wyzwolić odznakę niezależnie od ukończenia kursu (np. odznaka “certyfikowany członek” dla każdego, kto kupi konkretny pakiet), podepnij się pod woocommerce_order_status_completed zamiast pod akcję ukończenia LMS, a ID odznaki pobierz z meta produktu, a nie kursu.
Czy odbiorcy mogą dostać odznakę bez konta WordPress? Tak, i o to właśnie chodzi. Nagroda jest powiązana z ich adresem e-mail w Badges Ninja, a nie z rekordem użytkownika WordPress. Jeśli twoja strona pozwala na zakup jako gość albo anonimowe ukończenie quizu, po prostu upewnij się, że przechwytujesz prawdziwy adres e-mail do przekazania do badges_ninja_issue_award().
A jeśli chcę przeglądać nagrody, zanim zostaną wysłane? Pomiń bezpośrednie wywoływanie z hooka ukończenia. Zamiast tego zapisz oczekującą nagrodę (użytkownik, kurs, znacznik czasu) w niestandardowej tabeli albo typie wpisu, i wystaw ją z zaplanowanego zadania albo przycisku admina “Zatwierdź i przyznaj”, który na żądanie wywołuje tę samą funkcję pomocniczą.
Czy potrzebuję osobnej odznaki na każdy kurs, czy jedna może obejmować kilka? Oba podejścia działają. Niektórzy wystawcy tworzą jedną odznakę na kurs dla granularności; inni tworzą pojedynczą odznakę “ukończenie programu” i przyznają ją dopiero po ukończeniu wszystkich wymaganych kursów, sprawdzając ukończenie wymagań wstępnych wewnątrz hooka przed wywołaniem API.
Gotowy, by wystawić swoje pierwsze poświadczenie z możliwością weryfikacji? Zacznij za darmo na badges.ninja — kreator wizualny, publiczna strona weryfikacyjna, certyfikat PDF, format Open Badge v2.0. Bez karty kredytowej.
Jak powstał ten artykuł
Niektóre wpisy na tym blogu powstają z pomocą asystenta AI, a następnie są sprawdzane, weryfikowane merytorycznie i redagowane przez zespół Badges Ninja przed publikacją. Każdy przykład kodu i cena są weryfikowane względem działającego produktu. Więcej o naszym procesie redakcyjnym i wykorzystaniu AI przeczytasz na naszej stronie procesu redakcyjnego .

O autorze
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.
