WordPress'ten Open Badges Düzenleme (Ağır Bir Eklenti Olmadan)

Tamamlanma anında Badges Ninja API'sini çağırarak herhangi bir WordPress kurs/LMS eklentisinden (LearnDash, LifterLMS, Tutor) Open Badges düzenleyin — ayrı bir rozet eklentisi kurmaya gerek yok.

Nacho Coll Yazan Güncellendi 11 dk okuma
Tamamlanma anında Badges Ninja API'sini çağırarak herhangi bir WordPress kurs/LMS eklentisinden (LearnDash, LifterLMS, Tutor) Open Badges düzenleyin — ayrı bir rozet eklentisi kurmaya gerek yok.

WordPress’te kurslar yürütüyorsanız, bu senaryoyu zaten biliyorsunuzdur: birisi LearnDash, LifterLMS veya Tutor LMS’de bir modülü bitirir, LMS bunu “tamamlandı” olarak işaretler ve ardından… doğrulanabilir hiçbir şey olmaz. Belki bir PDF e-postalarsınız. Belki kendi veritabanı tablolarını, kendi görsel kütüphanesini ve bir “rozet”in ne olduğuna dair kendi görüşünü ekleyen özel bir WordPress rozet eklentisi kurarsınız — sitenizin dışındaki hiç kimsenin doğrulayamayacağı bir görüş.

Daha basit bir yol var. WordPress kurs eklentileri, birisi bir kursu tamamladığı anda zaten bir action hook tetikler. Bu hook’u yakalayıp Badges Ninja API’sine tek bir HTTP çağrısı yapabilirsiniz. Ekstra eklenti yok, ekstra barındırma yok, tescilli bir rozet formatı yok — sadece alıcınızın her yerde doğrulayabileceği, LinkedIn’e ekleyebileceği ve PDF olarak indirebileceği, standartlara uygun bir Open Badge v2.0 credential’ı.

Bu yazı önce deseni bir kez baştan sona anlatıyor, ardından LearnDash, LifterLMS ve Tutor LMS için özel hook’u gösteriyor.

Neden sadece bir WordPress rozet eklentisi kullanmayalım?

Özel WordPress rozet eklentileri, çözüyor gibi göründüklerinden daha dar bir sorunu çözer. Sitenizdeki bir “başarılarım” sayfasında bir görsel render etmekte iyidirler. Bir credential için gerçekten önemli olan konularda ise genellikle çok daha zayıftırlar:

  • Taşınabilirlik. Yalnızca WordPress sitenizde bir shortcode olarak var olan bir rozet, bir credential değildir — bir dekorasyondur. Alıcı iş değiştirdiği, gelen kutusunu değiştirdiği veya siteniz çöktüğü anda “kanıt” da onunla birlikte gider.
  • Doğrulama. Herkes, WordPress yönetici paneline giriş yapmadan bir credential’ın gerçek olduğunu kontrol edebilmelidir. Open Badge v2.0, tasarımı gereği size herkese açık bir doğrulama URL’si ve makine tarafından okunabilir JSON-LD sağlar.
  • Bakım yüzeyi. Her WordPress eklentisi, yamalanması gereken bir şey daha, yedeklenmesi gereken bir veritabanı tablosu daha, bir çekirdek güncellemesi sırasında bir arıza noktası daha demektir.

Kurs tamamlandığında harici bir API çağırmak bu üç sorunun da önüne geçer. WordPress, iyi olduğu şeyden — içerik sunumu ve ilerleme takibinden — sorumlu kalır ve credential’ın kendisi, onu düzenlemek, doğrulamak ve paylaşmak için özel olarak inşa edilmiş bir sistemde yaşar.

Desen: bir hook, bir HTTP çağrısı

Her büyük WordPress LMS eklentisi, bir kullanıcı bir kursu tamamladığında bir action tetikler. Entegrasyon her zaman aynı üç adımdan oluşur:

  1. Kendi LMS’iniz için tamamlanma action’ına bağlanın.
  2. Alıcının kimliğini bulun (veya oluşturun) — genellikle sadece WordPress hesabının e-postası ve görünen adı.
  3. Rozet ID’sini ve alıcı bilgilerini geçirerek Badges Ninja API’sinde wp_remote_post() ile POST /awards’ı çağırın.

Önce bir API anahtarına ihtiyacınız olacak. Panelinizde API Keys altında bir tane oluşturun — tam anlatım için API anahtarları rehberine bakın. Anahtarlar oluşturulduğunda yalnızca bir kez gösterilir, bu yüzden onu veritabanında değil wp-config.php içinde bir sabit olarak saklayın:

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

