Skip to Content
MoodlePartie 6 — Développer des pluginsCycle de vie et distribution d'un plugin

Chapitre 6.7 — Cycle de vie et distribution d’un plugin

Partie 6 : Développer des plugins — Chapitre 7/7 Public : développeur ayant construit ses premiers plugins (6.3–6.6). On passe de « ça marche sur ma machine » à « ça vit en production et chez les autres ». Version de référence : Moodle 5.2 (PHP 8.3+, racine web public/).

⏱️ TL;DR

  • Versionner : $plugin->version (YYYYMMDDXX) monte à chaque changement de schéma, d’access.php, de tasks.php, de services.php ou de comportement notable. $plugin->release est le libellé humain (v1.2.0).
  • requires fixe la version minimale de Moodle ; supported (tableau [min, max]) déclare la fourchette de branches supportées. dependencies liste les autres plugins requis.
  • environment.xml (rare) impose des prérequis serveur (extension PHP, version de lib).
  • Compatibilité multi-versions : une branche git par version majeure de Moodle supportée (MOODLE_502_STABLE…), plus main. On cherry-pick les correctifs entre branches.
  • Distribuer : git (le plus propre, dev + prod maîtrisée), zip (upload via l’interface), rarement composer. Un plugin = un dépôt nommé moodle-<type>_<nom>.
  • Déployer en prod : sauvegarde → mode maintenance → déposer le code (git checkout/pull) → php admin/cli/upgrade.php → purge des caches → sortir de maintenance. Jamais d’upload à chaud sur une prod chargée.
  • Gérer les incompatibilités à l’upgrade de Moodle : lire les upgrade notes, tester en préprod contre la matrice, corriger les dépréciations.
  • Publier sur moodle.org : licence GPL v3+, privacy provider, standards moodle-cs, CI verte, process de review (détaillé en Partie 11).

🎯 Objectifs

À la fin de ce chapitre, vous saurez :

  • Quand et comment incrémenter la version d’un plugin, et déclarer requires/supported/dependencies.
  • Mettre en place une stratégie de branches git pour supporter plusieurs versions de Moodle.
  • Distribuer votre plugin (git, zip) proprement.
  • Déployer en production sans casse (procédure scriptée).
  • Anticiper les incompatibilités lors des upgrades de Moodle et préparer une publication.

1. Versionner : le contrat de version.php, en profondeur

On a utilisé version.php dans chaque tutoriel. Voici sa version « production », avec tous les champs utiles.

<?php // version.php (exemple complet) defined('MOODLE_INTERNAL') || die(); $plugin->component = 'local_todolist'; // identité (obligatoire) $plugin->version = 2026070801; // version de CE code (obligatoire) $plugin->requires = 2026042000; // version MINIMALE de Moodle (5.2) $plugin->supported = [502, 503]; // branches supportées : 5.2 à 5.3 (optionnel, 4.0+) $plugin->maturity = MATURITY_STABLE; // ALPHA / BETA / RC / STABLE $plugin->release = 'v1.2.0'; // libellé humain (SemVer conseillé) $plugin->dependencies = [ // autres plugins requis (optionnel) 'mod_forum' => 2026042000, ];

1.1 version : la règle du « quand bumper »

$plugin->version (YYYYMMDDXX) est l’entier qui déclenche l’upgrade. Vous devez l’incrémenter à chaque fois que Moodle doit « reprendre en compte » quelque chose :

Vous avez modifié…Bumper version ?Pourquoi
db/install.xml / le schémaOui (+ écrire upgrade.php)rejouer la migration
db/access.php (capabilities)Ouiréenregistrer les capabilities
db/tasks.php / services.php / messages.php / hooks.phpOuirecharger ces déclarations
Une chaîne de langueNon (purge des caches suffit)pas de déclaration structurelle
Du code PHP/JS de logiqueRecommandé (traçabilité)marque une nouvelle release
Un template MustacheNon (purge suffit)rendu, pas structure

En cas de doute : bumpez. Un bump inutile ne coûte qu’un passage d’upgrade à vide ; un bump manquant laisse une déclaration non prise en compte (le bug « ma capability/tâche n’existe pas »).

⚠️ Piège : la version ne doit jamais reculer ni stagner sur un changement de schéma. Et en équipe, deux développeurs qui bumpent au même YYYYMMDDXX créent un conflit de version : convention utile → inclure l’incrément XX et coordonner (ou utiliser la date du jour + un compteur).

