Tagixo Plugin
Once your custom modules, PropTypes, or Props are stable, packaging them as a Composer plugin lets you reuse them across projects and ship updates independently. Both ccast/tagixo-filament and ccast/tagixo-primix are themselves Tagixo plugins — their service providers are real-world reference implementations.
Why bundle as a plugin
- Reuse across multiple projects without copy-paste
- Version independently with SemVer; pin minimum Tagixo version explicitly
- Distribute via Packagist or a private Composer repo
- Override per project through publishable views/assets
Plugin anatomy
A Tagixo plugin is a normal Composer package with three required pieces:
- A
composer.jsonwithautoload.psr-4mapping andextra.laravel.providersfor auto-discovery - A Laravel service provider that registers modules / PropTypes / Props with the core
- The actual extension classes (modules, PropTypes, props), optionally with companion Blade views and frontend assets
Step-by-step
1. Initialize the package
mkdir tagixo-charts && cd tagixo-charts
composer init --name=acme/tagixo-charts --type=library
Edit composer.json to declare PSR-4 and the service provider:
{
"name": "acme/tagixo-charts",
"description": "Chart modules for Tagixo Visual Builder",
"type": "library",
"license": "MIT",
"require": {
"php": "^8.2",
"ccast/tagixo": "^1.0"
},
"autoload": {
"psr-4": { "Acme\\TagixoCharts\\": "src/" }
},
"extra": {
"laravel": {
"providers": [
"Acme\\TagixoCharts\\AcmeTagixoChartsServiceProvider"
]
}
}
}
2. Scaffold the directory layout
tagixo-charts/
├── composer.json
├── src/
│ ├── AcmeTagixoChartsServiceProvider.php
│ ├── Modules/
│ ├── PropTypes/
│ └── Props/
├── resources/
│ └── views/
└── dist/ (optional, if shipping Vue widgets)
3. Scaffold extensions INTO the plugin
The make:tagixo-* commands support a --package= mode that reads the plugin's composer.json and writes files at the correct PSR-4 location:
# From your dev Laravel app, pointing at the plugin repo:
php artisan make:tagixo-module BarChart --package=../tagixo-charts --context=page
php artisan make:tagixo-prop-type ChartLegendPropType --package=../tagixo-charts
The command prints the package-mode registration snippet — paste it into the plugin's service provider:
Register in your package's ServiceProvider::boot():
\Ccast\Tagixo\Facades\Tagixo::registerModule(\Acme\TagixoCharts\Modules\BarChart::class);
4. Wire the service provider
<?php
namespace Acme\TagixoCharts;
use Ccast\Tagixo\Facades\Tagixo;
use Illuminate\Support\ServiceProvider;
class AcmeTagixoChartsServiceProvider extends ServiceProvider
{
public function register(): void
{
// Light setup — bindings, singletons. Keep this lean.
}
public function boot(): void
{
Tagixo::registerModules([
\Acme\TagixoCharts\Modules\BarChart::class,
\Acme\TagixoCharts\Modules\PieChart::class,
\Acme\TagixoCharts\Modules\LineChart::class,
]);
Tagixo::registerPropTypes([
\Acme\TagixoCharts\PropTypes\ChartLegendPropType::class,
\Acme\TagixoCharts\PropTypes\ChartAxisPropType::class,
]);
$this->loadViewsFrom(__DIR__.'/../resources/views', 'acme-tagixo-charts');
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/acme-tagixo-charts'),
], 'acme-tagixo-charts-views');
}
}
Frontend assets in a plugin
If your plugin ships custom Vue widgets (for custom Props that don't reuse a built-in widget), follow the same publish-dist/ pattern Tagixo core uses — no @vite() in consumer apps.
- Build the bundle ahead of release with the plugin's own
vite.config.js. Produce adist/directory. - Ship the
dist/directory inside the package. - Register a publish tag in the service provider:
$this->publishes([
__DIR__.'/../dist' => public_path('vendor/acme-tagixo-charts'),
], 'acme-tagixo-charts-assets');
- Document the consumer step:
php artisan vendor:publish --tag=acme-tagixo-charts-assets --forceafter install and after every plugin upgrade. - Reference assets from your Blade with
asset('vendor/acme-tagixo-charts/widgets.js').
If your plugin reuses only built-in widgets, you can skip frontend assets entirely.
Versioning
- Use SemVer. Bumps to module type IDs or saved-JSON shape are breaking changes — major version bump.
- Pin
requireto the minimum Tagixo version you need:"ccast/tagixo": "^1.0"(or wider if you actually support multiple majors). - Keep a
CHANGELOG.md. Mark breaking changes prominently.
Distribution
- Public: tag a release, push to GitHub, submit to Packagist. Consumer installs with
composer require acme/tagixo-charts. - Private: host on a private Composer repo (Satis, Cloudsmith, Packagist private repos) and add it to the consumer's
composer.jsonrepositoriesarray.
Multi-tenant note
Tagixo::registerModules() accumulates registrations for the process lifetime. For per-tenant module sets:
- Register a default set at
boot()for all tenants - Add per-tenant extras in a middleware that runs after tenant context is resolved
The registry is NOT request-scoped by default — it persists across requests in long-running processes (Octane, Roadrunner). Be careful with conditional registration that could leak state.
Testing your plugin
Use Orchestra Testbench to spin up a minimal Laravel app and load your service provider:
namespace Acme\TagixoCharts\Tests;
use Orchestra\Testbench\TestCase;
use Acme\TagixoCharts\AcmeTagixoChartsServiceProvider;
class RegistrationTest extends TestCase
{
protected function getPackageProviders($app): array
{
return [
\Ccast\Tagixo\TagixoServiceProvider::class,
AcmeTagixoChartsServiceProvider::class,
];
}
public function test_modules_are_registered(): void
{
$modules = app(\Ccast\Tagixo\Tagixo::class)->getCustomModules();
$this->assertContains(\Acme\TagixoCharts\Modules\BarChart::class, $modules);
}
}
Reference implementations
The two official SDK plugins are full-featured Tagixo plugins:
ccast/tagixo-filament—tagixo-filament/src/TagixoFilamentServiceProvider.phpccast/tagixo-primix—tagixo-primix/src/TagixoPrimixServiceProvider.php
Both wire modules, PropTypes, custom commands, and publishable assets. Use them as templates when in doubt.