Yeni oluşturulan anahtar bir kez gösteriliyor

Bu anahtarı sunucu tarafında tutun. Bu rehberdeki her şey WordPress sunucunuzda PHP üzerinde çalışır — wp_remote_post() sunucu tarafı bir çağrıdır ve wp-config.php hiçbir zaman tarayıcıya gönderilmez. İstediğiniz tam olarak da budur: anahtar HTTPS üzerinden sunucudan sunucuya seyahat eder ve hiçbir ziyaretçi onu okuyamaz. Bu çağrıyı asla istemci tarafı JavaScript’e taşımayın — anahtarı satır içine gömülmüş bir tarayıcı fetch() çağrısı, onu tarayıcının geliştirici araçları üzerinden herkese açık hale getirir. Sürdürmeye değer iki alışkanlık: barındırıcınızın wp-config.php’yi çalıştırılmış PHP olarak sunduğundan emin olun (asla düz metin olarak değil ve web kökünde bir wp-config.php.bak kopyası bırakmayın) ve bu entegrasyon için özel bir API anahtarı oluşturun, böylece herhangi bir şekilde ele geçirilirse diğer araçlarınızı bozmadan onu bağımsız olarak iptal edebilirsiniz.

Paylaşılan bir yardımcı fonksiyon, her LMS hook’unu ince tutar:

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

Alıcının e-postası, Badges Ninja’ya ulaştığında sunucu tarafında bir kez SHA-256 ile hashlenir ve dönen yanıt, ödülün doğrulama URL’sini içerir — çağrı başarılı olduktan sonra WordPress içinde tam orada bir “credential’ınızı görüntüleyin” bağlantısı göstermek isterseniz kullanışlıdır.

LearnDash

LearnDash, user ve course içeren tek bir dizi argümanıyla learndash_course_completed’i tetikler:

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

Rozet ID’sini tek bir küresel BADGES_NINJA_BADGE_ID sabiti yerine kurs meta verisi olarak saklamak, birden fazla kursunuz olduğunda doğru tercihtir — her kurs kendi rozet tasarımına karşılık gelir.

LifterLMS

LifterLMS, $user_id ve $course_id ile lifterlms_course_completed’i tetikler:

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, kurs ID’si ile tutor_course_complete_after’ı tetikler ve mevcut kullanıcıyı oturumdan çekersiniz:

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 kurulumunuz tamamlanmayı bir arka plan sürecinden (örneğin bir sınav otomatik değerlendirmesi üzerinden) tetikliyorsa, get_current_user_id()’yi kendi özel hook’unuzun sağladığı kullanıcı ID’siyle değiştirin — argümanları doğrulamak için kurulum sırasında bir kez error_log( print_r( func_get_args(), true ) ) ile payload’ı kontrol edin.

Hook’u bağlamadan önce rozeti tasarlamak

Bunların hiçbiri tetiklenmeden önce, ödüllendirecek bir rozete ihtiyacınız var. Görsel tasarımcı, kadroda bir tasarımcı bulundurmaya gerek kalmadan bunu kapsar — 80’den fazla şekil şablonu, özel renkler, ikon kütüphanesi ve logo yükleme, hepsi ızgaraya hizalanır. Tasarımcıda yeniyseniz, İlk Doğrulanabilir Dijital Sertifikanızı Tasarlamak bir şablon seçme ve alıcıların gerçekten paylaşmak isteyeceği bir şey sunma konusunda size yol gösterir.

Rozet oluşturulduktan sonra, ID’sini panelden (veya GET /badges üzerinden) alın ve kursunuzun özel alanına yerleştirin.

Alıcının gerçekte aldığı şey

İşte ev yapımı bir WordPress rozet eklentisinin taklit edemeyeceği kısım burası. POST /awards başarılı olduğunda, alıcı şunları alır:

  • Herkesin açabileceği benzersiz bir doğrulama URL’si — WordPress girişi gerekmez — credential’ın gerçek olduğunu, kimin ve ne zaman düzenlediğini gösterir.
  • Otomatik olarak oluşturulan bir QR kodu ve A4 PDF sertifika.
  • Düzenleyicinizin bir LinkedIn organizasyon ID’si ayarlanmışsa bir LinkedIn Profiline Ekle düğmesi — tek seferlik kurulum için LinkedIn “Profile Ekle” Düğmesi Ekleme yazısına bakın.
  • Magic-link ile giriş üzerinden badges.ninja/me adresindeki kendi alıcı portalına erişim — unutulacak bir parola yok, WordPress sitenizde yönetilecek ayrı bir hesap yok.
  • Standartlara uygun Open Badge v2.0 JSON-LD, böylece OB’yi tanıyan herhangi bir doğrulayıcı (sadece Badges Ninja değil) onu doğrulayabilir.

