Essayez sans attendre l'hébergement proposé par WordPress
-15% sur le premier mois avec le code 2025PRESS15AFF

Essayer maintenant

Créer un plugin WordPress distribué sur Packagist avec Composer : workflow professionnel de A à Z

Distribuer un plugin WordPress via Composer et Packagist, c’est le genre de workflow qui change vraiment la façon dont on gère ses projets — fini les copier-coller manuels et les mises à jour hasardeuses. Pourtant, entre la configuration du composer.json, le versioning sémantique et l’intégration avec des outils comme Bedrock, on peut vite se retrouver perdu si on n’a jamais mis en place ce type d’architecture. Dans cet article, on va parcourir le processus de A à Z : de la préparation du plugin jusqu’à sa consommation dans un projet réel, avec des exemples concrets à chaque étape.

Préparer son plugin WordPress pour Composer et Packagist

Avant de publier quoi que ce soit sur Packagist, il faut que votre plugin soit structuré correctement. Ce n’est pas une contrainte arbitraire : c’est ce qui rend votre code maintenable, partageable et professionnel. On va voir ça étape par étape.

Structurer son plugin avec une architecture Composer-ready

La première erreur qu’on fait souvent, c’est de mettre tous ses fichiers PHP à la racine du plugin. Ça fonctionne… mais ça ne scale pas. Pour qu’un plugin soit vraiment compatible Composer, on privilégie une arborescence claire dès le départ :

mon-plugin/
├── src/
│   ├── Admin/
│   ├── Frontend/
│   └── Core/
├── includes/         ← fichiers de compatibilité / bootstrap
├── assets/
├── templates/
├── vendor/           ← généré par Composer, ne jamais committer !
├── composer.json
├── composer.lock
├── .gitignore
└── mon-plugin.php    ← fichier principal du plugin

Le dossier src/ accueille toute la logique métier organisée par namespace. Le dossier includes/ peut servir pour les fichiers de compatibilité ou les hooks d’initialisation qui ne rentrent pas dans la logique PSR-4. Et vendor/ ? On y touche jamais directement — Composer s’en charge.

Parlons du .gitignore : c’est un point critique que beaucoup négligent. Vous devez absolument exclure le dossier vendor/ de votre dépôt Git :

/vendor/
composer.lock   ← à discuter selon les cas (voir plus bas)

Pourquoi exclure vendor/ ? Parce que c’est le rôle de Composer de le reconstruire. Committer vendor/, c’est alourdir inutilement votre dépôt et créer de futurs conflits. Pour composer.lock, la convention dans le monde des librairies distribuées est de l’exclure aussi (contrairement aux projets applicatifs).

Créer et configurer le fichier composer.json

C’est le cœur du dispositif. Le composer.json décrit votre plugin pour Packagist et pour Composer. Voici un exemple complet et commenté :

{
    "name": "acme-vendor/mon-plugin-wp",
    "description": "Un plugin WordPress qui fait des choses formidables",
    "type": "wordpress-plugin",
    "license": "GPL-2.0-or-later",
    "version": "1.0.0",
    "authors": [
        {
            "name": "Etienne",
            "email": "etienne@dev-wp.fr",
            "homepage": "https://dev-wp.fr"
        }
    ],
    "require": {
        "php": ">=7.4",
        "composer/installers": "^2.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^9.0"
    },
    "autoload": {
        "psr-4": {
            "AcmeVendor\\MonPlugin\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "AcmeVendor\\MonPlugin\\Tests\\": "tests/"
        }
    },
    "extra": {
        "installer-name": "mon-plugin-wp"
    }
}

Quelques points importants à retenir sur les champs :

  • name : format obligatoire vendor/package-name, tout en minuscules, avec des tirets. C’est ce que Packagist utilise comme identifiant unique.
  • type : wordpress-plugin permet à composer/installers de placer automatiquement le plugin dans wp-content/plugins/.
  • license : utilisez GPL-2.0-or-later pour rester compatible avec WordPress.
  • require : déclarez composer/installers ici si vous voulez que l’installation automatique dans le bon dossier WordPress fonctionne.
  • extra.installer-name : permet de contrôler le nom du dossier dans wp-content/plugins/.

Le nommage du vendor sur Packagist mérite une attention particulière : il doit correspondre à votre compte Packagist (ou organisation). Une fois publié, vous ne pouvez pas le changer facilement. Choisissez-le avec soin.

Définir l’autoloading PSR-4 et les dépendances

PSR-4, c’est la norme d’autoloading moderne en PHP. Le principe est simple : Composer va faire correspondre vos namespaces à des dossiers, automatiquement, sans que vous ayez besoin de require ou include partout.

Concrètement, avec la configuration qu’on a définie :

