Skip to Content
WordPressPartie 14 — Mini-jeux (exploration guidée)12 — Premier code : hooks & functions.php

Terrain 12 — Premier code : hooks & functions.php

⏱️ TL;DR — 30 mini-jeux ⭐⭐⭐ sur le mécanisme fondamental de WordPress : les hooks (actions & filtres). Tu vas brancher ton code sur le cœur sans le modifier. Travaille dans ton plugin labo (terrain 11) ou un thème enfant (terrain 13), avec WP_DEBUG_LOG actif.

💡 Pour un dev React — Une action = un event listener (« quand X arrive, fais Y ») ; un filtre = une transformation de valeur (« la donnée passe par ta fonction, tu la renvoies modifiée »). Tout WordPress est extensible par ces deux primitives.


🕹️ Mini-jeu 1 — Ton premier add_action ⭐⭐⭐ 💻

But : exécuter du code sur un événement. Mission : affiche un message en pied de chaque page. Étapes :

add_action( 'wp_footer', function () { echo '<p style="text-align:center">Fait avec ❤️ en apprenant WordPress</p>'; } );

✅ Solution

add_action( $hook, $callback ) attache ta fonction à un point d’action du cœur. wp_footer se déclenche juste avant </body> : ton echo s’affiche partout. Tu viens d’étendre WordPress sans toucher son code.


🕹️ Mini-jeu 2 — Action vs filtre ⭐⭐⭐ 💻

But : la distinction clé. Mission : énonce la différence, puis prédis lequel retourne une valeur.

✅ Solution

Action (do_action) : « il s’est passé quelque chose » → ton callback agit (echo, enregistre…) et ne retourne rien d’utile. Filtre (apply_filters) : « voici une valeur » → ton callback la modifie et la retourne. Oublier de return dans un filtre = bug classique (jeu 4).


🕹️ Mini-jeu 3 — Callback nommé plutôt qu’anonyme ⭐⭐⭐ 💻

But : du code réutilisable. Mission : réécris le jeu 1 avec une fonction nommée préfixée. Étapes :

function labo_footer_credit() { echo '<p class="labo-credit">Appris sur le terrain 12</p>'; } add_action( 'wp_footer', 'labo_footer_credit' );

✅ Solution

Une fonction nommée et préfixée (labo_) est réutilisable et détachable (remove_action, jeu 7) — impossible avec une closure anonyme. Préfixe toujours pour éviter les collisions.


🕹️ Mini-jeu 4 — Ton premier filtre ⭐⭐⭐ 💻

But : modifier une valeur. Mission : ajoute une signature à la fin de chaque article. Étapes :

add_filter( 'the_content', function ( $content ) { if ( is_single() ) { $content .= '<p><em>— Merci d\'avoir lu.</em></p>'; } return $content; } );

✅ Solution

the_content passe le contenu de l’article dans ta fonction : tu l’augmentes et le retournes. Sans le return $content, l’article disparaîtrait. is_single() limite aux articles seuls (jeu 17).


🕹️ Mini-jeu 5 — La priorité d’un hook ⭐⭐⭐ 💻

But : contrôler l’ordre. Mission : attache deux callbacks au même hook avec des priorités différentes. Étapes :

add_action( 'wp_footer', 'labo_un', 5 ); add_action( 'wp_footer', 'labo_deux', 20 );

✅ Solution

Le 3e argument = priorité (défaut 10). Plus petit = plus tôt. Ici labo_un (5) s’exécute avant labo_deux (20). Levier pour se placer avant/après un autre callback (le tien ou celui d’une extension).


🕹️ Mini-jeu 6 — Le nombre d’arguments ⭐⭐⭐⭐ 💻

But : recevoir plus d’un paramètre. Mission : utilise le 4e argument d’add_filter pour recevoir 2 arguments. Étapes :

add_filter( 'the_title', 'labo_titre', 10, 2 ); function labo_titre( $title, $post_id ) { return $title; }

✅ Solution

Le 4e argument (accepted_args) déclare combien de paramètres ton callback reçoit. the_title en fournit 2 (titre, ID) mais n’en passe qu’un si tu ne le demandes pas. Oublier ce chiffre = « argument manquant ».


🕹️ Mini-jeu 7 — Détacher un hook ⭐⭐⭐⭐ 💻

But : annuler un comportement. Mission : retire un callback attaché par défaut ou par une extension. Étapes :