Bunların hiçbiri WordPress’in inşa etmesi gereken bir şey değildir ve hiçbiri yalnızca WordPress veritabanınızda yaşamamalıdır.

Hataları zarifçe ele almak

Kurs tamamlama hook’ları canlı bir sayfa isteği sırasında tetiklenir ve yavaş veya başarısız bir API çağrısı öğrencinin “tebrikler” ekranını engellememelidir. Bir kanıt konseptinin ötesine geçtiğinizde iki pratik ayarlama:

Başarısız bir ödülün arayüzü engellemesine izin vermeyin. Yukarıdaki yardımcı fonksiyon zaten bir istisna fırlatmak yerine loglar ve false döndürür — LearnDash, LifterLMS ve Tutor, badges_ninja_issue_award()’ın ne döndürdüğüne bakılmaksızın normal tamamlama akışlarına devam eder.

Ölçekte, satır içi çağırmak yerine kuyruğa alın. Tek bir kurs üzerinden aynı anda büyük kohortlar geçiriyorsanız (bir kohort başlangıç tarihi, bir webinar tekrarının kilidinin açılması), API’yi eşzamanlı olarak çağırmak yerine hook’tan bir WP-Cron zamanlanmış olayı tetikleyin:

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

Bu, yükü yayar ve tek bir yavaş isteğin öğrencinin sorunu haline gelmesini önler. Gerçek anlamda büyük gruplar için (bir kerede taşınan bütün bir geçmiş kohort), WordPress hook yolunu tamamen atlayın ve CSV üzerinden toplu ödüller kullanın — bir kez yükleyin, platform düzenlemeyi sunucu tarafında, yerleşik duraklat/devam ettir özelliğiyle sayfalar.

İdempotanslık üzerine bir not

LMS’iniz tamamlanma hook’unu aynı kullanıcı için birden fazla tetiklerse (sınav tekrarlarıyla yaygın bir LearnDash uç durumu veya bir Tutor LMS yeniden senkronizasyonu), aynı rozeti iki kez ödüllendirmek istemezsiniz. En basit koruma, başarılı bir çağrının hemen ardından ayarladığınız bir WordPress user-meta bayrağıdır:

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

Gerçek hacimde düzenliyorsanız ve bunun site başına değil merkezi olarak ele alınmasını istiyorsanız, webhook tabanlı olay işlemeye veya her endpoint için istek/yanıt biçimleri için tam API hızlı başlangıcına göz atın.

Bu desen tek bir kursu aştığında

Yukarıdaki örnekler kurs başına bir rozet varsayar. İstiflenebilir credential’lar çalıştırmaya başladığınızda — birkaç kurs rozetinden sonra kilidi açılan bir parkur rozeti veya birden fazla ön koşula bağlı bir taçlandırma rozeti — “hangi rozet, hangi tamamlanma için” eşlemesini post meta’dan küçük bir arama tablosuna taşıyın veya aynı POST /awards çağrısını tetikleyen bir e-tablo tabanlı otomasyondan (Airtable veya Google Sheets) yönlendirin. API çağrısının kendisi değişmez; sadece onu ne zaman yapacağına karar veren şey değişir.

Entegrasyonu sorun giderme

Bunu ilk kez kurarken insanların karşılaştığı sürtünmenin çoğu bir avuç soruna dayanır:

Hook hiç tetiklenmiyor. Eklentinizin gerçek sürümü için doğru action’a bağlandığınızı doğrulayın — özellikle LearnDash, büyük sürümler arasında tamamlanma hook adlarını değiştirdi (daha eski kurulumlar bazen learndash_course_completed’in daha yeni olanlardan farklı bir kod yolundan tetiklenmesine hâlâ güveniyor). Callback’inizin en üstüne geçici bir error_log() ekleyin ve tek kullanımlık bir test kullanıcısı olarak bir test kursunu tamamlarken wp-content/debug.log’u izleyin.

