Видача Open Badges з WordPress (без важкого плагіна)

Видавайте Open Badges з будь-якого плагіна курсів/LMS на WordPress (LearnDash, LifterLMS, Tutor), викликаючи API Badges Ninja після завершення курсу — без встановлення окремого плагіна значків.

Nacho Coll Автор Оновлено 11 хв читання
Видавайте Open Badges з будь-якого плагіна курсів/LMS на WordPress (LearnDash, LifterLMS, Tutor), викликаючи API Badges Ninja після завершення курсу — без встановлення окремого плагіна значків.

Якщо ви ведете курси на WordPress, ви вже знаєте цей сценарій: хтось завершує модуль у LearnDash, LifterLMS чи Tutor LMS, LMS позначає це як «завершено», а далі… нічого верифікованого не відбувається. Може, ви надсилаєте PDF поштою. Може, встановлюєте окремий плагін значків для WordPress, який додає власні таблиці бази даних, власну бібліотеку зображень і власне уявлення про те, що таке «значок» — таке, яке ніхто поза вашим сайтом не може перевірити.

Є простіший шлях. Плагіни курсів WordPress уже викликають хук дії в момент, коли хтось завершує курс. Ви можете перехопити цей хук і зробити один HTTP-виклик до API Badges Ninja. Без додаткового плагіна, без додаткового хостингу, без пропрієтарного формату значка — просто поєднане зі стандартом поширення Open Badge v2.0, яке ваш одержувач може перевірити будь-де, додати до LinkedIn і завантажити як PDF.

Цей допис пояснює цей шаблон один раз, а потім показує конкретний хук для LearnDash, LifterLMS і Tutor LMS.

Чому б просто не використати плагін значків для WordPress?

Спеціалізовані плагіни значків для WordPress вирішують вужчу проблему, ніж здається на перший погляд. Вони добре відображають зображення на сторінці «мої досягнення» всередині вашого сайту. Зазвичай вони набагато слабші в речах, які насправді важливі для поширення:

  • Портативність. Значок, який існує лише як шорткод на вашому сайті WordPress, — це не поширення, а декорація. Щойно одержувач змінить роботу, змінить поштову скриньку, або ваш сайт впаде — «доказ» зникає разом із ним.
  • Верифікація. Будь-хто повинен мати змогу перевірити, що поширення справжнє, без входу в адмінпанель вашого WordPress. Open Badge v2.0 за задумом дає публічну URL-адресу верифікації та машиночитний JSON-LD.
  • Поверхня обслуговування. Кожен плагін WordPress — це ще одна річ для патчів, ще одна таблиця бази даних для резервного копіювання, ще одна точка відмови під час оновлення ядра.

Виклик зовнішнього API після завершення курсу обходить усі три проблеми одразу. WordPress залишається відповідальним за те, в чому він хороший — доставку контенту та відстеження прогресу, — а саме поширення живе в системі, побудованій спеціально для його видачі, верифікації та поширення.

Шаблон: один хук, один HTTP-виклик

Кожен великий плагін LMS для WordPress викликає дію, коли користувач завершує курс. Інтеграція завжди складається з тих самих трьох кроків:

  1. Підключіться до дії завершення для вашого конкретного LMS.
  2. Знайдіть (або створіть) особу одержувача — зазвичай просто його email облікового запису WordPress та ім’я, що відображається.
  3. Викличте POST /awards в API Badges Ninja за допомогою wp_remote_post(), передаючи ID значка та дані одержувача.

Спочатку вам потрібен ключ API. Згенеруйте його у своїй панелі в розділі API Keys — повний огляд див. у гайді з ключів API. Ключі показуються лише один раз при створенні, тож зберігайте його в wp-config.php як константу, а не в базі даних:

define( 'BADGES_NINJA_API_KEY', 'bws_your_32_hex_key_here' );
define( 'BADGES_NINJA_BADGE_ID', 'your-badge-id' );

Newly created key revealed once

Тримайте цей ключ на стороні сервера. Усе в цьому гайді виконується в PHP на вашому сервері WordPress — wp_remote_post() це серверний виклик, а wp-config.php ніколи не надсилається в браузер. Це саме те, що вам потрібно: ключ подорожує сервер-до-сервера через HTTPS, і жоден відвідувач сайту не може його прочитати. Ніколи не переносьте цей виклик у клієнтський JavaScript — fetch() з браузера з вбудованим ключем відкрив би його будь-кому через інструменти розробника браузера. Варто дотримуватися двох звичок: переконайтеся, що ваш хостинг подає wp-config.php як виконуваний PHP (ніколи як звичайний текст, і не залишайте копію wp-config.php.bak в кореневій директорії сайту), та створіть окремий ключ API для цієї інтеграції, щоб мати змогу відкликати його незалежно, якщо його коли-небудь скомпрометують — без порушення роботи інших ваших інструментів.

Спільна допоміжна функція робить кожен хук LMS тонким:

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 );
}

