Emitindo Open Badges a partir do WordPress (sem um plugin pesado)
Emita Open Badges a partir de qualquer plugin de curso/LMS do WordPress (LearnDash, LifterLMS, Tutor) chamando a API do Badges Ninja na conclusão — sem instalar um plugin de emblemas separado.
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.
Se você gerencia cursos no WordPress, já conhece a rotina: alguém termina um módulo no LearnDash, LifterLMS ou Tutor LMS, o LMS marca como “concluído” e então… nada verificável acontece. Talvez você envie um PDF por e-mail. Talvez você instale um plugin de emblemas dedicado para WordPress que adiciona suas próprias tabelas de banco de dados, sua própria biblioteca de imagens e sua própria ideia do que é um “emblema” — uma que ninguém fora do seu site consegue verificar.
Existe um caminho mais simples. Os plugins de curso do WordPress já disparam um action hook no momento em que alguém conclui um curso. Você pode capturar esse hook e fazer uma única chamada HTTP para a API do Badges Ninja. Sem plugin extra, sem hospedagem extra, sem formato de emblema proprietário — apenas uma credencial Open Badge v2.0 compatível com o padrão que seu destinatário pode verificar em qualquer lugar, adicionar ao LinkedIn e baixar como PDF.
Este post percorre o padrão uma vez e depois mostra o hook específico para LearnDash, LifterLMS e Tutor LMS.
Por que não usar simplesmente um plugin de emblemas do WordPress?
Os plugins de emblemas dedicados para WordPress resolvem um problema mais restrito do que parecem resolver. Eles são bons em renderizar uma imagem em uma página de “minhas conquistas” dentro do seu site. Costumam ser bem mais fracos nas coisas que realmente importam para uma credencial:
- Portabilidade. Um emblema que só existe como um shortcode no seu site WordPress não é uma credencial — é uma decoração. No momento em que o destinatário muda de emprego, muda de caixa de entrada, ou seu site sai do ar, a “prova” some junto.
- Verificação. Qualquer pessoa deveria conseguir checar que uma credencial é real sem fazer login no seu admin do WordPress. O Open Badge v2.0 oferece, por design, uma URL de verificação pública e JSON-LD legível por máquina.
- Superfície de manutenção. Cada plugin do WordPress é mais uma coisa para corrigir, mais uma tabela de banco de dados para fazer backup, mais um ponto de falha durante uma atualização do core.
Chamar uma API externa na conclusão do curso resolve os três problemas de uma vez. O WordPress continua responsável pelo que faz bem — entrega de conteúdo e acompanhamento de progresso — e a credencial em si vive em um sistema construído especificamente para emiti-la, verificá-la e compartilhá-la.
O padrão: um hook, uma chamada HTTP
Todo plugin de LMS relevante do WordPress dispara uma ação quando um usuário conclui um curso. A integração é sempre os mesmos três passos:
- Conecte-se à ação de conclusão do seu LMS específico.
- Busque (ou crie) a identidade do destinatário — geralmente apenas o e-mail da conta WordPress dele e o nome de exibição.
- Chame
POST /awardsna API do Badges Ninja comwp_remote_post(), passando o ID do emblema e os dados do destinatário.
Primeiro você vai precisar de uma chave de API. Gere uma no seu painel, em API Keys — veja o guia de chaves de API para o passo a passo completo. As chaves são exibidas uma única vez na criação, então armazene-a em wp-config.php como uma constante em vez de no banco de dados:
define( 'BADGES_NINJA_API_KEY', 'bws_your_32_hex_key_here' );
define( 'BADGES_NINJA_BADGE_ID', 'your-badge-id' );

