Skip to Content

Chapitre 7.1 — Anatomie d’un plugin

⏱️ TL;DR — Un plugin, c’est un dossier dans wp-content/plugins/ contenant au minimum un fichier PHP avec un en-tête de commentaire (Plugin Name: …). WordPress le détecte et permet de l’activer. Un plugin bien fait gère trois moments : l’activation (register_activation_hook — créer tables, options, flush rewrite), la désactivation (nettoyage réversible), et la désinstallation (uninstall.php — suppression définitive des données). On préfixe tout, on protège contre l’accès direct, et on branche sa logique sur des hooks.

🎯 Objectifs

  • Créer un plugin détecté et activable par WordPress.
  • Comprendre activation / désactivation / désinstallation.
  • Structurer les fichiers d’un plugin.
  • Appliquer les protections de base (accès direct, préfixes).

1. Le minimum : un fichier avec en-tête

Créez wp-content/plugins/wpr-books/wpr-books.php :

<?php /** * Plugin Name: WPR Books * Plugin URI: https://exemple.com/wpr-books * Description: Gère un catalogue de livres (CPT, taxonomie, REST). * Version: 1.0.0 * Requires at least: 6.4 * Requires PHP: 8.1 * Author: Vous * License: GPL-2.0-or-later * Text Domain: wpr-books * Domain Path: /languages */ // Sécurité : empêcher l'accès direct au fichier if ( ! defined( 'ABSPATH' ) ) { exit; }

Dès que ce fichier existe avec Plugin Name, le plugin apparaît dans Extensions et peut être activé.

⚠️ Piège n°1 — l’accès direct. Le if ( ! defined( 'ABSPATH' ) ) exit; en tête de chaque fichier PHP du plugin empêche qu’on l’exécute directement via son URL (hors du contexte WordPress) — une protection de base contre certaines attaques et fuites d’infos. À mettre systématiquement.


2. Structure d’un plugin qui grandit

Un plugin d’une fonction tient dans un fichier ; dès qu’il grossit, on organise :

wpr-books/ ├── wpr-books.php ← fichier principal (en-tête + amorçage) ├── uninstall.php ← nettoyage à la désinstallation ├── includes/ ← le code (classes, fonctions) │ ├── class-wpr-books.php │ ├── class-cpt.php │ └── class-meta.php ├── admin/ ← code spécifique à l'admin ├── assets/ ← CSS/JS (enqueue) ├── languages/ ← fichiers de traduction (.pot/.po/.mo) └── readme.txt ← pour wp.org

Le fichier principal amorce le plugin (charge les classes, instancie, branche les hooks). On détaille l’organisation en classe au chapitre suivant.


3. Les trois moments : activation, désactivation, désinstallation

Activation — préparer le terrain (une fois)

register_activation_hook( __FILE__, 'wpr_books_activate' ); function wpr_books_activate() { wpr_books_register_cpt(); // enregistrer le CPT (même fonction qu'au runtime) flush_rewrite_rules(); // régénérer les URLs (ch. 5.9) — UNE fois add_option( 'wpr_books_version', '1.0.0' ); // créer une table custom si besoin (dbDelta, ch. 5.6) }

Désactivation — nettoyage réversible

register_deactivation_hook( __FILE__, 'wpr_books_deactivate' ); function wpr_books_deactivate() { wp_clear_scheduled_hook( 'wpr_books_tache' ); // retirer les tâches cron (ch. 5.8) flush_rewrite_rules(); // NE PAS supprimer les données ici : la désactivation doit être réversible }

Désinstallation — suppression définitive (uninstall.php)

<?php // uninstall.php — exécuté à la SUPPRESSION du plugin if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { exit; } delete_option( 'wpr_books_version' ); // supprimer options, meta, tables custom… (si l'utilisateur le souhaite)

⚠️ Piège n°2 — confondre désactivation et désinstallation. La désactivation doit être réversible (on peut réactiver sans perdre de données) : n’y supprimez rien de définitif. La désinstallation (uninstall.php ou register_uninstall_hook) est le seul endroit pour supprimer les données. Supprimer les contenus d’un utilisateur à la simple désactivation est une faute grave.

💡 Pour un dev React — Ces hooks sont les lifecycle de votre plugin (comme un install/uninstall de dépendance, ou onMount/onUnmount à l’échelle du plugin) : activation = setup (migrations, seed), désactivation = pause propre (sans perte), désinstallation = cleanup définitif. Bien les séparer évite les catastrophes (données effacées par erreur).


4. Bonnes pratiques structurelles

  • Préfixer tout (wpr_books_…, ou un namespace PHP WPR\Books\…) : l’espace global de PHP est partagé par tous les plugins → sans préfixe, collision fatale de noms.
  • Constantes utiles en tête : define( 'WPR_BOOKS_PATH', plugin_dir_path( __FILE__ ) ); et plugin_dir_url( __FILE__ ) pour les assets.
  • Charger tard : brancher l’enregistrement (CPT, hooks) sur init (ch. 5.1), pas au chargement brut.
  • Un plugin = une responsabilité : évitez le plugin « fourre-tout ». Découpez si nécessaire.
  • Vérifier les prérequis (version PHP/WP) et échouer proprement plutôt que de provoquer une erreur fatale.

5. Activer et tester

  • Déposez le dossier, activez dans Extensions (ou wp plugin activate wpr-books).
  • WP_DEBUG activé (ch. 4.5) : un plugin propre ne génère aucune notice.
  • Testez le cycle complet : activer (les URLs/tables sont-elles créées ?), désactiver (réversible ?), désinstaller (le nettoyage se fait-il ?).

✏️ Exercices

  1. Quel est le strict minimum pour que WordPress détecte un plugin ?
  2. Où crée-t-on une table custom : à l’activation, à la désactivation ou à la désinstallation ? Et où la supprime-t-on ?
  3. Pourquoi préfixer (ou namespacer) systématiquement ses fonctions ?

✅ Solution

  1. Un fichier PHP dans wp-content/plugins/… avec un en-tête de commentaire contenant au moins Plugin Name:. WordPress le liste alors dans Extensions.
  2. On crée la table à l’activation (register_activation_hook, via dbDelta). On la supprime à la désinstallation (uninstall.php). La désactivation ne doit rien supprimer (réversible).
  3. Parce que PHP a un espace de noms global partagé par tous les plugins : sans préfixe/namespace, deux fonctions homonymes provoquent une erreur fatale. Le préfixe garantit l’unicité.

🧠 Quiz de révision

1. Qu’est-ce qui rend un fichier reconnaissable comme plugin ?

L’en-tête de commentaire avec au minimum Plugin Name:.

2. À quoi sert register_activation_hook ?

À exécuter du code une fois à l’activation : créer tables/options, enregistrer le CPT et flush_rewrite_rules().

3. La désactivation doit-elle supprimer les données ?

Non : elle doit être réversible. La suppression des données se fait à la désinstallation (uninstall.php).

4. À quoi sert if ( ! defined( ‘ABSPATH’ ) ) exit; ?

À empêcher l’accès direct au fichier PHP hors du contexte WordPress (protection de base).

5. Pourquoi éviter l’espace de noms global sans préfixe ?

Pour éviter les collisions de noms entre plugins (erreur fatale) : on préfixe (wpr_books_…) ou on utilise un namespace.


Chapitre suivant : Les hooks en pratique.