Skip to content

Publishing a Module ​

Introduction ​

A module is three ordinary Composer packages. Publishing it is publishing those packages — to Packagist, to a private Composer repository, or as Git repositories a site adds itself. Sites then install it like any kitloom module: Installing Modules.

kitloom's own packages

kitloom's packages are not on Packagist: they come from the kitloom Composer repository, https://packages.kitloom.dev, all at one version (^1.0 today). A site that installs your module has that repository already — it needs it for kitloom itself.

Before you publish ​

Names ​

kitloom:make-module --vendor=acme already named everything after your vendor:

text
acme/reviews            Acme\Reviews\            config acme-reviews
acme/reviews-filament   Acme\Reviews\Filament\
acme/reviews-nova       Acme\Reviews\Nova\

The admin packages must stay <domain package>-filament and <domain package>-nova and require the domain package directly: that is how the Modules screen finds a module's admin and switches it off together with the module.

Requirements ​

The generated packages require the kitloom packages at ^1.0, and the admin packages require your domain package with @dev, which works only through a path repository. Before publishing, tag your packages, require your domain package by version, and make sure the Laravel range covers what sites run — the skeletons are on Laravel 13:

json
"require": {
    "php": "^8.4",
    "illuminate/support": "^12.0|^13.0",
    "acme/reviews": "^1.0",
    "kitloom/access": "^1.0",
    "kitloom/settings-filament": "^1.0",
    "kitloom/wp-schema-filament": "^1.0",
    "filament/filament": "^5.0"
}

Require every kitloom package you use classes from — not only the one that happens to bring the others along. A package that is not required can be switched off on the Modules screen, or be missing on another site, and your module breaks there. In the kitloom repository, php tools/check-package-deps.php checks exactly this.

The Modules screen ​

extra.kitloom.module in the domain package's composer.json is what lists the package as a module:

json
"extra": {
    "kitloom": {
        "module": {
            "name": "Reviews",
            "description": "Book reviews with ratings and pages of their own."
        }
    }
}

Only the domain package declares it; without a description the screen shows the package's own. group and default place a module in kitloom:install's questions on a new site (the generator writes "group": "Content" and "default": false). The screen shows the name, the description and the version Composer installed; it says what keeps a module from being switched off and what has to be switched on first. While your module is on, the modules it requires cannot be switched off; switching yours off switches its admin packages off too. See Enabling & Disabling.

License ​

Pick a license and put it both in composer.json ("license": "MIT", or "proprietary" for a paid module) and in a LICENSE.md file at the package root. The generator writes proprietary, as kitloom's own packages are; change it to what yours is.

A module of yours requires kitloom packages, and every kitloom package is commercial: whoever installs your module needs a kitloom license of their own, whatever license your module carries. Say so in its README.

README ​

The domain package's README is the module's How it works page in both admins: the Modules screen serves it, and the module's menu links to it last. Write it for the person who configures the module, not only for the developer. The generated README has the sections to keep:

  • What is inside — what the module does, and where its data lives: tables, options, meta keys.
  • What the application overrides — the model in the registry, the config switches (acme-reviews.filament.register, acme-reviews.nova.register) and their publish tag.
  • Tests — the testsuite to run.

The admin packages have short READMEs of their own: the section, the settings page, the permission.

Tests and checks ​

The tests run on a bare skeleton — no code of a particular site assumed; see Testing. Run Pint and your static analysis on the packages; a module from the generator passes PHPStan with Larastan at level 8, the level kitloom's own packages are checked at.

Versions ​

Version the three packages together: the admin packages require ^1.0 of the domain package, and a change in what the domain package gives its admins is a new major version for all three.

What is a breaking change for a module:

  • a renamed or removed meta key, option or table column — sites have data under the old name. Read the old one, write the new one, and keep reading the old one for a major version;
  • a changed page part: its fields or the keys of its toArray() — themes rely on them;
  • a renamed permission — roles were granted it on sites;
  • a renamed agent tool or a changed argument of one — agents are told about them;
  • a changed contract, tag, REST route or shortcode others use.

Publishing ​

bash
# Each package in a repository of its own, tagged:
git tag v1.0.0 && git push --tags
# then submit the repository at packagist.org
json
{
    "repositories": [
        { "type": "composer", "url": "https://packages.acme.dev" }
    ]
}
json
{
    "repositories": [
        { "type": "vcs", "url": "https://git.acme.dev/acme/reviews.git" },
        { "type": "vcs", "url": "https://git.acme.dev/acme/reviews-filament.git" }
    ]
}

Keeping the three packages in one repository while you develop is fine — that is how kitloom itself is built: one repository, every top-level directory a package, installed into the skeletons as symlinked path repositories. Split them into a repository each for Packagist, or serve them from a private Composer repository that reads the monorepo.

Installing it on a site ​

bash
composer require acme/reviews acme/reviews-filament
php artisan migrate

The module plugs itself in on the next request. Nothing else is needed — if it is, the module is not finished: see the rules.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]