1.2 requires, supported, dependencies, maturity, release

  • requires : version minimale de Moodle. En dessous, Moodle refuse d’installer le plugin. Mettez la valeur de la plus ancienne version que vous supportez réellement (et que vous testez).
  • supported (depuis Moodle 4.0) : un tableau [branchemin, branchemax] en notation de branche (502 = 5.2, 503 = 5.3). Purement déclaratif/informatif (le plugin directory et l’admin l’affichent), mais honnête : ne déclarez que ce que vous testez.
  • dependencies : autres plugins requis, avec leur version minimale. Moodle bloque l’installation si une dépendance manque. À utiliser avec parcimonie (chaque dépendance complique le déploiement).
  • maturity : MATURITY_ALPHA/BETA/RC/STABLE. N’affichez STABLE que quand ça l’est.
  • release : le libellé humain. Adoptez SemVer (MAJEUR.MINEUR.CORRECTIF) : MAJEUR = rupture, MINEUR = ajout compatible, CORRECTIF = bug fix. C’est ce que verront vos utilisateurs.

💡 Pour un dev React : version (l’entier) ≈ le numéro de migration (interne, technique), et release (SemVer) ≈ la version npm (communication). requires/supported ≈ le champ engines de package.json (« ce package tourne sur Node ≥ X »). dependencies ≈ vos peerDependencies. La différence : ici les deux numéros (technique et humain) cohabitent explicitement, et l’entier technique pilote réellement l’upgrade.


2. environment.xml : imposer des prérequis serveur

Rare mais utile : votre plugin exige une extension PHP (ex. intl, gd), une version minimale d’une lib, ou un réglage serveur. On le déclare dans environment.xml, que Moodle vérifie avant l’installation.

<?xml version="1.0" encoding="UTF-8"?> <!-- public/local/todolist/environment.xml --> <COMPATIBILITY_MATRIX> <PLUGIN name="local_todolist"> <PHP_EXTENSIONS> <PHP_EXTENSION name="intl" level="required"> <FEEDBACK> <ON_CHECK message="intlrequired" plugin="local_todolist" /> </FEEDBACK> </PHP_EXTENSION> </PHP_EXTENSIONS> </PLUGIN> </COMPATIBILITY_MATRIX>

⚠️ Piège : ne dupliquez pas dans environment.xml ce que requires/dependencies gèrent déjà (version de Moodle, plugins). Réservez-le aux prérequis d’environnement système (extensions PHP, versions de bibliothèques) que Moodle ne vérifie pas autrement.


3. Compatibilité multi-versions : la stratégie de branches git

Moodle sort deux versions par an (chapitre 1.5) et n’offre pas de garantie de compatibilité d’API entre majeures. Un plugin sérieux supporte donc plusieurs versions de Moodle en parallèle. La stratégie communautaire standard : une branche git par version majeure de Moodle.

Le modèle :

  • main (ou master) : développement pour la version de Moodle la plus récente que vous ciblez.
  • MOODLE_XYZ_STABLE : une branche par version majeure supportée (MOODLE_502_STABLE, MOODLE_501_STABLE…). Ce sont les mêmes noms de branches que le core — les outils de la communauté (dont moodle-plugin-ci) s’appuient dessus.
  • Un correctif (bug fix compatible) est écrit une fois, puis cherry-pické sur chaque branche supportée.
  • Une fonctionnalité qui exige une API de la 5.2 ne descend pas sur la branche 5.1 : c’est là que le multi-branches gagne son coût.

Sur le plugin directory, chaque release est associée aux versions de Moodle qu’elle vise, et vous téléversez (ou laissez la CI publier) une release par branche.

⚠️ Piège : ne tentez pas de supporter toutes les versions dans un seul code avec des if (moodle_major() >= …) partout. Au-delà d’un ou deux tests conditionnels, le code devient illisible et fragile. Le multi-branches isole proprement les différences. Réservez les conditions in-code aux petits écarts d’API.

💡 Pour un dev React : c’est le modèle des branches de maintenance d’une lib open source (v4.x, v5.x) avec backport de correctifs par cherry-pick — exactement ce que font React, Next, etc. Le main file vers l’avant ; les branches stables reçoivent les fixes rétroportés.


4. Structurer et distribuer le dépôt

4.1 Un plugin = un dépôt

Chaque plugin vit dans son propre dépôt git, nommé par convention moodle-<type>_<nom> :

  • moodle-local_todolist
  • moodle-block_progressinfo
  • moodle-mod_simplecheck

Le contenu du dépôt = le contenu du dossier du plugin (le dépôt est local/todolist/). À l’installation, on le clone dans le bon dossier de Moodle :

