Claude Skill

bitrix-modules

Covers creation and maintenance of a custom Bitrix module in /local/modules/<vendor>.<module>/ — CModule class, install/index.php, DoInstall and DoUninstall, install/version.php with $arModuleVersion, registration of events and agents during installation, module options (options.

LLM Mart · 0 points · 13 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download bxmaximum-bitrix-framework-skills-skills_bitrix-modules-66c40e0.zip · 3 KB
Part of bxmaximum/bitrix-framework-skills — 38 skills

Install

skills CLI npx skills add https://github.com/bxmaximum/bitrix-framework-skills/tree/main/skills/bitrix-modules
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install bxmaximum-bitrix-framework-skills@llmmart
Git git clone https://github.com/bxmaximum/bitrix-framework-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole bxmaximum/bitrix-framework-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Bitrix Modules

Identifier and Namespace

  • Identifier: <vendor>.<module> (lowercase, no _, no digit at start).
  • Installer class: <vendor>_<module> (dot → _).
  • Namespace: \<Vendor>\<Module>\... (dot → \, CamelCase) for partner modules with a dot in the id.
  • One-word module id (no partner prefix), e.g. mymodule: installer class mymodule, PSR-4 namespace \Bitrix\Mymodule (Loader uses Bitrix\ + ucfirst($moduleName)), not \Mymodule.

Quick Creation

php bitrix/bitrix.php make:module vendor.module

Since main 25.900. On older versions, scaffold files manually.

make:module creates a minimal skeleton only:

  • install/index.php, install/version.php
  • install/mysql/install.sql, install/mysql/uninstall.sql (empty stubs)
  • default_option.php
  • lang/ru/install/index.php

It does not create .settings.php, /lib/, routes, or controllers. Add those yourself or via further make:* / dev:module-skeleton.

Minimal Structure

/local/modules/vendor.module/
├── install/
│   ├── index.php
│   ├── version.php
│   └── mysql/                   # optional SQL stubs from make:module
├── lang/ru/install/index.php
├── default_option.php
├── lib/                         # PSR-4, Vendor\Module\... (add manually)
├── views/                       # PHP views for renderView() in controllers
├── routes/                      # Module route files — require from /local/routes/web.php
├── .settings.php                # controllers, services, console (add manually)
└── include.php                  # optional, for registerNamespace/registerAutoLoadClasses

Module Routing

Routing is global-only. The kernel loads route files listed in global routing.config from /local/routes/ and /bitrix/routes/ only.

A routing section in the module's .settings.php is not auto-loaded. Connect module routes by require from /local/routes/web.php:

// /local/routes/web.php
return function (\Bitrix\Main\Routing\RoutingConfigurator $routes): void {
    $moduleRoutes = $_SERVER['DOCUMENT_ROOT'] . '/local/modules/vendor.module/routes/web.php';
    if (is_file($moduleRoutes))
    {
        (require $moduleRoutes)($routes);
    }
};

install/version.php

<?php
$arModuleVersion = [
    'VERSION' => '1.0.0',
    'VERSION_DATE' => '2026-04-16 12:00:00',
];

install/index.php

Inherit from CModule, implement DoInstall/DoUninstall. Base template:

<?php

use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ModuleManager;
use Bitrix\Main\EventManager;

Loc::loadMessages(__FILE__);

final class vendor_module extends CModule
{
    public $MODULE_ID = 'vendor.module';
    public $MODULE_VERSION;
    public $MODULE_VERSION_DATE;
    public $MODULE_NAME;
    public $MODULE_DESCRIPTION;
    public $PARTNER_NAME = 'Vendor';
    public $PARTNER_URI = 'https://vendor.example.com';

    public function __construct()
    {
        $arModuleVersion = [];
        include __DIR__ . '/version.php';

        $this->MODULE_VERSION = $arModuleVersion['VERSION'] ?? '';
        $this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE'] ?? '';

        $this->MODULE_NAME = (string)Loc::getMessage('VENDOR_MODULE_NAME');
        $this->MODULE_DESCRIPTION = (string)Loc::getMessage('VENDOR_MODULE_DESCRIPTION');
    }

    public function DoInstall(): void
    {
        global $USER, $APPLICATION;

        if (!$USER->IsAdmin())
        {
            $APPLICATION->ThrowException('Access denied');
            return;
        }

        ModuleManager::registerModule($this->MODULE_ID);

        $this->installDb();
        $this->installEvents();
        $this->installAgents();
        $this->installFiles();
    }

    public function DoUninstall(): void
    {
        global $USER;
        if (!$USER->IsAdmin()) return;

        $this->uninstallAgents();
        $this->uninstallEvents();
        $this->uninstallDb();
        $this->uninstallFiles();

        ModuleManager::unRegisterModule($this->MODULE_ID);
    }

    private function installDb(): void
    {
        // Table creation via ORM Entity:
        // \Vendor\Module\Model\PostTable::getEntity()->createDbTable();
    }

    private function uninstallDb(): void
    {
        // Application::getConnection()->dropTable(PostTable::getTableName());
    }

    private function installEvents(): void
    {
        EventManager::getInstance()->registerEventHandler(
            fromModule: 'main',
            eventType: 'OnAfterUserAdd',
            toModuleId: $this->MODULE_ID,
            toClass: \Vendor\Module\Internals\Integration\Main\EventHandler\OnAfterUserAddHandler::class,
            toMethod: 'handle',
        );
    }

    private function uninstallEvents(): void
    {
        EventManager::getInstance()->unRegisterEventHandler(
            fromModule: 'main',
            eventType: 'OnAfterUserAdd',
            toModuleId: $this->MODULE_ID,
            toClass: \Vendor\Module\Internals\Integration\Main\EventHandler\OnAfterUserAddHandler::class,
            toMethod: 'handle',
        );
    }

    private function installAgents(): void
    {
        \CAgent::AddAgent(
            \Vendor\Module\Cli\Agent\QueueAgent::class . '::run();',
            $this->MODULE_ID,
            'N',
            300,
            '',
            'Y',
            '',
            100,
        );
    }

    private function uninstallAgents(): void
    {
        \CAgent::RemoveModuleAgents($this->MODULE_ID);
    }

    private function installFiles(): void
    {
        CopyDirFiles(
            __DIR__ . '/components',
            $_SERVER['DOCUMENT_ROOT'] . '/local/components',
            true,
            true,
        );
    }

    private function uninstallFiles(): void
    {
        DeleteDirFilesEx('/local/components/vendor');
    }
}

Language Files

/local/modules/vendor.module/lang/ru/install/index.php (created by make:module):

<?php
$MESS['VENDOR_MODULE_NAME'] = 'Vendor Module';
$MESS['VENDOR_MODULE_DESCRIPTION'] = 'Module description';

Add lang/en/ (and other locales) as needed for multi-language admin UI.

Lang file paths must mirror the source file path relative to the module root: /install/index.php → /lang/<code>/install/index.php, /admin/my_page.php → /lang/<code>/admin/my_page.php. MODULE_NAME / MODULE_DESCRIPTION are read from these phrases in the installer constructor and shown in Admin → Settings → Product settings → Modules; if the lang file path or phrase codes don't match, the module appears there with an empty name/description.

DB Tables

Do not use raw SQL for table creation. Describe the entity in /lib/Model/PostTable.php and create the table via ORM:

\Bitrix\Main\Loader::includeModule('vendor.module');
\Vendor\Module\Model\PostTable::getEntity()->createDbTable();

For deletion:

\Bitrix\Main\Application::getConnection()->dropTable(PostTable::getTableName());

Module Options (options.php)

Module options (Option + default_option.php) are for permanent settings. For TTL runtime state vs cache vs Option, see skill bitrix-storage.

If you need a settings page in Admin Panel (Settings → Module Settings → Vendor Module):

<?php
/** @var CMain $APPLICATION */
/** @var string $mid */ // module id

use Bitrix\Main\Config\Option;
use Bitrix\Main\Localization\Loc;

$options = [
    ['api_key', Loc::getMessage('VENDOR_API_KEY'), '', ['text', 40]],
    ['debug_mode', Loc::getMessage('VENDOR_DEBUG'), 'N', ['checkbox', 'Y']],
];

if ($_SERVER['REQUEST_METHOD'] === 'POST' && check_bitrix_sessid())
{
    foreach ($options as $opt)
    {
        $val = $_POST[$opt[0]] ?? $opt[2];
        Option::set($mid, $opt[0], $val);
    }
}

// ... display via CAdminTabControl

PSR-4 Autoloading

Nothing needs to be registered manually in include.php if:

  1. Module is in /local/modules/vendor.module/.
  2. Classes are in /lib/.
  3. Namespace follows \Vendor\Module\... (or \Bitrix\Mymodule\... for a one-word id).

Bitrix Loader handles this automatically when includeModule is called.

Checklist

  • Module identifier follows vendor.module format (or one-word → \Bitrix\... namespace).
  • After make:module, .settings.php / lib/ added if needed (generator is minimal).
  • Module routes are required from /local/routes/web.php — not expected from module .settings.php routing.
  • DoInstall/DoUninstall are implemented and idempotent.
  • Event handlers and agents are registered upon installation and removed upon uninstallation.
  • DB tables are managed via ORM or SqlHelper (DDL).
  • Language files exist where needed (lang/ru/ from generator; add lang/en/ etc.).
  • Services and controllers are registered in .settings.php.
  • No hardcoded strings in index.php (use Loc).
  • Module is compatible with PSR-4.
  • Files are copied to /local/, not /bitrix/.
Files (bitrix-framework-skills)
  • SKILL.md 9.5 KB
    ---
    name: bitrix-modules
    description: Covers creation and maintenance of a custom Bitrix module in /local/modules/<vendor>.<module>/ — CModule class, install/index.php, DoInstall and DoUninstall, install/version.php with $arModuleVersion, registration of events and agents during installation, module options (options.php), generation via make:module. Applied when creating a new module, refining installation/uninstallation, registering event handlers and publishing module options in the Admin Panel. Key terms — CModule, DoInstall, DoUninstall, module manifest, install/index.php, make:module, vendor.module.
    ---
    
    # Bitrix Modules
    
    ## Identifier and Namespace
    
    - Identifier: `<vendor>.<module>` (lowercase, no `_`, no digit at start).
    - Installer class: `<vendor>_<module>` (dot → `_`).
    - Namespace: `\<Vendor>\<Module>\...` (dot → `\`, CamelCase) for partner modules with a dot in the id.
    - One-word module id (no partner prefix), e.g. `mymodule`: installer class `mymodule`, PSR-4 namespace **`\Bitrix\Mymodule`** (Loader uses `Bitrix\` + `ucfirst($moduleName)`), not `\Mymodule`.
    
    ## Quick Creation
    
    ```bash
    php bitrix/bitrix.php make:module vendor.module
    ```
    
    **Since main 25.900.** On older versions, scaffold files manually.
    
    `make:module` creates a **minimal** skeleton only:
    
    - `install/index.php`, `install/version.php`
    - `install/mysql/install.sql`, `install/mysql/uninstall.sql` (empty stubs)
    - `default_option.php`
    - `lang/ru/install/index.php`
    
    It does **not** create `.settings.php`, `/lib/`, routes, or controllers. Add those yourself or via further `make:*` / `dev:module-skeleton`.
    
    ## Minimal Structure
    
    ```
    /local/modules/vendor.module/
    ├── install/
    │   ├── index.php
    │   ├── version.php
    │   └── mysql/                   # optional SQL stubs from make:module
    ├── lang/ru/install/index.php
    ├── default_option.php
    ├── lib/                         # PSR-4, Vendor\Module\... (add manually)
    ├── views/                       # PHP views for renderView() in controllers
    ├── routes/                      # Module route files — require from /local/routes/web.php
    ├── .settings.php                # controllers, services, console (add manually)
    └── include.php                  # optional, for registerNamespace/registerAutoLoadClasses
    ```
    
    ## Module Routing
    
    Routing is **global-only**. The kernel loads route files listed in global `routing.config` from `/local/routes/` and `/bitrix/routes/` only.
    
    A `routing` section in the module's `.settings.php` is **not** auto-loaded. Connect module routes by `require` from `/local/routes/web.php`:
    
    ```php
    // /local/routes/web.php
    return function (\Bitrix\Main\Routing\RoutingConfigurator $routes): void {
        $moduleRoutes = $_SERVER['DOCUMENT_ROOT'] . '/local/modules/vendor.module/routes/web.php';
        if (is_file($moduleRoutes))
        {
            (require $moduleRoutes)($routes);
        }
    };
    ```
    
    ## `install/version.php`
    
    ```php
    <?php
    $arModuleVersion = [
        'VERSION' => '1.0.0',
        'VERSION_DATE' => '2026-04-16 12:00:00',
    ];
    ```
    
    ## `install/index.php`
    
    Inherit from `CModule`, implement `DoInstall`/`DoUninstall`. Base template:
    
    ```php
    <?php
    
    use Bitrix\Main\Localization\Loc;
    use Bitrix\Main\ModuleManager;
    use Bitrix\Main\EventManager;
    
    Loc::loadMessages(__FILE__);
    
    final class vendor_module extends CModule
    {
        public $MODULE_ID = 'vendor.module';
        public $MODULE_VERSION;
        public $MODULE_VERSION_DATE;
        public $MODULE_NAME;
        public $MODULE_DESCRIPTION;
        public $PARTNER_NAME = 'Vendor';
        public $PARTNER_URI = 'https://vendor.example.com';
    
        public function __construct()
        {
            $arModuleVersion = [];
            include __DIR__ . '/version.php';
    
            $this->MODULE_VERSION = $arModuleVersion['VERSION'] ?? '';
            $this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE'] ?? '';
    
            $this->MODULE_NAME = (string)Loc::getMessage('VENDOR_MODULE_NAME');
            $this->MODULE_DESCRIPTION = (string)Loc::getMessage('VENDOR_MODULE_DESCRIPTION');
        }
    
        public function DoInstall(): void
        {
            global $USER, $APPLICATION;
    
            if (!$USER->IsAdmin())
            {
                $APPLICATION->ThrowException('Access denied');
                return;
            }
    
            ModuleManager::registerModule($this->MODULE_ID);
    
            $this->installDb();
            $this->installEvents();
            $this->installAgents();
            $this->installFiles();
        }
    
        public function DoUninstall(): void
        {
            global $USER;
            if (!$USER->IsAdmin()) return;
    
            $this->uninstallAgents();
            $this->uninstallEvents();
            $this->uninstallDb();
            $this->uninstallFiles();
    
            ModuleManager::unRegisterModule($this->MODULE_ID);
        }
    
        private function installDb(): void
        {
            // Table creation via ORM Entity:
            // \Vendor\Module\Model\PostTable::getEntity()->createDbTable();
        }
    
        private function uninstallDb(): void
        {
            // Application::getConnection()->dropTable(PostTable::getTableName());
        }
    
        private function installEvents(): void
        {
            EventManager::getInstance()->registerEventHandler(
                fromModule: 'main',
                eventType: 'OnAfterUserAdd',
                toModuleId: $this->MODULE_ID,
                toClass: \Vendor\Module\Internals\Integration\Main\EventHandler\OnAfterUserAddHandler::class,
                toMethod: 'handle',
            );
        }
    
        private function uninstallEvents(): void
        {
            EventManager::getInstance()->unRegisterEventHandler(
                fromModule: 'main',
                eventType: 'OnAfterUserAdd',
                toModuleId: $this->MODULE_ID,
                toClass: \Vendor\Module\Internals\Integration\Main\EventHandler\OnAfterUserAddHandler::class,
                toMethod: 'handle',
            );
        }
    
        private function installAgents(): void
        {
            \CAgent::AddAgent(
                \Vendor\Module\Cli\Agent\QueueAgent::class . '::run();',
                $this->MODULE_ID,
                'N',
                300,
                '',
                'Y',
                '',
                100,
            );
        }
    
        private function uninstallAgents(): void
        {
            \CAgent::RemoveModuleAgents($this->MODULE_ID);
        }
    
        private function installFiles(): void
        {
            CopyDirFiles(
                __DIR__ . '/components',
                $_SERVER['DOCUMENT_ROOT'] . '/local/components',
                true,
                true,
            );
        }
    
        private function uninstallFiles(): void
        {
            DeleteDirFilesEx('/local/components/vendor');
        }
    }
    ```
    
    ## Language Files
    
    `/local/modules/vendor.module/lang/ru/install/index.php` (created by `make:module`):
    
    ```php
    <?php
    $MESS['VENDOR_MODULE_NAME'] = 'Vendor Module';
    $MESS['VENDOR_MODULE_DESCRIPTION'] = 'Module description';
    ```
    
    Add `lang/en/` (and other locales) as needed for multi-language admin UI.
    
    Lang file paths must **mirror the source file path** relative to the module root: `/install/index.php` → `/lang/<code>/install/index.php`, `/admin/my_page.php` → `/lang/<code>/admin/my_page.php`. `MODULE_NAME` / `MODULE_DESCRIPTION` are read from these phrases in the installer constructor and shown in Admin → *Settings → Product settings → Modules*; if the lang file path or phrase codes don't match, the module appears there with an empty name/description.
    
    ## DB Tables
    
    Do not use raw SQL for table creation. Describe the entity in `/lib/Model/PostTable.php` and create the table via ORM:
    
    ```php
    \Bitrix\Main\Loader::includeModule('vendor.module');
    \Vendor\Module\Model\PostTable::getEntity()->createDbTable();
    ```
    
    For deletion:
    
    ```php
    \Bitrix\Main\Application::getConnection()->dropTable(PostTable::getTableName());
    ```
    
    ## Module Options (`options.php`)
    
    Module options (`Option` + `default_option.php`) are for **permanent** settings. For TTL runtime state vs cache vs Option, see skill `bitrix-storage`.
    
    If you need a settings page in Admin Panel (*Settings → Module Settings → Vendor Module*):
    
    ```php
    <?php
    /** @var CMain $APPLICATION */
    /** @var string $mid */ // module id
    
    use Bitrix\Main\Config\Option;
    use Bitrix\Main\Localization\Loc;
    
    $options = [
        ['api_key', Loc::getMessage('VENDOR_API_KEY'), '', ['text', 40]],
        ['debug_mode', Loc::getMessage('VENDOR_DEBUG'), 'N', ['checkbox', 'Y']],
    ];
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && check_bitrix_sessid())
    {
        foreach ($options as $opt)
        {
            $val = $_POST[$opt[0]] ?? $opt[2];
            Option::set($mid, $opt[0], $val);
        }
    }
    
    // ... display via CAdminTabControl
    ```
    
    ## PSR-4 Autoloading
    
    Nothing needs to be registered manually in `include.php` if:
    1. Module is in `/local/modules/vendor.module/`.
    2. Classes are in `/lib/`.
    3. Namespace follows `\Vendor\Module\...` (or `\Bitrix\Mymodule\...` for a one-word id).
    
    Bitrix `Loader` handles this automatically when `includeModule` is called.
    
    ## Checklist
    
    - [ ] Module identifier follows `vendor.module` format (or one-word → `\Bitrix\...` namespace).
    - [ ] After `make:module`, `.settings.php` / `lib/` added if needed (generator is minimal).
    - [ ] Module routes are `require`d from `/local/routes/web.php` — not expected from module `.settings.php` `routing`.
    - [ ] `DoInstall`/`DoUninstall` are implemented and idempotent.
    - [ ] Event handlers and agents are registered upon installation and removed upon uninstallation.
    - [ ] DB tables are managed via ORM or `SqlHelper` (DDL).
    - [ ] Language files exist where needed (`lang/ru/` from generator; add `lang/en/` etc.).
    - [ ] Services and controllers are registered in `.settings.php`.
    - [ ] No hardcoded strings in `index.php` (use `Loc`).
    - [ ] Module is compatible with PSR-4.
    - [ ] Files are copied to `/local/`, not `/bitrix/`.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related