Публикация своего модуля - требования, обновления, поддержка
Готовим свой модуль к публикации: требования к коду, чистая установка и удаление, механика обновлений и понимание, во что обойдётся поддержка.
Механика
Публикуемый модуль отличается от проектного тремя вещами. У него постоянный идентификатор, начинающийся с кода партнёра; он ставится на чужие проекты, о которых вы ничего не знаете; и он обязан удаляться, не оставляя следов. Всё остальное у него устроено как у обычного модуля платформы.
Установка и удаление - это код, а не архив. Класс установки поднимает таблицы, копирует компоненты, регистрирует обработчики событий и заводит настройки; удаление проходит те же шаги в обратную сторону. Пропущенный шаг в удалении превращается в мусор на чужом сайте.
Обновления идут отдельным механизмом, а не простой перезаписью каталога модуля. Новая версия приезжает архивом, внутри которого лежит сценарий обновления: он копирует файлы и меняет структуру данных. Обычной перезаписи каталога недостаточно, потому что у покупателя может стоять версия, отставшая на несколько выпусков.
Чужие проекты устроены непредсказуемо, и это главная сложность публикации. Другая редакция, другой набор модулей, другая версия PHP, второй сайт, свои обработчики тех же событий - всё это встречается разом, и модуль обязан вести себя предсказуемо или внятно отказываться работать.
Наконец, публикация - это обязательство перед покупателем на годы вперёд. Ошибка в чужом магазине становится вашей задачей вне зависимости от того, чем вы заняты; поэтому решение о публикации принимают, оценив не только выгоду, но и поддержку на годы вперёд.
Отдельно стоит понимать, что покупатель будет ставить модуль на проект с чужой историей: с включённым композитом, с десятком других решений и с обменом, который идёт каждые пять минут. Модуль, проверенный только на аккуратном стенде, встречает всё это в первый же день продаж и ведёт себя совсем не так, как задумывалось.
Шаги
- Получить код партнёра и задать по нему постоянный идентификатор модуля вида
partner.module. - Написать установку и удаление так, чтобы второе полностью отменяло первое.
- Разложить файлы по каталогам установки: компоненты, страницы админки, языковые файлы.
- Собрать архив обновления со сценарием и проверить переход с любой прежней версии.
- Поставить модуль на чистую копию платформы и пройти сценарии целиком.
- Описать требования и ограничения в тексте, который прочитает будущий покупатель.
Код
Задаём идентификатор и версию:
$arModuleVersion = ['VERSION' => '1.2.0', 'VERSION_DATE' => '2026-08-06 12:00:00'];
// install/index.php$this->MODULE_ID = 'vendor.shop'; // код партнёра плюс имя модуля$this->PARTNER_NAME = 'Компания «Вендор»';$this->PARTNER_URI = 'https://example.org';Идентификатор модуля начинается с кода партнёра. Он же становится именем каталога и приставкой всех настроек, поэтому меняют его только вместе с выпуском нового модуля, а не новой версии.
Делаем установку и удаление зеркальными:
public function DoInstall(){ $this->InstallDB(); // таблицы $this->InstallEvents(); // обработчики событий $this->InstallFiles(); // компоненты и страницы админки ModuleManager::registerModule($this->MODULE_ID);}public function DoUninstall(){ ModuleManager::unRegisterModule($this->MODULE_ID); $this->UnInstallFiles(); $this->UnInstallEvents(); $this->UnInstallDB(); // с вопросом: удалять ли данные покупателя}Удаление обязано убирать всё, что поставила установка. Единственное исключение - данные: их удаляют только с явного согласия, потому что случайное удаление модуля не должно стоить покупателю накопленной за год информации.
Копируем файлы туда, где они переживут обновление:
public function InstallFiles(){ CopyDirFiles(__DIR__ . '/components', $_SERVER['DOCUMENT_ROOT'] . '/bitrix/components', true, true); CopyDirFiles(__DIR__ . '/admin', $_SERVER['DOCUMENT_ROOT'] . '/bitrix/admin', true, true); return true;}// файлы модуля живут в его каталоге, а в общие каталоги кладут только точки входаОбщие каталоги трогают минимально. Чем меньше файлов модуль раскладывает по чужим местам, тем меньше он конфликтует с другими решениями и тем чище удаляется.
Выпускаем обновление сценарием:
// updater.php внутри архива обновленияif ($updater->CanUpdateKernel()) { $updater->CopyFiles('install/components', 'components');}$updater->Query("ALTER TABLE b_vendor_shop ADD COLUMN STATUS varchar(20)", true);// сценарий должен переживать переход с любой прежней версии, а не только с соседнейОбновление приходит архивом со своим сценарием. Он выполняется у покупателя, чью версию вы не выбирали, поэтому изменения структуры пишут так, чтобы повторный запуск ничего не ломал.
Проверяем на чистой копии:
1. пустая установка платформы нужной редакции2. установка модуля, проход по всем его сценариям3. удаление модуля и проверка: не осталось ли таблиц, файлов и настроек4. установка прежней версии и обновление до новой5. повтор на второй редакции и на втором сайтеМодуль ставят на пустую копию, а не на свой проект. На своём проекте работает половина того, что на самом деле тянется из его настроек, и именно эта половина ломается у первого покупателя.
Сообщаем о несовместимости внятно:
if (!\Bitrix\Main\Loader::includeModule('sale')) { $APPLICATION->ThrowException('Модуль требует установленного модуля «Интернет-магазин»'); return false; // отказываемся работать, а не падаем на первой строке}if (version_compare(SM_VERSION, '22.0.0', '<')) { $APPLICATION->ThrowException('Нужна версия главного модуля не ниже 22.0'); return false;}// проверку версии делают до установки таблиц: откатывать половину сложнееОтказ с понятным сообщением стоит дешевле любой поддержки. Покупатель, увидевший строку про недостающий модуль, решает вопрос сам за минуту, а покупатель, увидевший белый экран, пишет вам письмо и ждёт ответа сутки.
Ограничения
Модуль не имеет права править файлы ядра и чужих модулей. Это не рекомендация, а условие публикации: решение, которое переписывает штатные файлы, ломается при первом же обновлении продукта у покупателя.
Редакции платформы заметно различаются между собой набором доступных в них штатных модулей. Код, обращающийся к магазину или к бизнес-процессам, обязан проверять их наличие и внятно сообщать, что без них модуль не работает, а не падать с ошибкой на первой строке.
Поддержка растягивается на годы вперёд и стоит дороже самой разработки. Покупатель, купивший модуль сегодня, придёт с вопросом через два года, и к этому моменту у него будет другая версия платформы, другая версия PHP и полностью забытые вами подробности.
Цену и условия поддержки продумывают до публикации, а не после первых продаж. Бесплатный модуль с сотней установок отнимает столько же времени, сколько платный, но не даёт ни рубля на это время, и решение об этом принимают заранее.
Публикация требует и текста для покупателя, а не только одного рабочего кода. Описание, снимки экрана, список требований и понятная инструкция по настройке отнимают не меньше времени, чем последний рабочий модуль, и без них модуль не покупают.
Типичные проблемы
После удаления модуля в базе остались его таблицы.
Удаление не отменяет всего того, что делала его собственная установка. Шаги удаления пишут зеркально шагам установки, один в один.
У покупателя модуль сломался после обновления продукта.
Модуль правил файлы ядра или полагался на их внутреннее устройство. Публикуемый модуль работает только со своим собственным каталогом файлов и своих таблиц.
Обновление не встаёт на старую версию.
Сценарий обновления рассчитан только на переход с соседней версии. Он должен переживать переход с любой прежней версии этого модуля.
Модуль падает на младшей редакции.
Код обращается к модулю, которого в этой редакции платформы попросту нет вовсе. Наличие нужных модулей проверяют и внятно сообщают самому покупателю об их отсутствии.
На чистой копии модуль не работает.
Он опирался на настройки и на данные вашего собственного рабочего проекта сайта. Проверку ведут на пустой установке, а не на своём сайте.
Частые вопросы
Можно ли опубликовать модуль без кода партнёра?
Нет: идентификатор модуля строится из него. Код получают в партнёрском кабинете до разработки.
Удалять ли данные покупателя при удалении модуля?
Только с явного подтверждения. Молчаливое удаление накопленных данных - худшее, что может сделать модуль.
Как проверить обновление с давней версии?
Поставить ту версию на чистую копию и обновить. Другого честного способа нет.
Сколько времени занимает поддержка?
Больше, чем разработка, и растянута на годы. Это стоит оценить до публикации, а не после.
Обязательно ли поддерживать второй сайт и язык?
Для публикуемого модуля - да: у покупателя может быть и то, и другое. Проверяют это на той же чистой копии.
Смежное
- Свой модуль - оглавление подтемы
- Свой модуль или код в проекте: когда пора выносить в модуль - решение об упаковке до публикации
- Мастер тиражного решения: шаги, макросы, публичная часть - мастер для тиражного решения
- Свой модуль не устанавливается: разбор причин - что проверяют перед передачей решения
- Свой модуль: структура, установка, автозагрузка классов - из чего он состоит
- Языковые файлы: сообщения, подстановки, второй язык - тексты для чужих проектов
- Готовое решение в проекте: установка, вмешательство, удаление - та же история со стороны покупателя
- Модули и решения - устройство модулей целиком