wp_remote_post() zaman aşımına uğruyor. Paylaşımlı barındırma ortamları bazen tanınmayan hostlara giden HTTPS trafiğini engeller veya istek zaman aşımlarını yukarıda ayarlanan 15 saniyenin altına sınırlar. Çağrılar sürekli zaman aşımına uğruyorsa, barındırıcınıza api.badges.ninja’ya giden bağlantılara izin verilip verilmediğini sorun ve PHP curl uzantınızın güncel CA sertifikalarına sahip olduğunu doğrulayın — güncel olmayan bir sertifika paketi, eski paylaşımlı barındırma yığınlarında yaygın, sessiz bir arızadır.

400 Bad Request. Payload’da gerekli bir alan eksik veya yanlış bir şekle sahip. POST /awards, badgeId, name ve email içeren iç içe bir recipient nesnesi ve bir issuedOn zaman damgası bekler — yukarıdaki yardımcı fonksiyon tam olarak bunu gönderir. En yaygın takılma noktası alıcının adıdır: en az 5 karakter olması gerekir, bu yüzden “Jo” gibi bir WordPress görünen adı reddedilir. Görünen ad çok kısa olduğunda hesabın tam adına (veya e-postanın yerel kısmına) geri dönün.

401 Unauthorized. API anahtarı sabiti yüklenmiyor veya sabit ayarlandıktan sonra yeniden oluşturuldu. Anahtarlar oluşturulduğunda yalnızca bir kez gösterilir ve tekrar alınamaz — hangi anahtarın aktif olduğunu takip edemediyseniz, tahmin etmek yerine eskisini silin ve yeni bir tane düzenleyin.

Rozet düzenlendi ama yanlış rozet tasarımıyla. Bu neredeyse her zaman testten kalan eski bir badges_ninja_badge_id post-meta değeridir. Eşleme kurs gönderisinde yaşadığından, yeni bir kohort için bir kursu çoğalttıktan sonra onu değiştirdiğinizi unutmak kolaydır — bir kursu her klonladığınızda hızlı bir kontrol yapmaya değer.

Aynı kişi için tekrarlanan ödüller. Yukarıda user-meta koruması ile ele alındı, ancak tekrarlamaya değer: LMS tamamlama hook’larının tam olarak bir kez tetikleneceği garanti edilmez. “Zaten ödüllendirildi”ni göz ardı edilecek bir uç durum değil, kontrol edilecek normal bir durum olarak ele alın.

Sık sorulan sorular

Bu, WooCommerce kurs paketleriyle çalışır mı? Evet — eğer bir paket satın alımının kurs tamamlanmasından bağımsız olarak bir rozeti tetiklemesi gerekiyorsa (örneğin belirli bir paketi satın alan herkes için bir “sertifikalı üye” rozeti), bir LMS tamamlama action’ı yerine woocommerce_order_status_completed’e bağlanın ve rozet ID’sini bir kurs yerine ürün meta verisinden arayın.

Alıcılar rozeti bir WordPress hesabı olmadan alabilir mi? Evet ve amaç da bu. Ödül, Badges Ninja’da bir WordPress kullanıcı kaydına değil, e-posta adreslerine bağlıdır. Siteniz misafir olarak ödeme veya anonim sınav tamamlamaya izin veriyorsa, badges_ninja_issue_award()’a geçirmek üzere gerçek bir e-posta adresi yakaladığınızdan emin olun.

Ödülleri dışarı çıkmadan önce incelemek istersem ne olur? Çağrıyı doğrudan tamamlama hook’undan tetiklemeyin. Bunun yerine, bekleyen ödülü (kullanıcı, kurs, zaman damgası) özel bir tabloya veya post türüne yazın ve talep üzerine aynı yardımcı fonksiyonu çağıran zamanlanmış bir görevden veya bir yönetici “Onayla ve Ödüllendir” düğmesinden düzenleyin.

Kurs başına ayrı bir rozete mi ihtiyacım var, yoksa bir rozet birkaçını kapsayabilir mi? İkisi de işe yarar. Bazı düzenleyiciler ayrıntı için kurs başına bir rozet oluşturur; diğerleri tek bir “program tamamlandı” rozeti oluşturur ve API’yi çağırmadan önce hook içinde ön koşul tamamlanmasını kontrol ederek yalnızca gerekli her kurs bittiğinde ödüllendirir.


İlk doğrulanabilir credential’ınızı düzenlemeye hazır mısınız? badges.ninja’da ücretsiz başlayın — görsel tasarımcı, herkese açık doğrulama sayfası, PDF sertifika, Open Badge v2.0 çıktısı. Kredi kartı gerekmez.

Nacho Coll

Yazar hakkında

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.

Blog'a Dön

İlgili Yazılar