Email одержувача хешується за алгоритмом SHA-256 на стороні сервера, щойно він потрапляє в Badges Ninja, а відповідь містить URL-адресу верифікації нагороди — зручно, якщо ви хочете показати посилання «переглянути своє поширення» прямо в WordPress після успішного виклику.

LearnDash

LearnDash викликає learndash_course_completed з одним аргументом-масивом, що містить user і 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 );
} );

Зберігання ID значка як метаданих курсу (замість однієї глобальної константи BADGES_NINJA_BADGE_ID) — правильне рішення, щойно у вас більше одного курсу — кожен курс відповідає власному дизайну значка.

LifterLMS

LifterLMS викликає lifterlms_course_completed з $user_id і $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 викликає tutor_course_complete_after з ID курсу, а поточного користувача ви отримуєте з сесії:

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 );
} );

Якщо ваше налаштування Tutor LMS викликає завершення з фонового процесу (наприклад, через автоматичне оцінювання тесту), замініть get_current_user_id() на ID користувача, який надає ваш конкретний хук — перевірте payload за допомогою error_log( print_r( func_get_args(), true ) ) один раз під час налаштування, щоб підтвердити аргументи.

Проєктування значка перед підключенням хука

Перш ніж усе це спрацює, вам потрібен значок для нагородження. Візуальний конструктор охоплює це без потреби мати дизайнера в штаті — понад 80 шаблонів форм, власні кольори, бібліотека іконок і завантаження логотипа, усе з прив’язкою до сітки. Якщо ви новачок у конструкторі, Проєктування вашого першого верифікованого цифрового сертифіката проведе вас через вибір шаблону і створення того, чим одержувачі справді захочуть поділитися.

Коли значок уже існує, візьміть його ID з панелі (або через GET /badges) і вставте в поле користувацького поля курсу.

Що насправді отримує одержувач

Це та частина, яку саморобний плагін значків для WordPress відтворити не може. Коли POST /awards успішний, одержувач отримує:

  • Унікальну URL-адресу верифікації, яку будь-хто може відкрити — без входу в WordPress — що показує, що поширення справжнє, хто його видав і коли.
  • QR-код і PDF-сертифікат формату A4, згенеровані автоматично.
  • Кнопку Add to LinkedIn Profile, якщо ваш емітент має встановлений ID організації LinkedIn — див. Додавання кнопки LinkedIn «Add to Profile» для одноразового налаштування.
  • Доступ до власного порталу одержувача за адресою badges.ninja/me, через вхід за magic-link — жодного пароля, який треба пам’ятати, жодного окремого облікового запису для керування на вашому сайті WordPress.
  • Поєднаний зі стандартом Open Badge v2.0 JSON-LD, тож будь-який верифікатор, що підтримує OB (не лише Badges Ninja), може його перевірити.

Жодну з цих речей WordPress не зобов’язаний створювати, і жодна з них не повинна жити лише у вашій базі даних WordPress.

Витончена обробка помилок

Хуки завершення курсу викликаються під час живого запиту сторінки, і повільний або невдалий виклик API не повинен блокувати екран «вітаємо» для того, хто навчається. Два практичні налаштування, коли ви виходите за межі proof of concept:

Не дозволяйте невдалій нагороді блокувати UI. Наведена вище допоміжна функція вже логує і повертає false замість того, щоб кидати виняток — LearnDash, LifterLMS і Tutor продовжують свій звичайний потік завершення незалежно від того, що повертає badges_ninja_issue_award().

Ставте в чергу замість викликів inline, у великому масштабі. Якщо ви проводите великі когорти через один курс одночасно (дата старту когорти, розблокування запису вебінару), викликайте заплановану подію WP-Cron з хука замість синхронного виклику API:

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 );

Це розподіляє навантаження і не дає одному повільному запиту стати проблемою для того, хто навчається. Для справді великих партій (ціла минула когорта, мігрована за один раз) повністю пропустіть шлях хука WordPress і використайте масові нагороди через CSV — завантажте один раз, і платформа пагінує видачу на стороні сервера, з вбудованою паузою й відновленням.

Примітка про ідемпотентність

Якщо ваш LMS коли-небудь викличе свій хук завершення більше одного разу для того самого користувача (поширений крайовий випадок у LearnDash з повторними спробами тесту, або повторна синхронізація в Tutor LMS), ви не хочете нагороджувати тим самим значком двічі. Найпростіший захист — прапорець у метаданих користувача WordPress, який ви встановлюєте одразу після успішного виклику:

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 );
}

Якщо ви видаєте значки в реальному масштабі і хочете обробляти це централізовано, а не на кожному сайті окремо, погляньте на обробку подій на основі вебхуків або повний швидкий старт API для форм запитів і відповідей для кожного ендпоінту.

Коли цей шаблон переростає один курс

