Module Development

Scaffold Commands

Artisan generators for every extension type — modules, form fields, PropTypes, props, and builder pages.

Scaffold Commands

Tagixo ships seven Artisan generator commands that create the boilerplate PHP classes needed to extend the builder. Every command follows the same conventions for output path and namespace resolution, and all share a common set of options via the ResolvesScaffoldTarget concern.


Scaffolding configuration

By default, generated files land under app/tagixo/ and the namespace is derived automatically from that path (each segment is ucfirst-ed, so app/tagixo becomes App\Tagixo). You can change the defaults project-wide in config/tagixo.php:

'scaffolding' => [
    'path'      => 'app/tagixo',  // relative to base_path()
    'namespace' => null,           // null = auto-derive from path segments
],

All seven commands share these options that control where files are written:

Option Description
--path= Override the base path (must be used together with --namespace)
--namespace= Override the base namespace (must be used together with --path)
--package= Absolute path to a Composer package directory; reads its composer.json autoload.psr-4 and writes inside that package's source tree
--force / -f Overwrite the file if it already exists

When --path and --namespace are both given, the generated class goes to {path}/{TypeSuffix}/{ClassName}.php under the specified namespace. When --package is given, the command reads the package's composer.json, resolves its single PSR-4 entry, and places all generated files inside the package source directory — useful when building a redistributable Tagixo extension.


make:tagixo-module

Create a new builder module — a self-contained content block that appears in the module catalogue and can be dragged into canvas columns.

php artisan make:tagixo-module <name> [--context=page] [--icon=heroicon-o-cube] [--path=] [--namespace=] [--package=] [--force]

Additional options:

Option Short Default Description
--context -c page Comma-separated contexts the module is available in (page, mail, pdf)
--icon -i heroicon-o-cube Heroicon name shown in the module catalogue

The command creates two files:

  1. {path}/Modules/{Name}.php — the module PHP class, extending Ccast\Tagixo\Components\Module.
  2. resources/views/tagixo/modules/{kebab-name}.blade.php — the Blade view used for rendering the module on the front-end.

Generated class example (php artisan make:tagixo-module HeroBanner):

namespace App\Tagixo\Modules;

use Ccast\Tagixo\Components\Module;
use Ccast\Tagixo\Core\ModuleDefinition;
use Ccast\Tagixo\Core\Props\TextProp;

class HeroBanner extends Module
{
    public static function getLabel(): string { return __('Hero Banner'); }
    public static function getIcon(): string  { return 'heroicon-o-cube'; }

    public static function define(): ModuleDefinition
    {
        return ModuleDefinition::make()
            ->content(
                TextProp::make('text')
                    ->setLabel(__('Text'))
                    ->default(__('Hero Banner')),
            );
    }
}

After creation the command prints the config/tagixo.php modules array snippet needed to register the class.


make:tagixo-prop-type

Create a custom PropType — a named group of Props that appears as a panel in the builder design drawer.

php artisan make:tagixo-prop-type <name> [--path=] [--namespace=] [--package=] [--force]

Generates {path}/PropTypes/{Name}.php, extending Ccast\Tagixo\Core\PropTypes\AbstractPropType. You implement key(), label(), tab(), hasCss(), schema(), and toCss().

Generated class example:

namespace App\Tagixo\PropTypes;

use Ccast\Tagixo\Core\PropTypes\AbstractPropType;

class ShadowPropType extends AbstractPropType
{
    public function key(): string   { return 'shadow_prop_type'; }
    public function label(): string { return __('Shadow Prop Type'); }
    public function tab(): string   { return 'design'; }
    public function hasCss(): bool  { return false; }

    public function schema(): array
    {
        return [
            // \App\Tagixo\Props\YourProp::make('value')->setLabel(__('Value')),
        ];
    }

    public function toCss(array $values): string { return ''; }
}

Use this when you need to bundle several related props under a single named group and attach them to modules via ->design() or ->propType().


make:tagixo-prop

Create a custom Prop — a single design control included in a PropType's schema().

php artisan make:tagixo-prop <name> [--path=] [--namespace=] [--package=] [--force]

Generates {path}/Props/{Name}.php, extending Ccast\Tagixo\Core\Props\AbstractProp. You implement widget() (the Vue widget identifier used on the builder front-end), widgetConfig(), and toCss().

Generated class example:

namespace App\Tagixo\Props;

use Ccast\Tagixo\Core\Props\AbstractProp;

class CustomSliderProp extends AbstractProp
{
    public function widget(): string          { return 'custom-slider-prop'; }
    public function widgetConfig(): array     { return $this->baseConfig(); }
    public function toCss(mixed $value): string { return ''; }
}

Props are not registered independently. They are consumed inside a PropType's schema() array and discovered implicitly from there.


make:tagixo-form-field

Create a custom form field module — a draggable field element available inside the form builder canvas.

php artisan make:tagixo-form-field <name> [--icon=heroicon-o-pencil-square] [--field-type=text] [--path=] [--namespace=] [--package=] [--force]

Additional options:

Option Default Description
--icon / -i heroicon-o-pencil-square Heroicon name shown in the form builder catalogue
--field-type text HTML input type identifier rendered by the form engine

Generates {path}/FormFields/{Name}.php, extending Ccast\Tagixo\FormBuilder\FormModule. The generated stub sets ->contexts(['form']) automatically so the field only appears inside the form builder.

Generated class example:

namespace App\Tagixo\FormFields;

use Ccast\Tagixo\FormBuilder\FormModule;
use Ccast\Tagixo\Core\ModuleDefinition;