remove_action( 'wp_head', 'wp_generator' );

✅ Solution

remove_action/remove_filter détachent un callback (il faut le même nom et la même priorité). Ici on cache la version de WordPress du <head> (durcissement, terrain 16). Ne marche que sur des callbacks nommés.


🕹️ Mini-jeu 8 — Le hook init ⭐⭐⭐ 💻

But : le point d’entrée « tout est prêt ». Mission : logue un message sur init. Étapes :

add_action( 'init', function () { error_log( 'Terrain 12 : init a tiré' ); } );

✅ Solution

init se déclenche après le chargement de WordPress, avant tout rendu : c’est qu’on enregistre CPT, taxonomies, shortcodes (terrain 15). error_log() écrit dans debug.log (terrain 11) — ton console.log serveur.


🕹️ Mini-jeu 9 — Charger un CSS proprement ⭐⭐⭐⭐ 💻

But : la BONNE façon d’ajouter des assets. Mission : enfile une feuille de style sur le front. Étapes :

add_action( 'wp_enqueue_scripts', function () { wp_enqueue_style( 'labo', plugins_url( 'labo.css', __FILE__ ) ); } );

✅ Solution

Jamais de <link>/<script> en dur dans wp_head : on enfile via wp_enqueue_style/script sur le hook wp_enqueue_scripts. WordPress gère alors dépendances, versions, ordre, dédoublonnage. Règle absolue (Partie 6).


🕹️ Mini-jeu 10 — Charger un JS avec dépendance ⭐⭐⭐⭐ 💻

But : dépendances gérées. Mission : enfile un JS qui dépend de wp-element (React). Étapes :

wp_enqueue_script( 'labo-js', plugins_url( 'labo.js', __FILE__ ), array( 'wp-element' ), '1.0', true );

✅ Solution

Le 3e argument = dépendances (chargées avant), le 5e true = dans le footer. Déclarer wp-element te donne React côté WordPress (Partie 8). WordPress résout l’ordre pour toi.


🕹️ Mini-jeu 11 — Une page d’admin ⭐⭐⭐⭐ 💻

But : ajouter une entrée de menu. Mission : crée une page sous « Réglages ». Étapes :

add_action( 'admin_menu', function () { add_options_page( 'Labo', 'Labo', 'manage_options', 'labo', 'labo_page' ); } ); function labo_page() { echo '<div class="wrap"><h1>Mon Labo</h1></div>'; }

✅ Solution

admin_menu + add_options_page créent une page d’admin protégée par la capability manage_options (admin only). La fonction de rendu affiche le HTML. Base d’une page de réglages (Settings API, terrain 15).


🕹️ Mini-jeu 12 — Réagir à l’enregistrement ⭐⭐⭐⭐ 💻

But : agir quand un article est sauvé. Mission : logue l’ID à chaque save_post. Étapes :

add_action( 'save_post', function ( $post_id ) { if ( wp_is_post_revision( $post_id ) ) return; error_log( "Article sauvé : $post_id" ); } );

✅ Solution

save_post tire à chaque sauvegarde. On ignore les révisions (sinon double déclenchement). C’est le hook où l’on sauve des métadonnées custom (terrain 15) — avec vérif nonce + capability (terrain 16).


🕹️ Mini-jeu 13 — Un filtre sur la classe du body ⭐⭐⭐ 💻

But : styler selon le contexte. Mission : ajoute une classe CSS au <body>. Étapes :

add_filter( 'body_class', function ( $classes ) { $classes[] = 'theme-labo'; return $classes; } );

✅ Solution

body_class reçoit un tableau de classes : tu en ajoutes une et retournes le tableau. Tu peux alors cibler .theme-labo en CSS. Modèle typique du filtre qui manipule une liste.


🕹️ Mini-jeu 14 — Raccourcir les extraits ⭐⭐⭐ 💻

But : un filtre numérique. Mission : limite les extraits à 20 mots. Étapes :

add_filter( 'excerpt_length', function ( $len ) { return 20; } );

✅ Solution

excerpt_length filtre un nombre. Beaucoup de comportements sont des valeurs filtrables (longueur, texte « […] » via excerpt_more). Cherche « filter » + ton besoin : il existe souvent un hook.


🕹️ Mini-jeu 15 — Ajouter un item au menu ⭐⭐⭐⭐ 💻

But : injecter dans la navigation. Mission : ajoute un lien en fin de menu principal. Étapes :