# Depuis la racine du code Moodle git clone https://github.com/vous/moodle-local_todolist.git public/local/todolist

Un README.md, un LICENSE (GPL v3+), un .gitignore (ignorer amd/build/, node_modules/, vendor/) et un fichier CI (.github/workflows/) complètent le dépôt.

4.2 Les trois voies de distribution

  • Git (recommandé) — en dev et en production maîtrisée : versionnable, diff-able, git pull pour mettre à jour, branches par version de Moodle. C’est la voie propre.
  • Zip via l’interfaceAdministration du site → Plugins → Installer des plugins : téléverser le zip (le zip doit contenir un dossier racine nommé comme le plugin). Simple pour un client non technique, mais pas de traçabilité git.
  • Composer — marginal dans l’écosystème Moodle. Certaines équipes gèrent l’ensemble Moodle + plugins via Composer et un installer dédié, mais ce n’est pas la norme communautaire. À réserver aux infrastructures qui le maîtrisent déjà.

⚠️ Piège du zip : l’archive doit avoir exactement un dossier racine, nommé comme le plugin (todolist, pas moodle-local_todolist-main que GitHub génère). Un zip mal structuré fait échouer la détection avec un message obscur. Beaucoup préfèrent générer le zip via la CI plutôt qu’à la main.

⚠️ Piège du build JS : si votre plugin a des modules AMD (amd/src/), la version distribuée doit inclure amd/build/ compilé (grunt amd). En dev on ignore build/ dans git ; pour une release, on le compile et on l’inclut (ou la CI le fait). Un plugin distribué sans amd/build/ a un JS qui ne charge pas en production (où cachejs est activé).


5. Déployer en production sans casse

Voici la procédure de référence. Ne déviez pas : un upgrade raté sur une prod d’étudiants est un incident majeur.

# 0. SAUVEGARDER (base + moodledata + code). Non négociable. mysqldump ... > backup.sql # ou pg_dump tar czf moodledata.tgz /var/moodledata git -C /var/www/moodle rev-parse HEAD > code-version.txt # 1. Mode maintenance (les utilisateurs voient une page d'attente) php admin/cli/maintenance.php --enable # 2. Déployer le code du plugin (git recommandé) git -C public/local/todolist fetch --tags git -C public/local/todolist checkout v1.2.0 # une release taguée, pas "latest" # (ou pour le core : git checkout MOODLE_502_STABLE && git pull) # 3. Compiler le JS si nécessaire (souvent fait en amont dans la release) # grunt amd (dans un environnement de build, pas forcément la prod) # 4. Jouer les mises à niveau de schéma php admin/cli/upgrade.php --non-interactive # 5. Purger les caches php admin/cli/purge_caches.php # 6. Sortir du mode maintenance php admin/cli/maintenance.php --disable

Les principes derrière la procédure :

  • Sauvegarder d’abord, toujours : base et moodledata et la référence du code (pour rollback). Un upgrade qui échoue à mi-parcours doit pouvoir être annulé.
  • Mode maintenance : upgrade.php peut modifier le schéma pendant que des utilisateurs écrivent → incohérences. On ferme le site le temps de l’opération (quelques secondes à quelques minutes).
  • Déployer une version taguée, pas un main mouvant : vous devez savoir exactement quel code tourne.
  • CLI, pas l’interface web, sur une prod : plus fiable, scriptable, journalisable, sans timeout de navigateur.
  • Purge des caches en fin : sinon l’ancien code/langue/JS reste servi.

⚠️ Piège : ne jamais déposer du code de plugin à chaud sur une prod chargée sans mode maintenance, en pariant que « l’upgrade est petit ». Entre le moment où le nouveau code est en place et où upgrade.php a tourné, l’application est dans un état incohérent (nouveau code, ancien schéma) — erreurs fatales pour les utilisateurs actifs.

💡 Pour un dev React : c’est votre pipeline de déploiement habituel (backup → migrate → deploy → cache-bust) transposé, avec une particularité : le mode maintenance joue le rôle d’un deploy window explicite parce que la migration de schéma et le code ne sont pas atomiques. Pensez « migration Prisma en prod » : on ne la lance pas pendant que l’app écrit dans les tables concernées.


6. Survivre aux upgrades de Moodle

