Custom Module Development for 1C-Bitrix
Extending functionality by patching the core is the worst thing you can do in 1C-Bitrix. After every platform update those patches are wiped out, maintenance becomes a nightmare, and a year later it is impossible to understand what was changed and why. A custom module is the correct way to add non-standard functionality without touching the core.
Bitrix Module Architecture
A 1C-Bitrix module is a directory under /bitrix/modules/<vendor>.<modulename>/ with a strictly defined structure. Bitrix uses the naming convention <vendor>.<name>, where vendor is a short identifier for the developer.
vendor.modulename/
├── install/
│ ├── index.php # Installer class (extends CModule)
│ ├── db/
│ │ └── mysql/
│ │ ├── install.sql # SQL for creating tables
│ │ └── uninstall.sql # SQL for dropping tables
│ └── files/ # Files copied during installation
│ └── bitrix/
│ └── components/
├── lib/ # Classes in namespace Vendor\Modulename\
│ ├── Repository.php
│ ├── Service.php
│ └── Orm/
│ └── EntityTable.php # ORM entity (D7)
├── lang/
│ ├── ru/
│ │ └── install/
│ │ └── index.php # Language labels
│ └── en/
├── options.php # Module settings page
└── include.php # Loaded on \Bitrix\Main\Loader::includeModule()
Installer Class
The installer extends CModule and implements the DoInstall() and DoUninstall() methods:
// vendor.modulename/install/index.php
class vendor_modulename extends CModule
{
public string $MODULE_ID = 'vendor.modulename';
public string $MODULE_VERSION = '1.0.0';
public string $MODULE_NAME = 'Module Name';
public string $MODULE_DESCRIPTION = 'Module description';
public string $PARTNER_NAME = 'Vendor';
public function DoInstall(): void
{
RegisterModule($this->MODULE_ID);
$this->InstallDB();
$this->InstallFiles();
$this->InstallEvents();
}
public function InstallDB(): void
{
global $DB;
$DB->RunSQLBatch($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/vendor.modulename/install/db/mysql/install.sql');
}
public function InstallEvents(): void
{
RegisterModuleDependences(
'main', 'OnPageStart',
'vendor.modulename', '\Vendor\Modulename\EventHandlers', 'onPageStart'
);
}
public function DoUninstall(): void
{
$this->UnInstallEvents();
$this->UnInstallDB();
UnRegisterModule($this->MODULE_ID);
}
}
ORM D7: Working with Data
Modern modules use the Bitrix D7 ORM instead of raw SQL queries. A table class is declared by extending \Bitrix\Main\ORM\Data\DataManager:
namespace Vendor\Modulename\Orm;
use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields\{IntegerField, StringField, DatetimeField, BooleanField};
class RequestTable extends DataManager
{
public static function getTableName(): string
{
return 'vendor_modulename_requests';
}
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new StringField('NAME', ['required' => true, 'size' => 255]),
new StringField('EMAIL', ['size' => 255]),
new BooleanField('ACTIVE', ['default_value' => true]),
new DatetimeField('CREATED_AT'),
];
}
}
Usage:
// Fetch records
$result = RequestTable::getList([
'filter' => ['ACTIVE' => true],
'select' => ['ID', 'NAME', 'EMAIL'],
'order' => ['CREATED_AT' => 'DESC'],
]);
// Add a record
RequestTable::add(['NAME' => 'Test', 'EMAIL' => '[email protected]']);
Events
A module can subscribe to platform events and generate its own. Registering an event handler:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'sale', // module
'OnSaleOrderBeforeSaved', // event
['\Vendor\Modulename\EventHandlers', 'onOrderBeforeSaved']
);
Generating a custom event for extensibility:
$event = new \Bitrix\Main\Event('vendor.modulename', 'OnRequestAdded', ['REQUEST' => $request]);
$event->send();
Admin Interface
An admin panel section is registered via a menu entry (/bitrix/menu.php or automatically via the menu.php file in the module folder). Admin section pages reside in /bitrix/admin/vendor_modulename_*.php.
For modern projects the admin interface is implemented as an Inertia/React SPA or as classic Bitrix admin pages using CAdminList and CAdminForm.
Versioning and Marketplace
A module can be distributed through the 1C-Bitrix Marketplace. For publication: no code errors, language files for ru/en, documentation, and compatibility with current PHP and platform versions.
Typical Development Timelines
| Module Complexity | Description | Timeline |
|---|---|---|
| Simple | 1–2 entities, no complex logic | 1–2 weeks |
| Medium | 3–5 entities, events, custom UI | 3–6 weeks |
| Complex | Integrations, multisite, API | 2–4 months |
The module is documented at the API level (PHPDoc) and with user documentation for administrators.