add_filter( 'wp_nav_menu_items', function ( $items, $args ) { return $items . '<li><a href="/contact">Contact</a></li>'; }, 10, 2 );

✅ Solution

wp_nav_menu_items filtre le HTML des items : on concatène. Combiné à $args->theme_location, on cible un menu précis. Répond au « menu conditionnel » évoqué au terrain 06, jeu 19.


🕹️ Mini-jeu 16 — Déclencher son propre hook ⭐⭐⭐⭐ 💻

But : rendre TON code extensible. Mission : expose une action et un filtre personnels. Étapes :

do_action( 'labo_apres_traitement', $data ); $prix = apply_filters( 'labo_prix', $prix );

✅ Solution

do_action/apply_filters créent tes points d’extension : d’autres (ou toi) pourront s’y brancher sans modifier ton plugin. C’est ainsi qu’on écrit du code extensible (Partie 7) — la philosophie WordPress appliquée à ton propre code.


🕹️ Mini-jeu 17 — Les conditional tags ⭐⭐⭐ 💻

But : agir selon le contexte. Mission : n’ajoute la signature (jeu 4) que sur la home ET pas en admin. Étapes :

if ( is_front_page() && ! is_admin() ) { // ... }

✅ Solution

is_front_page(), is_single(), is_page(), is_admin(), is_user_logged_in()… répondent « où/qui sommes-nous ». ⚠️ La plupart ne sont fiables qu’après le hook wp (pas trop tôt). Base de tout code contextuel.


🕹️ Mini-jeu 18 — Rediriger conditionnellement ⭐⭐⭐⭐ 💻

But : contrôler l’accès à une page. Mission : redirige les non-connectés d’une page vers l’accueil. Étapes :

add_action( 'template_redirect', function () { if ( is_page( 'membres' ) && ! is_user_logged_in() ) { wp_safe_redirect( home_url() ); exit; } } );

✅ Solution

template_redirect tire avant le rendu du gabarit : moment idéal pour rediriger. Toujours wp_safe_redirect() puis exit. Brique d’un contenu réservé aux membres.


🕹️ Mini-jeu 19 — Un shortcode ⭐⭐⭐ 💻

But : insérer du dynamique dans le contenu. Mission : crée [labo_annee] qui affiche l’année. Étapes :

add_shortcode( 'labo_annee', function () { return esc_html( date( 'Y' ) ); } );

✅ Solution

add_shortcode mappe [labo_annee] à une fonction qui retourne (jamais echo) le HTML. Insérable via le bloc Shortcode (terrain 05, jeu 27). Un shortcode retourne, comme un filtre.


🕹️ Mini-jeu 20 — Shortcode avec attributs ⭐⭐⭐⭐ 💻

But : paramétrer. Mission : [labo_salut nom="Alex"] → « Salut Alex ». Étapes :

add_shortcode( 'labo_salut', function ( $atts ) { $a = shortcode_atts( array( 'nom' => 'toi' ), $atts ); return 'Salut ' . esc_html( $a['nom'] ); } );

✅ Solution

shortcode_atts fusionne les attributs passés avec des défauts — comme des props avec valeurs par défaut. Toujours échapper la sortie (esc_html). Pattern réutilisé partout.


🕹️ Mini-jeu 21 — Personnaliser le titre de la page login ⭐⭐⭐ 💻

But : toucher l’écran de connexion. Mission : change le lien du logo de /wp-login.php. Étapes :

add_filter( 'login_headerurl', function () { return home_url(); } );

✅ Solution

L’écran de login a ses propres hooks (login_headerurl, login_enqueue_scripts pour un CSS, login_headertext). White-labelliser le login est une demande client fréquente. Chaque « zone » de WordPress a ses hooks dédiés.


🕹️ Mini-jeu 22 — Autoriser un type de fichier ⭐⭐⭐⭐ 💻

But : étendre les uploads. Mission : autorise l’upload de fichiers .svg (avec prudence). Étapes :

add_filter( 'upload_mimes', function ( $mimes ) { $mimes['svg'] = 'image/svg+xml'; return $mimes; } );

✅ Solution

upload_mimes filtre les types autorisés. ⚠️ Le SVG peut contenir du script (XSS) : à n’autoriser que pour des rôles de confiance + assainissement. Bon exemple d’un hook puissant mais sensible (terrain 16).


🕹️ Mini-jeu 23 — Un avis dans l’admin ⭐⭐⭐ 💻

But : communiquer avec l’admin. Mission : affiche une bannière d’information en admin. Étapes :

add_action( 'admin_notices', function () { echo '<div class="notice notice-info"><p>Labo actif.</p></div>'; } );

✅ Solution

admin_notices affiche les bandeaux du haut de l’admin (classes notice-info/success/warning/error). Utile pour prévenir/alerter. À conditionner (capability, page) pour ne pas spammer tous les écrans.


🕹️ Mini-jeu 24 — Vérifier la capability dans un hook ⭐⭐⭐⭐ 💻

But : sécuriser une action. Mission : n’exécute une action sensible que si l’utilisateur peut manage_options. Étapes :

if ( current_user_can( 'manage_options' ) ) { // action réservée aux admins }

✅ Solution

current_user_can() est le garde de sécurité : on vérifie la capability, jamais le rôle en dur. Réflexe à graver avant toute action sensible (terrain 16). Cacher un bouton ne suffit pas — il faut vérifier au traitement.


🕹️ Mini-jeu 25 — Injecter dans le <head> ⭐⭐⭐ 💻

But : meta/vérification. Mission : ajoute une balise meta dans le head. Étapes :

add_action( 'wp_head', function () { echo '<meta name="labo" content="terrain-12">' . "\n"; } );

✅ Solution

wp_head (déclenché par wp_head() du thème) est le point d’injection du <head> : meta, balises de vérification, préconnexions. Les plugins SEO l’utilisent massivement. Ne jamais y mettre un asset (→ enqueue, jeu 9).


🕹️ Mini-jeu 26 — Trouver le bon hook ⭐⭐⭐⭐ 💻

But : la compétence méta. Mission : tu veux agir « juste après la publication d’un article » — trouve le hook.

✅ Solution

Cherche dans le Hooks Reference (developer.wordpress.org) ou active « Query Monitor » pour voir les hooks tirés. Ici : transition_post_status ou publish_post. La vraie compétence WordPress = savoir quel hook existe pour ton besoin.


🕹️ Mini-jeu 27 — Déboguer un hook qui ne tire pas ⭐⭐⭐⭐ 💻

But : méthode de diagnostic. Mission : ton callback ne s’exécute pas — liste 3 causes probables.

✅ Solution

Causes fréquentes : (1) hook attaché trop tard (après son déclenchement) ; (2) priorité/accepted_args incorrects ; (3) condition (is_*) évaluée trop tôt ; (4) faute de frappe dans le nom du hook. Ajoute un error_log() en tête de callback pour vérifier qu’il entre.


🕹️ Mini-jeu 28 — Filtre avec valeur conditionnelle ⭐⭐⭐⭐ 💻

But : modifier seulement parfois. Mission : double le nombre d’articles par page, mais seulement sur les archives. Étapes :

add_action( 'pre_get_posts', function ( $q ) { if ( ! is_admin() && $q->is_main_query() && $q->is_archive() ) { $q->set( 'posts_per_page', 20 ); } } );

✅ Solution

pre_get_posts modifie la requête principale avant exécution (puissant !). Toujours vérifier ! is_admin() et is_main_query() pour ne pas tout casser. Un des hooks les plus utiles (Partie 5).


🕹️ Mini-jeu 29 — Organiser son code ⭐⭐⭐ 💻

But : hygiène. Mission : regroupe tes hooks du terrain dans des fichiers includes/ chargés depuis le plugin principal.

✅ Solution

Un functions.php ou plugin qui grossit devient illisible : découpe en includes/hooks-front.php, includes/admin.php, chargés par require_once. Préfixe tout. C’est le passage du snippet au plugin structuré (terrain 15).


🕹️ Mini-jeu 30 — Récap hooks ⭐⭐⭐ 💻

But : capstone du terrain. Mission : un mini-plugin qui : enfile un CSS, ajoute une signature aux articles (filtre), une page d’admin (action), un shortcode, et retire wp_generator — le tout préfixé et sécurisé.

✅ Solution

Si tu combines actions, filtres, priorités, enqueue, capability et shortcode sans copier-coller aveugle, tu tiens le cœur du dev WordPress. Tous les terrains suivants (thèmes, plugins, sécurité, REST) ne sont que des applications des hooks. Bravo.


Terrain suivant : 13 — Thème enfant.