Skip to Content

Projet Niveau 2 — Plugin « Bibliothèque » (CPT Livre)

⏱️ TL;DR — Votre premier vrai plugin, et le début du fil rouge wpr-books. Vous enregistrez un Custom Post Type « Livre », une taxonomie « Genre », des champs personnalisés (ISBN, prix) via une metabox, un shortcode qui liste le catalogue, et une page de réglages (Settings API). Objectif : maîtriser le triptyque hooks / enregistrement / sécurité qui fonde tout développement WordPress.

🎯 Niveau & objectifs

  • Niveau : 2 (intermédiaire). Prérequis : Niveaux 0–1 ; bases de PHP ; WP_DEBUG activé.
  • Durée indicative : 6–10 h.
  • Vous allez pratiquer : structure d’un plugin, add_action/add_filter, register_post_type, register_taxonomy, metaboxes, register_post_meta, Settings API, shortcodes, sécurité (nonces, sanitize_*, esc_*, capabilities).

📋 Cahier des charges

Contexte — Une petite librairie veut gérer un catalogue de livres structuré dans WordPress, sans bidouiller des articles. Vous livrez le plugin socle. (C’est wpr-books, qui grandira aux niveaux 3, 4, 5.)

Objectif — Un plugin autonome, activable/désactivable proprement, qui ajoute un type de contenu « Livre » complet et l’affiche en front.

Périmètre inclus

  1. En-tête de plugin correct + activation/désactivation (avec flush_rewrite_rules au bon moment).
  2. CPT wpr_book (« Livre ») : public, show_in_rest: true, support titre/éditeur/thumbnail, réécriture d’URL livres/.
  3. Taxonomie wpr_genre (« Genre »), hiérarchique, show_in_rest.
  4. Champs meta : wpr_isbn (texte) et wpr_prix (nombre), enregistrés via register_post_meta et édités via une metabox (avec nonce).
  5. Un shortcode [wpr_books genre="..." limit="..."] listant les livres via WP_Query.
  6. Une page de réglages (Settings API) : ex. « nombre de livres par page par défaut », « devise ».
  7. Chargement des traductions (load_plugin_textdomain) et chaînes traduisibles.

Périmètre exclu — Pas de bloc Gutenberg (Niveau 3), pas de REST custom (Niveau 3), pas de front Next.js (Niveau 4). On reste PHP + admin + shortcode.

Contraintes

  • Aucune donnée non filtrée ne rentre en base (sanitize_*), aucune donnée non échappée ne sort (esc_*).
  • Sauvegarde de la metabox protégée par nonce + current_user_can.
  • Préfixe wpr_ partout (fonctions, options, meta) pour éviter les collisions.
  • Code organisé (au moins séparé en quelques fichiers includes/).

Livrables

  • Le dossier du plugin (zippable, installable sur une autre instance).
  • Un readme court : ce que fait le plugin, le shortcode et ses attributs.

✅ Critères de réussite

  • Le menu « Livres » apparaît dans l’admin ; on peut créer un livre avec ISBN et prix.
  • Les livres sont accessibles en front sur /livres/<slug> (permaliens rafraîchis).
  • La metabox refuse une sauvegarde sans nonce valide.
  • Le shortcode affiche le catalogue, filtrable par genre, respectant la limite.
  • Les champs wpr_isbn/wpr_prix apparaissent dans /wp-json/wp/v2/wpr_book (grâce à show_in_rest + register_post_meta).
  • Désactiver le plugin retire le menu ; aucune erreur PHP dans debug.log.

🗺️ Endroits à visiter

EndroitPourquoi y aller
Dossier wp-content/plugins/filesystemOuvrez 2–3 plugins simples existants : voir une vraie structure
register_post_type (doc)dev.wordpress.org Tous les arguments (rewrite, show_in_rest, supports)
Hooks init, save_post, admin_menuPlugin Handbook Les points d’accroche que vous allez utiliser
/wp-json/wp/v2/navigateurVoir votre CPT apparaître dans l’API (prépare le Niv. 3–4)
WP_DEBUG + debug.logwp-config.php / wp-content/Votre console : activez-le, gardez-le ouvert
WP-CLIterminalwp post list --post_type=wpr_book, wp plugin list
Settings API (doc)Plugin Handbook Le pattern officiel de page d’options
Core : wp-includes/post.phpfilesystemLire comment le core enregistre ses propres types

💡 Pour un dev React — Un plugin, c’est un module qui s’accroche au cycle de vie via des hooks — pensez aux useEffect/listeners, mais côté serveur et déclaratifs. register_post_type ≈ définir un modèle de données + ses routes d’un coup (comme un schéma Prisma qui génèrerait aussi l’admin et l’API REST). La discipline nouvelle : sanitize à l’entrée, escape à la sortie — non négociable, c’est la base de la sécurité WordPress.

⚠️ Piègeregister_post_type doit tourner sur le hook init, jamais directement au chargement du fichier. Et pensez à flush_rewrite_rules à l’activation (une seule fois), sinon vos URLs /livres/... renvoient un 404 fantôme.

🚀 Étapes suggérées

  1. En-tête de plugin + fichier principal ; activer le plugin vide.
  2. register_post_type('wpr_book') sur init ; créer un livre de test.
  3. Hook d’activation : flush_rewrite_rules. Vérifier l’URL front.
  4. register_taxonomy('wpr_genre') ; classer des livres.
  5. register_post_meta + metabox (affichage + sauvegarde avec nonce).
  6. Shortcode [wpr_books] via WP_Query.
  7. Page de réglages (Settings API).
  8. i18n : envelopper les chaînes, charger le textdomain.
  9. Relecture sécurité : chaque entrée sanitize, chaque sortie esc.

🎁 Bonus

  • Ajoutez une colonne « Prix » à la liste d’admin des livres (manage_{post_type}_posts_columns).
  • Rendez wpr_prix triable dans l’admin.
  • Ajoutez une capability custom (manage_wpr_books) plutôt que manage_options.

🔗 Chapitres du cours liés


Projet suivant : Niveau 3 — Bloc « Livre à la une » + REST.