Module Development: Getting Started

Last updated on May 20, 2026 19:06

The true power of PolyCMS lies in its modularity. Modules (sometimes called plugins) allow you to extend the core functionality of the CMS, add new API endpoints, create custom admin interfaces, or integrate with third-party services—all without touching a single line of core code.

This guide will walk you through scaffolding your first module.

1. Directory Structure

All modules must be placed inside the modules/ directory at the root of your PolyCMS installation. They follow a Vendor/ModuleName namespace convention.

Let's create a module called BlogEnhancer by the vendor Polyx.

modules/
└── Polyx/
    └── BlogEnhancer/
        ├── module.json          # The Module Manifest
        └── src/
            └── BlogEnhancerServiceProvider.php

2. The Module Manifest (module.json)

Every module must have a module.json file in its root directory. The core ModuleManager parses this file to discover the module, register its PSR-4 autoloading namespace, and boot its Service Provider.

Create modules/Polyx/BlogEnhancer/module.json:

{
  "name": "BlogEnhancer",
  "vendor": "Polyx",
  "version": "1.0.0",
  "description": "Adds extra features and SEO tools to the core blog.",
  "provider": "Modules\\Polyx\\BlogEnhancer\\BlogEnhancerServiceProvider",
  "autoload": {
    "psr-4": {
      "Modules\\Polyx\\BlogEnhancer\\": "src/"
    }
  },
  "sandbox": false
}

3. Trusted Native vs. Sandbox Remote

Notice the "sandbox": false key in the manifest above. PolyCMS implements a dual-model architecture:

  • Trusted Native (sandbox: false): The module is executed natively within the Laravel core. It has direct access to the database, file system, and can alter rendering rules via Service Providers. Use this for deep system integrations (like Caching, Backup modules, or complex Payment Gateways).

  • Sandbox Remote (sandbox: true): A zero-trust execution model. The module lives out-of-band and only communicates via the /api/v1 or /graphql endpoints using an Admin-approved Sanctum token. Use this for 3rd-party integrations (like Mailchimp sync, CRM connectors, or AI generation).

For this tutorial, we are building a Trusted Native module.

4. The Service Provider

The Service Provider is the entry point for your PHP code. This is where you register routes, bind singletons, and hook into the core events.

Create modules/Polyx/BlogEnhancer/src/BlogEnhancerServiceProvider.php:

<?php

declare(strict_types=1);

namespace Modules\Polyx\BlogEnhancer;

use Illuminate\Support\ServiceProvider;
use App\Facades\Hook;

class BlogEnhancerServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Bind classes into the service container
    }

    public function boot(): void
    {
        // 1. Load routes (if you have them)
        // $this->loadRoutesFrom(__DIR__ . '/routes/api.php');

        // 2. Load Views (if you have them)
        // $this->loadViewsFrom(__DIR__ . '/../resources/views', 'blog-enhancer');

        // 3. Register Hooks
        $this->registerHooks();
    }

    private function registerHooks(): void
    {
        // Example: Add a custom menu item to the Admin panel
        Hook::addAction('admin.menu.build', function ($menuRegistry) {
            $menuRegistry->addChild('content', [
                'key' => 'blog_enhancer_tools',
                'label' => 'SEO Tools',
                'url' => '/admin/blog-enhancer',
                'icon' => 'SparklesIcon',
                'order' => 90
            ]);
        });
    }
}

5. Enable the Module

Now that your scaffold is complete, log in to the PolyCMS Admin Panel and navigate to Settings > Modules.

You should see your BlogEnhancer module listed. Click Enable.

The core system will reload, and because we hooked into admin.menu.build, you will instantly see the new "SEO Tools" link appear in the sidebar under the Content section!

Next Steps

Now that your module is booting, you can expand it by: