Свой простой модуль для 1С-Битрикс: от /local/modules до рабочего компонента
Пошаговый практический пример создания простого модуля для 1С-Битрикс: структура /local/modules, класс модуля, установка компонента и проверка через админку.
Требования
- 1С-Битрикс: Управление сайтом (любой актуальный релиз)
- Базовые знания PHP
- Доступ к файловой системе проекта
Свой простой модуль для 1С-Битрикс: от /local/modules до рабочего компонента
В этой статье разберём минимальный, но боевой пример собственного модуля под 1С‑Битрикс, который:
- корректно устанавливается и удаляется через админку;
- ставит один компонент;
- не ломает обновления и соответствует официальному подходу.
Без философии. Только практика и структура из учебного курса Битрикса, но нормальным человеческим языком.
Когда нужен модуль, а не код в /local
Коротко и по делу:
Модуль нужен, когда:
- код переиспользуется на нескольких проектах;
- требуется установка/удаление через админку;
- нужны настройки, версии, права доступа;
- компонент — часть функционального блока, а не разовая правка.
Если код живёт только в одном проекте и никогда никуда не поедет — /local/php_interface ок.
Во всех остальных случаях — модуль.
Структура простого модуля
Делаем модуль vendor.simplemodule.
Базовая структура
/local/modules/vendor.simplemodule/
├── install/
│ ├── components/
│ │ └── vendor/
│ │ └── simple.date/
│ │ ├── component.php
│ │ ├── .description.php
│ │ └── templates/
│ │ └── .default/
│ │ └── template.php
│ ├── index.php
│ ├── step.php
│ ├── unstep.php
│ └── version.php
├── lang/
├── include.php
└── vendor.simplemodule.php
Обрати внимание: компонент лежит внутри модуля, а не сразу в /local/components.
Файл version.php
Минимальный, но обязательный.
<?php
$arModuleVersion = [
"VERSION" => "1.0.0",
"VERSION_DATE" => "2026-02-09",
];
По документации Битрикс в version.php используют двойные кавычки — одинарные могут не отрабатывать при установке.
Класс модуля
Сниппеты по статье: InstallDB/UnInstallDB и SQL · События при установке/удалении · Автозагрузка классов модуля · Проверка B_PROLOG_INCLUDED в компоненте
Файл:
/local/modules/vendor.simplemodule/vendor.simplemodule.php
В структуре по документации класс может быть описан в install/index.php; на практике его часто выносят в корневой файл с именем модуля (например, vendor.simplemodule.php), чтобы подключать через include.php.
<?php
use Bitrix\Main\ModuleManager;
class vendor_simplemodule extends CModule
{
public $MODULE_ID = 'vendor.simplemodule';
public $MODULE_VERSION;
public $MODULE_VERSION_DATE;
public $MODULE_NAME = 'Простой учебный модуль';
public $MODULE_DESCRIPTION = 'Учебный модуль с одним компонентом';
public $MODULE_GROUP_RIGHTS = 'N';
public function __construct()
{
include __DIR__ . '/install/version.php';
$this->MODULE_VERSION = $arModuleVersion['VERSION'];
$this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE'];
}
Что здесь важно
$MODULE_IDстрого совпадает с именем папки;- версия и дата берутся из
version.php; - никакой логики — только описание.
Установка файлов (InstallFiles)
public function InstallFiles()
{
CopyDirFiles(
__DIR__ . '/install/components',
$_SERVER['DOCUMENT_ROOT'] . '/local/components',
true,
true
);
return true;
}
Что происходит:
- копируем компоненты из модуля;
- они появляются в
/local/components/vendor/...; - Bitrix начинает их видеть.
Удаление файлов (UnInstallFiles)
public function UnInstallFiles()
{
DeleteDirFilesEx('/local/components/vendor/simple.date');
return true;
}
Никакой магии — просто аккуратно удаляем то, что поставили.
Установка модуля (DoInstall)
public function DoInstall()
{
global $APPLICATION;
$this->InstallFiles();
ModuleManager::registerModule($this->MODULE_ID);
$APPLICATION->IncludeAdminFile(
'Установка модуля',
__DIR__ . '/install/step.php'
);
}
Порядок важен
- Копируем файлы
- Регистрируем модуль
- Показываем шаг установки
В учебном курсе Битрикс в DoInstall() вызывают InstallDB() → InstallEvents() → InstallFiles(), причём в том примере InstallDB() только регистрирует модуль (RegisterModule). Мы используем современный API ModuleManager::registerModule() и показываем шаг установки через IncludeAdminFile — оба варианта соответствуют документации.
Удаление модуля (DoUninstall)
public function DoUninstall()
{
global $APPLICATION;
$this->UnInstallFiles();
ModuleManager::unRegisterModule($this->MODULE_ID);
$APPLICATION->IncludeAdminFile(
'Удаление модуля',
__DIR__ . '/install/unstep.php'
);
}
}
Файлы step.php и unstep.php
Минимальный вариант.
<?php
echo 'Модуль успешно установлен';
<?php
echo 'Модуль успешно удалён';
Простейший компонент внутри модуля
Компонент:
vendor:simple.date
.description.php
<?php
$arComponentDescription = [
'NAME' => 'Текущая дата',
'DESCRIPTION' => 'Простой компонент для вывода текущей даты',
'PATH' => [
'ID' => 'vendor',
'NAME' => 'Учебные компоненты',
],
];
component.php
Защита от прямого вызова — проверка B_PROLOG_INCLUDED (сниппет):
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
$arResult['DATE'] = date('d.m.Y');
$this->IncludeComponentTemplate();
Шаблон компонента
templates/.default/template.php — в шаблоне та же проверка (сниппет):
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
?>
<div class="simple-date">
Текущая дата: <strong><?= htmlspecialcharsbx($arResult['DATE']) ?></strong>
</div>
Установка и проверка
1. Установка модуля
Админка → Настройки → Модули → Простой учебный модуль → Установить.
Если не появился:
- проверь имя папки;
- проверь
$MODULE_ID; - обнови список модулей.
2. Проверка компонента
В визуальном редакторе или в коде:
<?php
$APPLICATION->IncludeComponent(
'vendor:simple.date',
'',
[]
);
Если видишь текущую дату — всё работает.
Настройки модуля (options)
В Битриксе настройки модуля — это значения, хранящиеся в таблице b_option.
Работаем только через API, без самодельных таблиц.
Где живут настройки
- ключи и значения — в
b_option - интерфейс — через
options.php(если нужен UI) - доступ — через
\Bitrix\Main\Config\Option
Простейшая настройка без интерфейса
use Bitrix\Main\Config\Option;
// запись
Option::set(
'vendor.simplemodule',
'show_date',
'Y'
);
// чтение
$showDate = Option::get(
'vendor.simplemodule',
'show_date',
'N'
);
Важно:
- первый параметр —
MODULE_ID; - всегда указывай дефолт;
- никаких
COption(устаревшее API).
Использование настройки в компоненте
use Bitrix\Main\Config\Option;
if (Option::get('vendor.simplemodule', 'show_date', 'Y') !== 'Y') {
return;
}
$arResult['DATE'] = date('d.m.Y');
Права доступа модуля
Права доступа в модуле — стандартный механизм, не самописный.
Включение поддержки прав
В классе модуля:
public $MODULE_GROUP_RIGHTS = 'Y';
После этого в админке появится вкладка «Права доступа».
Проверка прав в коде
global $APPLICATION;
if ($APPLICATION->GetGroupRight('vendor.simplemodule') < 'R') {
return;
}
Стандартные уровни
| Код | Значение |
|---|---|
| D | доступ запрещён |
| R | чтение |
| W | запись |
| X | полный доступ |
Важно: не выдумывай свои уровни — Bitrix этого не любит.
Автозагрузка классов модуля
Современный способ — через Bitrix\Main\Loader и PSR-4. Готовый шаблон: сниппет «Автозагрузка классов модуля».
Структура
/local/modules/vendor.simplemodule/
├── lib/
│ └── Service/
│ └── DateProvider.php
├── include.php
include.php
<?php
use Bitrix\Main\Loader;
Loader::registerAutoLoadClasses(
'vendor.simplemodule',
[
'Vendor\\SimpleModule\\Service\\DateProvider' =>
'lib/Service/DateProvider.php',
]
);
Класс
<?php
namespace Vendor\SimpleModule\Service;
class DateProvider
{
public static function getCurrentDate(): string
{
return date('d.m.Y');
}
}
Использование
use Vendor\SimpleModule\Service\DateProvider;
$arResult['DATE'] = DateProvider::getCurrentDate();
Критично:
namespaceв форматеVendor\SimpleModule\...(например,Vendor\SimpleModule\Service);- путь от корня модуля;
- никаких
require_once.
Модуль с ORM (DataManager)
ORM в Битриксе — это \Bitrix\Main\Entity\DataManager.
Используется только для своих таблиц.
Таблица
CREATE TABLE vendor_simple_date (
ID int NOT NULL AUTO_INCREMENT,
CREATED_AT datetime NOT NULL,
PRIMARY KEY (ID)
);
Класс таблицы
/local/modules/vendor.simplemodule/lib/DateTable.php
<?php
namespace Vendor\SimpleModule;
use Bitrix\Main\Entity;
use Bitrix\Main\Type\DateTime;
class DateTable extends Entity\DataManager
{
public static function getTableName()
{
return 'vendor_simple_date';
}
public static function getMap()
{
return [
new Entity\IntegerField('ID', [
'primary' => true,
'autocomplete' => true,
]),
new Entity\DatetimeField('CREATED_AT', [
'required' => true,
'default_value' => new DateTime(),
]),
];
}
}
Использование ORM
use Vendor\SimpleModule\DateTable;
DateTable::add([]);
$items = DateTable::getList([
'order' => ['ID' => 'DESC'],
'limit' => 5,
])->fetchAll();
События модуля
События подключаются только после установки модуля. Регистрация и снятие в DoInstall/DoUninstall: сниппет «События при установке/удалении».
Регистрация обработчика
В DoInstall():
use Bitrix\Main\EventManager;
EventManager::getInstance()->registerEventHandler(
'main',
'OnPageStart',
'vendor.simplemodule',
'Vendor\\SimpleModule\\EventHandler',
'onPageStart'
);
Удаление обработчика
В DoUninstall():
EventManager::getInstance()->unRegisterEventHandler(
'main',
'OnPageStart',
'vendor.simplemodule',
'Vendor\\SimpleModule\\EventHandler',
'onPageStart'
);
Класс обработчика
/lib/EventHandler.php
<?php
namespace Vendor\SimpleModule;
class EventHandler
{
public static function onPageStart()
{
// минимальная логика
}
}
Важно:
- события регистрируются и удаляются;
- не оставляй «висячие» хендлеры;
- никакой бизнес-логики в событиях.
Ниже — создание и удаление таблиц через install.sql/uninstall.sql (штатный DB API) и типичные ошибки модулей, из-за которых «падают обновления» и админка начинает ненавидеть тебя.
install.sql / uninstall.sql (создание и удаление таблицы)
Где хранить SQL в модуле
Классический (официальный, учебный) подход — держать SQL внутри install/:
/local/modules/vendor.simplemodule/
└── install/
├── db/
│ ├── install.sql
│ └── uninstall.sql
└── ...
Да, пути могут быть разными в реальных модулях, но суть по доке: SQL выполняем через
$DB->RunSQLBatch()(метод принимает путь к .sql-файлу; глобальный$DB— экземплярCDatabase), а файлы лежат в install-части.
install/db/install.sql
CREATE TABLE IF NOT EXISTS vendor_simple_date (
ID INT NOT NULL AUTO_INCREMENT,
CREATED_AT DATETIME NOT NULL,
PRIMARY KEY (ID)
);
install/db/uninstall.sql
DROP TABLE IF EXISTS vendor_simple_date;
Выполнение SQL при установке/удалении (строго штатно)
Добавляем в класс модуля два метода: InstallDB() и UnInstallDB(). Готовый код с проверкой ошибок: сниппет «InstallDB/UnInstallDB и SQL». В учебнике Битрикс метод InstallDB() иногда используется только для регистрации модуля в БД (RegisterModule); здесь мы используем его для создания своих таблиц, а регистрацию делаем отдельно через ModuleManager::registerModule() в DoInstall() — так делают многие штатные и партнёрские модули.
<?php
use Bitrix\Main\Application;
use Bitrix\Main\IO\Path;
class vendor_simplemodule extends CModule
{
// ...
public function InstallDB()
{
global $DB;
$sqlPath = $_SERVER['DOCUMENT_ROOT'] . '/local/modules/' . $this->MODULE_ID . '/install/db/install.sql';
if (file_exists($sqlPath)) {
$errors = $DB->RunSQLBatch($sqlPath);
if (is_array($errors)) {
throw new \Bitrix\Main\SystemException(implode("\n", $errors));
}
}
return true;
}
public function UnInstallDB()
{
global $DB;
$sqlPath = $_SERVER['DOCUMENT_ROOT'] . '/local/modules/' . $this->MODULE_ID . '/install/db/uninstall.sql';
if (file_exists($sqlPath)) {
$errors = $DB->RunSQLBatch($sqlPath);
if (is_array($errors)) {
throw new \Bitrix\Main\SystemException(implode("\n", $errors));
}
}
return true;
}
}
Подключаем в DoInstall() и DoUninstall()
public function DoInstall()
{
global $APPLICATION;
$this->InstallDB();
$this->InstallFiles();
\Bitrix\Main\ModuleManager::registerModule($this->MODULE_ID);
$APPLICATION->IncludeAdminFile('Установка модуля', __DIR__ . '/install/step.php');
}
public function DoUninstall()
{
global $APPLICATION;
$this->UnInstallFiles();
$this->UnInstallDB();
\Bitrix\Main\ModuleManager::unRegisterModule($this->MODULE_ID);
$APPLICATION->IncludeAdminFile('Удаление модуля', __DIR__ . '/install/unstep.php');
}
Критично:
- SQL выполняем до register/unregister — так проще отлаживать;
RunSQLBatch()возвращает массив ошибок — его нельзя игнорировать;IF EXISTS/IF NOT EXISTSспасают при повторной установке/удалении.
Типичные ошибки модулей, из-за которых «падают обновления»
Это то, что реально валит проекты после апдейтов, миграций и просто «перестало работать в понедельник».
1) Модуль пишет/правит файлы в /bitrix/*
Плохо: модуль кладёт свои файлы в ядро или меняет файлы ядра. Почему падает: обновление ядра перезатирает всё. Иногда — вместе с проектом.
✅ Правило: всё своё — в /local. Ядро — не трогаем.
2) Нет симметрии между install и uninstall
Плохо: зарегистрировал обработчики событий, но не удалил; создал таблицы, но не удалил; скопировал компоненты, но не удалил.
Симптомы:
- дубли обработчиков → код выполняется дважды;
- ошибки при переустановке;
- «призраки» в системе.
✅ Правило: что поставил — то убрал (файлы/события/опции/таблицы).
3) Бизнес-логика в DoInstall() / __construct()
Плохо: в конструкторе модуля подключаются классы, бьётся ORM, читаются таблицы, вызываются сервисы.
Почему падает: админка просто открывает список модулей → а у тебя там пол-проекта стартует и валится.
✅ Правило:
__construct()— только мета (version.php, name/desc).- установка — только инфраструктура (файлы, таблицы, события).
4) Неправильный $MODULE_ID и структура папок
Плохо: папка vendor.simplemodule, а $MODULE_ID = 'vendor.simple_module' или класс модуля называется иначе.
Симптомы: модуль “не виден”, “не ставится”, “не удаляется”.
✅ Правило:
- папка:
vendor.simplemodule $MODULE_ID:vendor.simplemodule- класс:
vendor_simplemodule(точно как ожидает Bitrix)
5) Компонент кладут не туда
Плохо: компонент лежит прямо в /local/modules/.../components и не копируется, или копируется в /bitrix/components.
✅ Правило:
- исходники компонента:
/install/components/vendor/... - установка: копирование в
/local/components/vendor/...
6) Классы без автозагрузки, всё через require_once
Плохо: в init.php или component.php пачка require_once, часть путей относительная.
Почему падает: при изменении структуры / кеша / окружения ловишь “Failed opening required”.
✅ Правило:
- регистрируй автозагрузку через
Loader::registerAutoLoadClasses() require_once— только для install-скриптов и то по необходимости.
7) События регистрируются «в рантайме», а не через установку
Плохо: AddEventHandler вызывается в init.php модуля или в include.php без контроля установки.
Почему падает: модуль удалили, а обработчики продолжают жить или подключаться.
✅ Правило:
- регистрировать события через
EventManagerвDoInstall() - удалять в
DoUninstall()
8) Нет проверки B_PROLOG_INCLUDED в компонентах/шаблонах
Плохо: шаблон или component.php может выполняться напрямую.
✅ Правило: в каждом файле компонента/шаблона (сниппет):
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
9) Грязные опции: не удаляются / конфликтуют по ключам
Плохо: Option::set() без namespace и без удаления при uninstall.
✅ Правило:
- ключи только под своим
MODULE_ID - при удалении — чистим опции модуля (если политика проекта это допускает).
Итоговый чек-лист перед продом
Перед тем как использовать модуль в реальном проекте, проверь:
- Имя папки =
$MODULE_ID - Компоненты копируются в
/local/components -
InstallFilesиUnInstallFilesсимметричны - Нет бизнес-логики в классе модуля
- Компонент работает без модуля (после копирования)
- Модуль корректно удаляется и ставится повторно
- Код не трогает
/bitrix
Итог
Ты получил:
- минимальный, но корректный модуль;
- понятную структуру;
- компонент, который реально устанавливается;
- основу для масштабирования (настройки, события, ORM — дальше).
Это ровно тот уровень, с которого стоит начинать писать свои модули под Битрикс — без оверинженеринга и шаманства.
В статье уже разобраны настройки модуля, права доступа, автозагрузка классов, ORM и события — пользуйся соответствующими разделами как справочником.



Комментарии