wp_hash( $participant_id . $evenement_id . $sel_secret ) : c’est autour de cette ligne que tient l’essentiel du contrôle d’accès décrit ici. Pour un organisateur d’événement professionnel — une convention sectorielle, un salon fournisseurs, une journée d’intégration client — la question n’est pas de vendre des billets au grand public, mais de vérifier à l’entrée qu’une personne précise, déjà identifiée par son inscription, correspond bien au badge qu’elle présente.
Ce tutoriel construit, étape par étape, une extension qui génère des billets nominatifs infalsifiables et les vérifie via un point de terminaison REST interrogeable par une tablette au poste d’accueil, sans passer par un service de billetterie tiers ni ses commissions par billet vendu.
Étape 1 : modéliser le participant et son billet
Le point de départ est un type de contenu personnalisé participant_evenement, chaque billet correspondant à un article de ce type. Trois métadonnées suffisent : l’identifiant unique du billet, un jeton de validation, et un statut d’entrée.
function enregistrer_cpt_participant() {
register_post_type( 'participant_evenement', [
'label' => 'Participants',
'public' => false,
'show_ui' => true,
'supports' => [ 'title' ],
'capability_type' => 'post',
] );
}
add_action( 'init', 'enregistrer_cpt_participant' );
Étape 2 : générer un jeton signé lors de l’inscription
Chaque billet reçoit, à sa création, un jeton dérivé d’un sel secret propre au site et stocké en constante, jamais dans la base de données. Ce jeton n’est pas un simple identifiant incrémental : il doit résister à une tentative de devinette ou de fabrication d’un faux billet à partir d’un identifiant connu.
function generer_jeton_billet( int $post_id ) : string {
$sel = defined( 'BILLETTERIE_SEL_SECRET' ) ? BILLETTERIE_SEL_SECRET : wp_salt( 'auth' );
return substr( hash_hmac( 'sha256', (string) $post_id, $sel ), 0, 16 );
}
add_action( 'save_post_participant_evenement', function ( $post_id, $post, $update ) {
if ( $update ) {
return;
}
update_post_meta( $post_id, '_jeton_billet', generer_jeton_billet( $post_id ) );
}, 10, 3 );
Le jeton est ensuite encodé dans un QR code, généré côté serveur au moment de l’envoi du billet par e-mail, sous la forme d’une URL contenant l’identifiant du participant et son jeton.
Étape 3 : exposer un point de contrôle REST pour le poste d’accueil
Le poste d’accueil scanne le QR code, ce qui déclenche une simple requête vers un point de terminaison REST dédié. Ce point de terminaison vérifie le jeton, contrôle qu’il n’a pas déjà été utilisé, puis marque l’entrée comme effectuée.

Étape 4 : refuser un badge déjà scanné, sans ambiguïté
Le point sensible d’un contrôle d’accès professionnel n’est pas de valider un badge correct : c’est de refuser catégoriquement un badge déjà scanné, y compris si deux postes d’accueil tentent la validation à quelques secondes d’écart. La marque de passage doit être écrite de façon atomique.
function controler_route_rest() {
register_rest_route( 'controle-acces/v1', '/valider', [
'methods' => 'POST',
'permission_callback' => function () {
return current_user_can( 'edit_posts' );
},
'callback' => function ( WP_REST_Request $requete ) {
$post_id = absint( $requete->get_param( 'id' ) );
$jeton = sanitize_text_field( $requete->get_param( 'jeton' ) );
if ( generer_jeton_billet( $post_id ) !== $jeton ) {
return new WP_Error( 'jeton_invalide', 'Badge non reconnu.', [ 'status' => 403 ] );
}
if ( get_post_meta( $post_id, '_entree_validee', true ) ) {
return new WP_Error( 'deja_scanne', 'Ce badge a déjà été validé.', [ 'status' => 409 ] );
}
update_post_meta( $post_id, '_entree_validee', current_time( 'mysql' ) );
return [ 'statut' => 'valide', 'nom' => get_the_title( $post_id ) ];
},
] );
}
add_action( 'rest_api_init', 'controler_route_rest' );
Étape 5 : préparer le fonctionnement en cas de coupure réseau
Un salon professionnel se déroule rarement dans des conditions réseau idéales. La tablette d’accueil doit pouvoir mettre en file d’attente les scans effectués hors connexion, puis les rejouer dès que le réseau revient — en acceptant qu’un badge validé deux fois en local soit détecté et signalé lors de la synchronisation, plutôt que silencieusement ignoré.
- Stockage local des scans effectués (via le stockage du navigateur de la tablette) tant que la requête REST échoue.
- Rejeu séquentiel des scans en attente dès la reconnexion, avec traitement individuel de chaque conflit signalé.
- Affichage clair, sur l’écran de l’hôtesse, de la différence entre « badge invalide » et « badge déjà entré ».
En résumé
Un système de contrôle d’accès nominatif pour un événement B2B ne demande ni service tiers ni licence par billet : un type de contenu, un jeton signé par HMAC, et une route REST protégée suffisent à couvrir l’essentiel des besoins d’un accueil professionnel. La difficulté ne réside pas dans la génération des billets, mais dans la gestion rigoureuse de l’état « déjà scanné », qui doit rester fiable même en cas de coupure réseau ou de double poste d’accueil.