Наведені вище приклади припускають один значок на курс. Щойно ви почнете керувати ступінчастими поширеннями — значок треку, який розблоковується після кількох значків курсів, або підсумковий значок, що залежить від кількох передумов, — перенесіть мапінг «який значок за яке завершення» з метаданих запису в невелику таблицю пошуку, або керуйте ним через автоматизацію на основі таблиці (Airtable чи Google Sheets), яка викликає той самий виклик POST /awards. Сам виклик API не змінюється; змінюється лише те, що вирішує, коли його робити.

Усунення несправностей інтеграції

Кілька проблем становлять більшість труднощів, з якими люди стикаються, налаштовуючи це вперше:

Хук ніколи не спрацьовує. Переконайтеся, що ви підключаєтесь до правильної дії для фактичної версії вашого плагіна — LearnDash, зокрема, змінював назви хуків завершення між основними релізами (старіші інсталяції іноді все ще покладаються на те, що learndash_course_completed викликається з іншого шляху коду, ніж у новіших). Додайте тимчасовий error_log() на початку вашого коллбека і спостерігайте за wp-content/debug.log, завершуючи тестовий курс як одноразовий користувач.

wp_remote_post() перевищує час очікування. Середовища спільного хостингу іноді блокують вихідний HTTPS до незнайомих хостів або обмежують час очікування запиту нижче встановлених вище 15 секунд. Якщо виклики постійно перевищують час очікування, перевірте у свого хостинг-провайдера, чи дозволені вихідні з’єднання до api.badges.ninja, і підтвердьте, що ваше розширення PHP curl має актуальні CA-сертифікати — застарілий пакет сертифікатів є поширеною тихою відмовою на старіших стеках спільного хостингу.

400 Bad Request. У payload відсутнє обов’язкове поле або він має неправильну форму. POST /awards очікує badgeId, вкладений об’єкт recipient з name і email, та часову мітку issuedOn — наведена вище допоміжна функція надсилає саме це. Найпоширеніша причина помилки — ім’я одержувача: воно має містити щонайменше 5 символів, тож ім’я, що відображається у WordPress, наприклад «Jo», буде відхилено. Використовуйте повне ім’я облікового запису (або локальну частину email) як запасний варіант, коли ім’я, що відображається, закоротке.

401 Unauthorized. Константа ключа API не завантажується, або її було згенеровано повторно після встановлення константи. Ключі показуються лише один раз при створенні і не можуть бути отримані знову — якщо ви втратили відстеження того, який ключ активний, видаліть застарілий і видайте новий, замість того щоб гадати.

Значок видано, але до неправильного дизайну значка. Це майже завжди застаріле значення метаданих запису badges_ninja_badge_id, що залишилося після тестування. Оскільки мапінг живе в записі курсу, легко забути, що ви його змінили після дублювання курсу для нової когорти — варто швидко перевіряти це щоразу, коли клонуєте курс.

Дубльовані нагороди для однієї й тієї самої особи. Розглянуто вище із захистом на метаданих користувача, але варто повторити: хуки завершення LMS не гарантовано спрацьовують рівно один раз. Ставтеся до «вже нагороджено» як до звичайного випадку для перевірки, а не крайового випадку, який можна ігнорувати.

Часті запитання

Чи працює це з пакетами курсів WooCommerce? Так — якщо покупка пакета має спричиняти видачу значка незалежно від завершення курсу (наприклад, значок «сертифікований учасник» для будь-кого, хто купує конкретний пакет), підключіться до woocommerce_order_status_completed замість дії завершення LMS, і беріть ID значка з метаданих товару, а не курсу.

Чи можуть одержувачі отримати значок без облікового запису WordPress? Так, і в цьому вся суть. Нагорода прив’язана до їхньої email-адреси в Badges Ninja, а не до запису користувача WordPress. Якщо ваш сайт дозволяє оформлення замовлення як гість або анонімне проходження тесту, просто переконайтеся, що ви фіксуєте справжню email-адресу для передачі в badges_ninja_issue_award().

А якщо я хочу переглядати нагороди перед відправленням? Пропустіть прямий виклик з хука завершення. Замість цього запишіть очікувану нагороду (користувач, курс, часова мітка) в користувацьку таблицю чи тип запису, і видайте її із запланованого завдання або адміністративної кнопки «Затвердити й нагородити», яка за запитом викликає ту саму допоміжну функцію.

Чи потрібен мені окремий значок для кожного курсу, чи один може охоплювати кілька? Обидва варіанти працюють. Деякі емітенти створюють один значок на курс для деталізації; інші створюють єдиний значок «завершення програми» і видають його лише після завершення всіх обов’язкових курсів, перевіряючи завершення передумов усередині хука перед викликом API.


Готові видати своє перше верифіковане поширення? Почніть безкоштовно на badges.ninja — візуальний конструктор, публічна сторінка верифікації, PDF-сертифікат, вивід Open Badge v2.0. Без кредитної картки.

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.

Назад до Блогу

Схожі статті