"autoload": {
    "psr-4": {
        "AcmeVendor\\MonPlugin\\": "src/"
    }
}

…la classe AcmeVendor\MonPlugin\Admin\SettingsPage sera chargée depuis le fichier src/Admin/SettingsPage.php. C’est automatique, propre, et ça évite les require_once en cascade qu’on voit encore trop souvent dans les vieux plugins.

Un exemple de classe qui exploite cet autoloading :

<?php

namespace AcmeVendor\MonPlugin\Admin;

class SettingsPage {

    public function __construct() {
        add_action( 'admin_menu', [ $this, 'register_menu' ] );
    }

    public function register_menu(): void {
        add_options_page(
            'Mon Plugin',
            'Mon Plugin',
            'manage_options',
            'mon-plugin-settings',
            [ $this, 'render' ]
        );
    }

    public function render(): void {
        echo '<div class="wrap"><h1>Réglages Mon Plugin</h1></div>';
    }
}

Et dans le fichier principal du plugin, on initialise tout ça en chargeant l’autoloader généré par Composer :

<?php
/**
 * Plugin Name: Mon Plugin WP
 * Description: Un plugin distribué via Composer et Packagist
 * Version: 1.0.0
 * License: GPL-2.0-or-later
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

require_once __DIR__ . '/vendor/autoload.php';

new \AcmeVendor\MonPlugin\Admin\SettingsPage();

Après chaque modification du composer.json, pensez à lancer composer dump-autoload pour régénérer le fichier d’autoloading. C’est une étape qu’on oublie… et qu’on regrette !

Publier et versionner son plugin sur Packagist

Une fois votre composer.json bien configuré et votre dépôt Git en place, on passe à l’étape concrète : publier sur Packagist. C’est là que le workflow devient vraiment professionnel.

Créer un compte et soumettre son dépôt sur Packagist

Rendez-vous sur packagist.org et créez un compte (la connexion via GitHub est possible et franchement plus pratique). Une fois connecté, cliquez sur le bouton « Submit » en haut à droite.

Packagist va vous demander l’URL de votre dépôt GitHub ou GitLab. Collez-la, validez, et c’est tout… ou presque. Packagist va automatiquement détecter votre composer.json et extraire les informations : nom du paquet, description, dépendances. Si la détection échoue, vérifiez que votre fichier est bien à la racine du dépôt et que le champ name respecte bien le format vendor/package-name.

Capture d’écran suggérée : l’interface de soumission avec l’URL du dépôt et la prévisualisation des métadonnées détectées.

Gérer le versioning sémantique avec les tags Git

Le versioning sémantique (SemVer), c’est le système MAJOR.MINOR.PATCH. Simple en théorie, mais concrètement pour un plugin WordPress, ça donne quoi ?

  • PATCH (ex: 1.0.1) : correction de bug, mise à jour de sécurité. Rien de cassé, rien de nouveau.
  • MINOR (ex: 1.1.0) : nouvelle fonctionnalité ajoutée, rétrocompatible. Vos utilisateurs peuvent mettre à jour sans crainte.
  • MAJOR (ex: 2.0.0) : breaking change. Vous avez modifié une API publique, supprimé une fonction, changé la structure des hooks… Les projets consommateurs doivent adapter leur code.

Pour créer un tag Git et le pousser sur votre dépôt :

git tag -a v1.0.0 -m "First stable release"
git push origin v1.0.0

Et voilà, Packagist détecte ce tag et crée automatiquement la version 1.0.0 de votre paquet. Chaque tag Git devient une version installable via Composer. C’est aussi simple que ça.

Automatiser les mises à jour avec le webhook GitHub/GitLab

Par défaut, Packagist ne vérifie pas en permanence si votre dépôt a changé. Il faut donc mettre en place un webhook pour que chaque push ou nouveau tag déclenche une réindexation automatique.

Sur GitHub :

  1. Allez dans Settings → Webhooks → Add webhook de votre dépôt
  2. Payload URL : https://packagist.org/api/github?username=VOTRE_USERNAME
  3. Content type : application/json
  4. Ajoutez votre token API Packagist (disponible dans votre profil) dans les headers ou en paramètre
  5. Sélectionnez les événements « Push » et « Create » (pour les tags)

Sur GitLab, le principe est identique via Settings → Integrations. Une fois le webhook configuré, chaque git push ou nouveau tag met à jour Packagist en quelques secondes. Plus besoin de se connecter manuellement pour forcer la synchronisation.

Capture d’écran suggérée : la page de configuration du webhook dans GitHub, avec les champs remplis.

Gérer les versions stables, bêta et les contraintes de version

Côté projet consommateur, quand un développeur veut installer votre plugin via Composer, il va spécifier une contrainte de version dans son composer.json. Voici les plus courantes :

  • ^1.0 : accepte toutes les versions >=1.0.0 et <2.0.0 (le plus courant, recommandé)
  • ~1.2 : accepte >=1.2.0 et <1.3.0 (plus restrictif)
  • 1.0.* : uniquement les patches de la version 1.0
  • @beta : autorise l’installation des versions bêta (à éviter en production)

Pour publier une version bêta, taguez votre dépôt avec un suffixe explicite :

git tag -a v1.1.0-beta.1 -m "Beta release for v1.1.0"
git push origin v1.1.0-beta.1

Packagist va bien reconnaître ce tag comme une version instable. Par défaut, composer require n’installe pas les versions bêta sauf si le projet consommateur a "minimum-stability": "beta" dans son composer.json. Donc pas de risque d’imposer une version instable à vos utilisateurs par inadvertance.

Bon à savoir : la branche main (ou master) est accessible sous l’alias dev-main dans Composer. C’est utile pendant le développement, mais en production, on s’en tient aux tags.

Intégrer le plugin via Composer dans un projet WordPress

On a publié notre plugin sur Packagist, les tags Git sont en place, les webhooks tournent… super. Maintenant, voyons comment tout ça s’utilise côté projet. C’est finalement là que la magie opère vraiment.

Installer le plugin avec composer require et le configurer avec WPackagist

La commande de base, vous la connaissez déjà :

composer require vendor/mon-plugin

Simple. Efficace. Mais dans un projet WordPress réel, c’est rarement la seule dépendance. On a souvent d’autres plugins à gérer — et c’est là que WPackagist entre en jeu.

WPackagist est un dépôt Composer qui miroir l’intégralité du répertoire officiel WordPress. Il permet d’installer des plugins du répertoire via Composer, avec la notation wpackagist-plugin/nom-du-plugin. Concrètement, vos deux sources (Packagist pour votre plugin custom, WPackagist pour les plugins standards) coexistent sans problème dans le même composer.json.

Voici un exemple complet de composer.json pour un projet WordPress :

{
  "name": "mon-agence/mon-projet-wp",
  "type": "project",
  "require": {
    "php": ">=8.1",
    "composer/installers": "^2.0",
    "vendor/mon-plugin": "^1.2",
    "wpackagist-plugin/contact-form-7": "^5.8",
    "wpackagist-theme/twentytwentyfour": "*"
  },
  "repositories": [
    {
      "type": "composer",
      "url": "https://wpackagist.org",
      "only": [
        "wpackagist-plugin/*",
        "wpackagist-theme/*"
      ]
    }
  ],
  "extra": {
    "installer-paths": {
      "web/app/plugins/{$name}/": [
        "type:wordpress-plugin"
      ],
      "web/app/themes/{$name}/": [
        "type:wordpress-theme"
      ],
      "web/app/mu-plugins/{$name}/": [
        "type:wordpress-muplugin"
      ]
    }
  },
  "scripts": {
    "post-install-cmd": [
      "php artisan optimize:clear || true",
      "echo 'Installation terminée !'"
    ],
    "post-update-cmd": [
      "@post-install-cmd"
    ]
  },
  "config": {
    "allow-plugins": {
      "composer/installers": true
    }
  }
}

Le point clé ici, c’est le package composer/installers. C’est lui qui lit le champ "type": "wordpress-plugin" de votre composer.json de plugin et qui force l’installation dans le bon répertoire (wp-content/plugins/ ou web/app/plugins/ selon votre structure). Sans lui, Composer déposerait tout dans vendor/ — ce qui ne fonctionnerait pas du tout pour WordPress.

Et si vous utilisez Bedrock (le boilerplate WordPress de Roots), bonne nouvelle : tout ce workflow est nativement supporté. Bedrock est justement conçu autour de Composer et de cette structure installer-paths. Votre plugin custom publié sur Packagist s’intégrera sans friction.

Quelques bonnes pratiques à garder en tête :

  • Committez toujours composer.lock : il garantit que toute l’équipe (et votre CI/CD) installe exactement les mêmes versions. C’est votre filet de sécurité.
  • N’ajoutez jamais vendor/ au dépôt : ajoutez-le à votre .gitignore. Idem pour wp-content/plugins/ si tout est géré par Composer.
  • Profitez des scripts Composer : post-install-cmd et post-update-cmd permettent d’automatiser des tâches après installation (vider le cache, lancer des migrations, générer des assets…). Un vrai gain de temps en équipe.

Bon, et pour la contrainte de version côté projet, on en a parlé dans la section précédente — mais pour rappel, préférez "^1.2" plutôt que "*" pour éviter les mauvaises surprises lors d’une mise à jour majeure.