How to Create a Custom Seeder

Understanding Zero Seeding Architecture

Zero CMS features a highly scalable, decoupled hybrid seeding system combining Declarative PHP Array Datasets (defining static content and configurations) and Procedural OOP Seeder Classes (running complex dynamic loops, generating fresh UUIDv7 keys, mapping file streams, and creating randomized e-commerce/community transaction histories).

1. Declaring a PHP Blueprint Dataset

Instead of fragile and slow JSON templates, Zero CMS utilizes compiled, high-performance native PHP array files. These files live under the DemoGenerator presets directory (e.g. src/Modules/DemoGenerator/Seeders/corporate.php) and return a clean array configuration directly. Blueprints can embed dynamic environmental variables natively:

Sample PHP Seeder Preset Blueprint

Sample PHP Seeder Preset Blueprint php
<?php
// src/Modules/DemoGenerator/Seeders/my-preset.php
$domain = parse_url(Env::get('BASE_URL', 'http://localhost'), PHP_URL_HOST) ?: 'localhost';

return [
    'sites' => [
        [
            'id' => '019fb176-1f1e-7799-b829-c2c530a8840a',
            'name' => 'My New Showcase',
            'domain' => $domain,
            'theme' => 'default',
            'enabled_modules' => ['blog']
        ]
    ],
    'pages' => [
        [
            'title' => 'Home',
            'slug' => '',
            'status' => 'published',
            'site_domain' => $domain,
        ]
    ]
];

2. Creating a Dynamic OOP Seeder Class

For complex e-commerce catalogs, nested blog commenting grids, or dynamic records, implement a dynamic seeder class implementing Zero\Interfaces\SeederInterface (located under src/Modules/[ModuleName]/Seeders/):

Sample OOP Modular Seeder Class

Sample OOP Modular Seeder Class php
<?php
namespace Zero\Modules\MyModule\Seeders;

use Exception;
use Zero\Core\App;
use Zero\Core\Env;
use Zero\Database\DB;
use Zero\Interfaces\BlockHelperInterface;
use Zero\Interfaces\Controller;
use Zero\Interfaces\Job as JobInterface;
use Zero\Interfaces\Model;
use Zero\Interfaces\SeederInterface;
use Zero\Models\Traits\HasSlug;
use Zero\Models\Traits\IsModel;
use App\Modules\Blog\Models\Post;
use Zero\Modules\Search\Traits\Searchable;
use Zero\Modules\Shop\Jobs\SendOrderReceipt;
use Zero\Support\Emailer;
use Zero\Support\Security;

class MyCustomSeeder implements SeederInterface
{
    public function getModuleId(): string 
    { 
        return 'mymodule'; 
    }
    
    public function getPriority(): int 
    { 
        return 30; 
    }

    public function run(string $siteId, string $uploadsDir): void
    {
        echo "--> Running MyCustomSeeder for site ID $siteId...\n";
        
        // Dynamic UUIDv7 key generation ensures zero primary-key database collisions!
        $id = Security::uuidv7();
        DB::query("INSERT INTO my_table(id, site_id, ...) VALUES(?, ?, ...)", [$id, $siteId]);
    }
}

3. Auto-Discovery and Execution

Zero CMS features an automatic discovery engine. On bootstrap, the master CLI runner (bin/seed, backed by Zero\Support\SeederRunner) scans active modular directories for dataset blueprints and seeder classes. It priority-orders them (lower numbers running first, e.g. Blog priority 10, Artworks priority 20, Shop priority 30) and sequentially compiles, migrates, and executes the entire system in under 3 seconds!

To run the database schemas handshake and re-seed all multi-tenant domains in development, execute:

CLI Command to Re-Seed All Tenants

CLI Command to Re-Seed All Tenants bash
docker exec -w /data/misc/zero php83 bin/seed