Deux fois par an, une nouvelle version de Moodle peut casser votre plugin (chapitre 1.5). Le processus pour l’anticiper :

  1. Lire les Upgrade / API change notes de la nouvelle version sur moodledev.io : la liste des changements d’API et des dépréciations. C’est votre checklist.
  2. Tester tôt contre la release candidate de Moodle, avant sa sortie officielle. La CI (moodle-plugin-ci) teste votre plugin sur une matrice Moodle × PHP × base de données (Partie 11).
  3. Corriger les dépréciations : une fonction dépréciée émet un debugging() mais fonctionne encore une version ou deux ; utilisez ce sursis pour migrer vers la nouvelle API avant qu’elle disparaisse.
  4. Publier une release compatible, déclarer la nouvelle branche dans supported, ajouter la branche git MOODLE_XYZ_STABLE.

⚠️ Piège : ne « figez » jamais une instance sur une vieille version de Moodle pour éviter de mettre à jour vos plugins. La dette s’accumule et explose à l’upgrade forcé (fin de vie/faille), avec potentiellement plusieurs versions à franchir d’un coup et des plugins tous à réparer en même temps. Le bon rythme : suivre chaque version, tester tôt, corriger au fil de l’eau.


7. Vers la publication sur moodle.org (intro)

Distribuer en privé (git/zip) ne demande rien de spécial. Publier sur le plugin directory de moodle.org impose une barre de qualité — c’est le sujet complet de la Partie 11, chapitre 8. En avant-goût, les prérequis non négociables :

  • Licence GPL v3+ (fichier LICENSE, en-têtes de fichiers). Non négociable : tout le directory est GPL.
  • Privacy provider : même un null_provider si le plugin ne stocke aucune donnée personnelle (Partie 11). Obligatoire depuis le RGPD.
  • Standards de code : moodle-cs (le PHPCS de Moodle) vert, PHPDoc complet, pas de fonctions dépréciées.
  • Tests + CI : une CI moodle-plugin-ci verte est quasi attendue par les reviewers.
  • Documentation : README, CHANGES, chaînes de langue anglaises propres (la traduction viendra via AMOS).
  • Puis le process de review humain (délais de plusieurs semaines, allers-retours) — préparez-vous à itérer.

📚 Aller plus loin : les prérequis officiels sont sur moodledev.io/general/community/plugincontribution  et le checklist de publication. Le détail complet (process, maintenance d’un plugin communautaire, monétisation en écosystème GPL) est en Partie 11.8.


8. Récapitulatif : le cycle de vie complet

Vous avez bouclé la Partie 6 : du premier fichier d’un plugin (6.2) à sa vie en production et sa distribution (ce chapitre). Le fil rouge : Moodle est un système à contrats explicites — de fichiers (par type de plugin) et de cycle de vie (version, upgrade, backup, déploiement). Une fois ces contrats intégrés, développer pour Moodle devient mécanique et prévisible, malgré la taille du système.


✏️ Exercices

Exercice 1 — Bump ou pas bump ? Pour chaque changement, faut-il incrémenter $plugin->version ? (a) corriger une faute dans une chaîne FR ; (b) ajouter une colonne à une table ; (c) ajouter une capability ; (d) modifier un template Mustache ; (e) ajouter une tâche planifiée.

✅ Solution