Mantenha essa chave no servidor. Tudo neste guia roda em PHP no seu servidor WordPress — wp_remote_post() é uma chamada do lado do servidor, e wp-config.php nunca é enviado ao navegador. É exatamente isso que você quer: a chave viaja de servidor para servidor via HTTPS, e nenhum visitante do site consegue lê-la. Nunca mova essa chamada para JavaScript do lado do cliente — um fetch() feito pelo navegador com a chave embutida a exporia para qualquer pessoa através das ferramentas de desenvolvedor do navegador. Dois hábitos que valem a pena manter: garanta que sua hospedagem sirva wp-config.php como PHP executado (nunca como texto simples, e não deixe uma cópia wp-config.php.bak na raiz do site), e crie uma chave de API dedicada para essa integração, para poder revogá-la de forma independente caso ela seja comprometida — sem quebrar suas outras ferramentas.
Uma função auxiliar compartilhada mantém cada hook de LMS enxuto:
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 );
}
O e-mail do destinatário recebe hash SHA-256 no lado do servidor assim que chega ao Badges Ninja, e o payload de retorno inclui a URL de verificação do award — útil se você quiser mostrar um link de “ver sua credencial” logo ali no WordPress depois que a chamada for bem-sucedida.
LearnDash
O LearnDash dispara learndash_course_completed com um único argumento em array contendo user e 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 );
} );
Armazenar o ID do emblema como metadado do curso (em vez de uma única constante global BADGES_NINJA_BADGE_ID) é a escolha certa assim que você tem mais de um curso — cada curso corresponde ao seu próprio design de emblema.
LifterLMS
O LifterLMS dispara lifterlms_course_completed com $user_id e $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
O Tutor LMS dispara tutor_course_complete_after com o ID do curso, e você obtém o usuário atual a partir da sessão:
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 );
} );
Se a sua configuração do Tutor LMS dispara a conclusão a partir de um processo em segundo plano (por exemplo, via correção automática de quiz), troque get_current_user_id() pelo ID de usuário que o seu hook específico fornece — verifique o payload com error_log( print_r( func_get_args(), true ) ) uma vez durante a configuração para confirmar os argumentos.
Projetando o emblema antes de conectar o hook
Antes de qualquer coisa disso disparar, você precisa de um emblema para conceder. O designer visual resolve isso sem exigir um designer na equipe — mais de 80 modelos de formas, cores personalizadas, biblioteca de ícones e upload de logotipo, tudo com ajuste à grade. Se você é novo no designer, Projetando seu primeiro certificado digital verificável mostra como escolher um modelo e lançar algo que os destinatários realmente vão querer compartilhar.
Depois que o emblema existir, pegue o ID dele no painel (ou via GET /badges) e coloque no campo personalizado do seu curso.
O que o destinatário realmente recebe
Essa é a parte que um plugin de emblemas caseiro do WordPress não consegue replicar. Quando POST /awards tem sucesso, o destinatário recebe:
- Uma URL de verificação única que qualquer pessoa pode abrir — sem precisar fazer login no WordPress — mostrando que a credencial é real, quem a emitiu e quando.
- Um código QR e um certificado em PDF A4, gerados automaticamente.
- Um botão de Adicionar ao perfil do LinkedIn, se o seu emissor tiver um ID de organização do LinkedIn configurado — veja Adicionar um botão “Adicionar ao perfil” do LinkedIn para a configuração única.
- Acesso ao próprio portal do destinatário em
badges.ninja/me, via login com link mágico — sem senha para esquecer, sem conta separada para gerenciar no seu site WordPress. - Open Badge v2.0 JSON-LD compatível com o padrão, para que qualquer verificador compatível com OB (não apenas o Badges Ninja) possa validá-la.
Nada disso é trabalho do WordPress construir, e nada disso deveria viver apenas dentro do seu banco de dados WordPress.
Lidando com falhas com elegância
Os hooks de conclusão de curso disparam durante uma requisição de página ao vivo, e uma chamada de API lenta ou malsucedida não deveria bloquear a tela de “parabéns” do aluno. Dois ajustes práticos assim que você avançar além de uma prova de conceito:
Não deixe um award falho bloquear a interface. A função auxiliar acima já registra o erro e retorna false em vez de lançar uma exceção — LearnDash, LifterLMS e Tutor continuam seu fluxo normal de conclusão independentemente do que badges_ninja_issue_award() retornar.
Coloque na fila em vez de chamar inline, em escala. Se você estiver processando turmas grandes por um único curso de uma vez (uma data de início de turma, um desbloqueio de reprise de webinar), dispare um evento agendado do WP-Cron a partir do hook em vez de chamar a API de forma síncrona:
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 );
Isso distribui a carga e evita que uma única requisição lenta se torne o problema do aluno. Para lotes verdadeiramente grandes (uma turma inteira do passado, migrada de uma só vez), pule totalmente o caminho do hook do WordPress e use awards em massa via CSV — envie o arquivo uma vez, e a plataforma pagina a emissão no lado do servidor com pausa/retomada já embutidas.
Uma nota sobre idempotência
Se o seu LMS algum dia disparar o hook de conclusão mais de uma vez para o mesmo usuário (um caso extremo comum do LearnDash com novas tentativas de quiz, ou uma resincronização do Tutor LMS), você não vai querer conceder o mesmo emblema duas vezes. A proteção mais simples é um flag de user-meta do WordPress que você define logo após uma chamada bem-sucedida:
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 );
}
Se você estiver emitindo em volume real e quiser tratar isso de forma centralizada em vez de por site, veja o tratamento de eventos via webhooks ou o guia rápido completo da API para os formatos de requisição/resposta de cada endpoint.
Quando esse padrão cresce além de um único curso
Os exemplos acima assumem um emblema por curso. Assim que você passa a trabalhar com credenciais empilháveis — um emblema de trilha que é desbloqueado após vários emblemas de curso, ou um emblema final que depende de múltiplos pré-requisitos — mova o mapeamento de “qual emblema, para qual conclusão” do post meta para uma pequena tabela de consulta, ou conduza isso a partir de uma automação apoiada em planilha (Airtable ou Google Sheets) que dispare a mesma chamada POST /awards. A chamada de API em si não muda; muda apenas o que decide quando fazê-la.
Solucionando problemas da integração
Um punhado de problemas explica a maior parte do atrito que as pessoas encontram ao configurar isso pela primeira vez:
O hook nunca dispara. Confirme se você está conectando à ação correta para a versão real do seu plugin — o LearnDash, em particular, mudou nomes de hooks de conclusão entre versões principais (instalações mais antigas às vezes ainda dependem de learndash_course_completed disparando por um caminho de código diferente das mais novas). Adicione um error_log() temporário no topo do seu callback e observe wp-content/debug.log enquanto você conclui um curso de teste como um usuário descartável.
wp_remote_post() expira o tempo de espera. Ambientes de hospedagem compartilhada às vezes bloqueiam conexões HTTPS de saída para hosts desconhecidos, ou limitam os tempos de espera de requisição abaixo dos 15 segundos definidos acima. Se as chamadas expiram consistentemente, verifique com sua hospedagem se conexões de saída para api.badges.ninja são permitidas, e confirme se a extensão curl do seu PHP tem certificados CA atualizados — um pacote de certificados desatualizado é uma falha silenciosa comum em pilhas de hospedagem compartilhada mais antigas.
400 Bad Request. Ao payload falta um campo obrigatório ou ele tem o formato errado. POST /awards espera badgeId, um objeto recipient aninhado com name e email, e um timestamp issuedOn — o helper acima envia exatamente isso. O tropeço mais comum é o nome do destinatário: ele precisa ter pelo menos 5 caracteres, então um nome de exibição do WordPress como “Jo” é rejeitado. Use como alternativa o nome completo da conta (ou a parte local do e-mail) quando o nome de exibição for curto demais.
401 Unauthorized. A constante da chave de API não está sendo carregada, ou ela foi regenerada depois que a constante foi definida. As chaves são exibidas uma única vez na criação e não podem ser recuperadas de novo — se você perdeu o controle de qual chave está ativa, exclua a antiga e emita uma nova em vez de adivinhar.
Emblema emitido, mas com o design errado. Isso quase sempre é um valor de post-meta badges_ninja_badge_id obsoleto, deixado de algum teste. Como o mapeamento vive no post do curso, é fácil esquecer que você o alterou depois de duplicar um curso para uma nova turma — vale a pena uma verificação rápida sempre que você clonar um curso.
Awards duplicados para a mesma pessoa. Já coberto acima com a proteção de user-meta, mas vale repetir: não há garantia de que os hooks de conclusão do LMS disparem exatamente uma vez. Trate “já concedido” como um caso normal a ser verificado, não como um caso extremo a ser ignorado.
Perguntas frequentes
Isso funciona com pacotes de cursos do WooCommerce? Sim — se uma compra de pacote deveria disparar um emblema independentemente da conclusão do curso (por exemplo, um emblema de “membro certificado” para quem compra um pacote específico), conecte-se a woocommerce_order_status_completed em vez de uma ação de conclusão de LMS, e busque o ID do emblema no meta do produto em vez do curso.
Os destinatários podem receber o emblema sem uma conta WordPress? Sim, e esse é justamente o ponto. O award está vinculado ao endereço de e-mail dele no Badges Ninja, não a um registro de usuário do WordPress. Se o seu site permite checkout como convidado ou conclusão anônima de quiz, apenas garanta que você está capturando um endereço de e-mail real para passar para badges_ninja_issue_award().
E se eu quiser revisar os awards antes de eles saírem? Evite disparar a chamada diretamente a partir do hook de conclusão. Em vez disso, grave o award pendente (usuário, curso, timestamp) em uma tabela personalizada ou tipo de post, e emita-o a partir de uma tarefa agendada ou de um botão de admin “Aprovar e conceder” que chama a mesma função auxiliar sob demanda.
Preciso de um emblema separado por curso, ou um pode cobrir vários? Ambos funcionam. Alguns emissores criam um emblema por curso para mais granularidade; outros criam um único emblema de “programa concluído” e só o concedem depois que cada curso obrigatório é concluído, verificando a conclusão de pré-requisitos dentro do hook antes de chamar a API.
Pronto para emitir sua primeira credencial verificável? Comece grátis no badges.ninja — designer visual, página de verificação pública, certificado em PDF, saída Open Badge v2.0. Não é necessário cartão de crédito.
Como este artigo foi feito
Alguns posts deste blog são redigidos com a ajuda de um assistente de IA e depois revisados, verificados e editados pela equipe da Badges Ninja antes da publicação. Cada exemplo de código e preço é verificado no produto real. Saiba mais sobre nosso processo editorial e de IA em nossa página do processo editorial .

Sobre o 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.
Mais de Nacho Coll
- Open Badges no Salesforce: emita credenciais verificáveis a partir de gatilhos do CRM1 de out. de 2026 · 10min de leitura
- Emitindo Open Badges pela API REST do Badges Ninja: guia de início rápido28 de set. de 2026 · 10min de leitura
- Incorpore a verificação de emblemas no seu site (sem iframe, sem SDK)24 de set. de 2026 · 11min de leitura
