Combien de kilo-octets faut-il réellement pour qu’un apprenant clique sur une réponse et voie s’afficher « correct » ou « incorrect » ? Sur une plateforme de formation en ligne qui utilisait jusqu’ici une bibliothèque de quiz React tierce, pesant plusieurs centaines de kilo-octets une fois empaquetée avec ses dépendances, la question méritait d’être posée sérieusement au moment de reconstruire ce module de quiz en bloc natif. La réponse, une fois le bloc reconstruit avec les stores de l’Interactivity API stabilisée depuis WordPress 6.5, tient en douze kilo-octets de JavaScript.
Le quiz se compose d’un bloc parent (le conteneur du quiz, qui gère le score global) et de blocs enfants représentant chaque question, insérés via InnerBlocks avec un allowedBlocks restreint à un seul type de bloc question, garantissant une structure éditoriale cohérente quel que soit le nombre de questions ajoutées par le formateur.
Un état partagé entre bloc parent et blocs enfants
Le bloc parent déclare l’état initial du quiz côté serveur, dans son render_callback, via wp_interactivity_state() : score courant, nombre de questions répondues, état de complétion. Chaque bloc question enfant partage ce même espace de nom d’interactivité (data-wp-interactive="acme/quiz"), ce qui lui permet de lire et modifier l’état du quiz parent sans prop-drilling ni gestionnaire d’état tiers.
function acme_render_quiz( $attributes, $content ) {
wp_interactivity_state( 'acme/quiz', [
'score' => 0,
'repondues' => 0,
'total' => $attributes['nombreQuestions'],
] );
return sprintf(
'<div data-wp-interactive="acme/quiz">%s</div>',
$content
);
}
Le bloc question : une directive par état visuel
Chaque question affiche ses propositions de réponse avec une classe conditionnée par l’état de la réponse sélectionnée, gérée entièrement par des directives déclaratives, sans logique de rendu JavaScript personnalisée :

<ul data-wp-context='{ "reponseChoisie": null, "bonneReponse": "b" }'>
<li
data-wp-on--click="actions.choisirReponse"
data-wp-class--correct="state.estCorrecte"
data-wp-class--incorrect="state.estIncorrecte"
data-wp-key="reponse-a"
>Option A</li>
<li
data-wp-on--click="actions.choisirReponse"
data-wp-key="reponse-b"
>Option B</li>
</ul>
import { store, getContext, getElement } from '@wordpress/interactivity';
store( 'acme/quiz', {
state: {
get estCorrecte() {
const context = getContext();
const { attributes } = getElement();
return context.reponseChoisie === attributes[ 'data-wp-key' ]
&& context.reponseChoisie === context.bonneReponse;
},
},
actions: {
choisirReponse() {
const context = getContext();
const { attributes } = getElement();
const cle = attributes[ 'data-wp-key' ];
if ( context.reponseChoisie !== null ) {
return; // une question ne se répond qu'une fois
}
context.reponseChoisie = cle;
const { state } = store( 'acme/quiz' );
state.repondues += 1;
if ( cle === context.bonneReponse ) {
state.score += 1;
}
},
},
} );
Pourquoi ce choix a été retenu plutôt qu’une bibliothèque existante
La bibliothèque de quiz React précédente offrait davantage de types de questions prêts à l’emploi (glisser-déposer, association de paires), fonctionnalités que ce quiz n’utilisait en réalité jamais. Le compromis retenu accepte de coder chaque nouveau type de question à la main, en échange d’un poids JavaScript divisé par plusieurs dizaines et d’une absence totale de dépendance à maintenir à jour face aux failles de sécurité éventuelles d’une bibliothèque tierce.
- Poids JavaScript total du bloc : environ 12 Ko, contre plusieurs centaines de Ko pour la bibliothèque précédente avec ses dépendances React embarquées.
- Aucune dépendance externe à surveiller ou mettre à jour en cas d’alerte de sécurité.
- Chaque nouveau type de question exige un développement spécifique, contrairement à la bibliothèque précédente qui les proposait tous nativement.
Ce qu’il reste à surveiller
L’enregistrement du score final, une fois le quiz terminé, est envoyé côté serveur via un appel fetch classique déclenché par une action du store, vers un point de terminaison REST qui journalise le résultat dans une table de progression. Ce point reste identique à toute autre soumission de formulaire côté WordPress, l’Interactivity API ne changeant rien à la nécessité de valider et journaliser ce résultat côté serveur, jamais uniquement côté client.
Je ne recommande de reconstruire un composant interactif « à la main » avec l’Interactivity API que lorsque les besoins réels sont clairement identifiés et limités : c’est un excellent compromis poids contre fonctionnalités, mais il perd tout son intérêt si chaque nouveau besoin oblige à réinventer ce qu’une bibliothèque mature proposait déjà.
En résumé
Ce quiz démontre qu’un composant interactif riche ne nécessite pas systématiquement un framework JavaScript complet embarqué côté public. L’Interactivity API, désormais stable, a permis de diviser drastiquement le poids du bloc tout en conservant une expérience fluide pour l’apprenant, au prix d’un développement plus artisanal pour chaque nouveau type de question.