class VatFieldModule extends FormModule
{
    public static function getLabel(): string     { return __('Vat Field Module'); }
    public static function getIcon(): string      { return 'heroicon-o-pencil-square'; }
    public static function getFieldType(): string  { return 'text'; }
    public static function getTypeId(): string    { return 'vat-field-module'; }

    public static function define(): ModuleDefinition
    {
        return ModuleDefinition::make()
            ->tab('content', __('Content'), [
                TextProp::make('name')->setLabel(__('Field Name')),
                TextProp::make('label')->setLabel(__('Label'))->default(__('Vat Field Module')),
                static::columnSpanProp(),
            ])
            ->tab('validation', __('Validation'), [...static::commonValidationProps()])
            ->design('typography', 'spacing')
            ->contexts(['form'])
            ->meta(['isFormField' => true])
            ->canvas('cards');
    }
}

make:tagixo-form-hook

Create a form lifecycle hook — a server-side handler invoked after a form submission (send email, call a webhook, write to an external system, etc.).

php artisan make:tagixo-form-hook <name> [--icon=heroicon-o-bolt] [--path=] [--namespace=] [--package=] [--force]

Additional options:

Option Default Description
--icon / -i heroicon-o-bolt Heroicon name shown in the form hooks list in the admin

Generates {path}/FormHooks/{Name}.php, extending Ccast\Tagixo\FormBuilder\Hooks\FormHook. The handle() method receives the submitted form data and the form's configuration array.

Generated class example:

namespace App\Tagixo\FormHooks;

use Ccast\Tagixo\FormBuilder\Hooks\FormHook;

class NotifySlackHook extends FormHook
{
    public static function getKey(): string   { return 'notify-slack-hook'; }
    public static function getLabel(): string { return __('Notify Slack Hook'); }
    public static function getIcon(): string  { return 'heroicon-o-bolt'; }

    public function handle(array $formData, array $submitConfig): void
    {
        // dispatch Slack notification
    }
}

After creation the command prints the registration snippet for config/tagixo.php under the hooks key.


make:tagixo-form-wrapper

Create a form wrapper module — a structural container (e.g. a multi-step wizard step) that wraps other form fields inside the form builder canvas.

php artisan make:tagixo-form-wrapper <name> [--icon=heroicon-o-rectangle-group] [--field-type=wrapper] [--path=] [--namespace=] [--package=] [--force]

Additional options:

Option Default Description
--icon / -i heroicon-o-rectangle-group Heroicon name
--field-type wrapper Type identifier used by the form renderer

Generates {path}/FormWrappers/{Name}.php, extending Ccast\Tagixo\FormBuilder\FormModuleWrapper.

Generated class example:

namespace App\Tagixo\FormWrappers;

use Ccast\Tagixo\FormBuilder\FormModuleWrapper;
use Ccast\Tagixo\Core\ModuleDefinition;

class WizardStepWrapper extends FormModuleWrapper
{
    public static function getLabel(): string     { return __('Wizard Step Wrapper'); }
    public static function getIcon(): string      { return 'heroicon-o-rectangle-group'; }
    public static function getFieldType(): string  { return 'wrapper'; }
    public static function getTypeId(): string    { return 'wizard-step-wrapper'; }

    public static function define(): ModuleDefinition
    {
        return ModuleDefinition::make()
            ->tab('content', __('Content'), [])
            ->contexts(['form'])
            ->canvas('cards');
    }
}

make:tagixo-plugin

Create a Tagixo plugin class — the entry point for a package that bundles modules, prop types, form hooks, and other extensions under a single identifier.

php artisan make:tagixo-plugin <name> [--path=] [--namespace=] [--package=] [--force]

Generates {path}/Plugins/{Name}.php, extending Ccast\Tagixo\TagixoPluginBase. The boot() method receives the Tagixo singleton and is where you call registerModule(), registerPropType(), etc.

Generated class example:

namespace App\Tagixo\Plugins;

use Ccast\Tagixo\TagixoPluginBase;
use Ccast\Tagixo\Tagixo;

// Implement HasPlugin to expose a Filament or Primix sub-plugin that gets
// auto-registered by tagixo-filament / tagixo-primix with no extra user code.
class EcommercePlugin extends TagixoPluginBase /* implements HasPlugin */
{
    public function getId(): string { return 'ecommerce-plugin'; }

    public function boot(Tagixo $tagixo): void
    {
        // $tagixo->registerModule(\App\Tagixo\Modules\ProductCardModule::class);
        // $tagixo->registerPropType(\App\Tagixo\PropTypes\PricePropType::class);
    }

    // Uncomment to expose a Filament or Primix admin panel plugin:
    // tagixo-filament / tagixo-primix will auto-register it — no user action needed.
    // public function getPlugin(): object
    // {
    //     return \App\Tagixo\AdminPlugin::make();
    // }
}

After creation the command prints the ServiceProvider registration call:

\Ccast\Tagixo\Facades\Tagixo::plugin(\App\Tagixo\Plugins\EcommercePlugin::make());

Command reference summary

Command Extends Output directory suffix
make:tagixo-module Ccast\Tagixo\Components\Module Modules/
make:tagixo-prop-type Ccast\Tagixo\Core\PropTypes\AbstractPropType PropTypes/
make:tagixo-prop Ccast\Tagixo\Core\Props\AbstractProp Props/
make:tagixo-form-field Ccast\Tagixo\FormBuilder\FormModule FormFields/
make:tagixo-form-hook Ccast\Tagixo\FormBuilder\Hooks\FormHook FormHooks/
make:tagixo-form-wrapper Ccast\Tagixo\FormBuilder\FormModuleWrapper FormWrappers/
make:tagixo-plugin Ccast\Tagixo\TagixoPluginBase Plugins/

See also