(a) Non (purge des caches suffit) — (b) Oui (+ upgrade.php + install.xml) — (c) Oui (access.php n’est relu qu’à l’upgrade) — (d) Non (purge suffit) — (e) Oui (tasks.php n’est relu qu’à l’upgrade). Règle : tout ce qui est déclaratif structurel (db/*.php, schéma) ⇒ bump ; le rendu/langue ⇒ purge. En cas de doute, bumper.

Exercice 2 — Supporter 5.1 et 5.2. Votre plugin doit tourner sur Moodle 5.1 et 5.2, mais une fonctionnalité utilise une API apparue en 5.2. Quelle stratégie, et que mettez-vous dans version.php de chaque branche ?

✅ Solution

Stratégie de branches : une branche MOODLE_501_STABLE (sans la fonctionnalité 5.2, requires = version 5.1, supported = [501, 501]) et une branche MOODLE_502_STABLE (avec la fonctionnalité, requires = version 5.2, supported = [502, 502] ou [502, 503]). Les correctifs communs sont écrits sur une branche et cherry-pickés sur l’autre ; la fonctionnalité 5.2 reste uniquement sur la branche 5.2. On publie deux releases sur le directory, chacune ciblant sa version. On évite les if (version >= …) in-code au-delà de très petits écarts.

Exercice 3 — Zip qui échoue. Vous téléchargez votre plugin depuis GitHub (moodle-local_todolist-main.zip) et l’upload via l’interface échoue avec un message peu clair. Pourquoi, et comment produire un zip correct ?

✅ Solution

Le zip GitHub contient un dossier racine moodle-local_todolist-main/ (nom du repo + branche), or Moodle attend un seul dossier racine nommé exactement comme le plugin : todolist/. Il faut renommer ce dossier racine en todolist (et rezipper), ou générer l’archive proprement (ex. via git archive ou la CI) avec todolist/ à la racine. Vérifier aussi que amd/build/ est présent et compilé si le plugin a du JS.

Exercice 4 — Ordonner un déploiement. Remettez dans le bon ordre : purge des caches ; upgrade.php ; mode maintenance ON ; sauvegarde ; déployer le code ; mode maintenance OFF. Justifiez deux contraintes d’ordre.

✅ Solution

Ordre : 1. sauvegarde → 2. maintenance ON → 3. déployer le code → 4. upgrade.php → 5. purge des caches → 6. maintenance OFF. Contraintes : (a) maintenance AVANT upgrade.php — la migration modifie le schéma ; laisser les utilisateurs écrire pendant ce temps crée des incohérences. (b) sauvegarde AVANT tout — sans point de restauration, un upgrade raté est irréversible. (c) bonus : purge APRÈS upgrade (sinon l’ancien code/JS/langue en cache est servi), et maintenance OFF en dernier.

Exercice 5 — Préparer une publication. Un client veut publier votre plugin sur moodle.org. Listez les cinq prérequis à vérifier avant de soumettre.

✅ Solution

(1) Licence GPL v3+ (fichier LICENSE + en-têtes) ; (2) Privacy provider (au minimum null_provider si aucune donnée perso) ; (3) moodle-cs vert + PHPDoc complet, pas de fonctions dépréciées ; (4) CI moodle-plugin-ci verte (matrice versions/PHP/BDD, phpunit/behat) ; (5) documentation (README, chaînes anglaises propres, versions supportées déclarées dans supported). Ensuite seulement, soumettre — et s’attendre à des allers-retours avec les reviewers (détail en Partie 11.8).


🧠 Quiz de révision

Q1. Dans quels cas doit-on incrémenter $plugin->version ?

Réponse

À chaque changement déclaratif structurel que Moodle doit reprendre en compte : schéma (install.xml + upgrade.php), db/access.php, db/tasks.php, services.php, messages.php, hooks.php, et par convention à chaque nouvelle release. Pas nécessaire pour une simple chaîne de langue ou un template (purge des caches suffit). En cas de doute : bumper.

Q2. À quoi servent respectivement requires, supported et dependencies ?

Réponse

requires = version minimale de Moodle (installation refusée en dessous) ; supported = fourchette de branches déclarée (informatif, à ne renseigner que si testé) ; dependencies = autres plugins requis avec leur version minimale (installation bloquée s’ils manquent).

Q3. Décrivez la stratégie de branches git pour supporter plusieurs versions de Moodle.

Réponse

Une branche MOODLE_XYZ_STABLE par version majeure de Moodle supportée (mêmes noms que le core), plus main pour la version la plus récente. Les correctifs communs sont cherry-pickés entre branches ; les fonctionnalités dépendant d’une API récente restent sur la branche correspondante. On publie une release par branche/version.

Q4. Quelle est la procédure de déploiement d’un plugin en production et pourquoi le mode maintenance ?

Réponse

Sauvegarde (base + moodledata + code) → mode maintenance ON → déployer le code (version taguée) → php admin/cli/upgrade.php → purge des caches → maintenance OFF. Le mode maintenance ferme le site pendant la migration de schéma pour éviter que des écritures utilisateur, sur un schéma en cours de modification, ne créent des incohérences.

Q5. Comment prépare-t-on un plugin aux deux upgrades annuels de Moodle ?

Réponse

Lire les API change / upgrade notes de la nouvelle version, tester tôt via moodle-plugin-ci contre la RC sur une matrice (Moodle × PHP × BDD), corriger les dépréciations pendant le sursis, puis publier une release compatible (nouvelle branche stable + supported mis à jour). Ne jamais figer une instance pour éviter les mises à jour.

Fin de la Partie 6. Vous savez désormais construire (local, block, mod, et tous les autres types), versionner, distribuer et déployer un plugin, et le maintenir à travers les versions de Moodle. Le socle développeur est complet.

Partie suivante : Partie 7 — Frontend : JavaScript, React et Tailwind. On quitte le PHP pour le navigateur : Mustache en profondeur, modules AMD/ES6, l’écosystème core/*, puis intégrer React 19 et Tailwind dans un plugin sans casser la plateforme — le terrain le plus familier pour un dev Next.js, avec quelques surprises.