Кастомный модуль Craft CMS: где ломается логика проекта
Штатная модель Craft CMS рассчитана на предсказуемые сущности: записи, категории, поля, права по ролям. Пока проект живёт в этих рамках, всё работает без вмешательства в ядро. Проблемы начинаются там, где бизнес-логика перестаёт быть типовой — и это не про «мало плагинов», а про то, что сама модель данных не описывает реальные отношения.
Первое узкое место — нестандартная логика прав. Встроенные роли оперируют разделами и группами записей, но не отвечают на вопросы вида «редактор видит только свои материалы внутри своего подразделения» или «согласующий может править поле, но не публиковать». Начинаются обходные пути через костыльные проверки в шаблонах, и каждое новое правило приходится вписывать вручную в десяток мест.
Второе — связи между сущностями. Когда запись должна ссылаться на несколько связанных объектов с разными типами отношений и условиями отображения, штатных полей Relations не хватает: теряется контекст связи, появляются дубли, а выборки становятся тяжёлыми. То же с интеграциями с внутренними системами — складом, CRM, биллингом: обмен требует промежуточной логики, которой в CMS просто нет.
Кастомный модуль Craft CMS решает это на уровне архитектуры: собственные таблицы и сервисы для связей, отдельный слой правил доступа, обработчики событий для интеграций. Ядро остаётся нетронутым — обновления CMS не ломают вашу логику. Разбираем, как это закрывается на практике.
Что даёт модуль: скорость, отказоустойчивость, контроль
Нестандартная логика, размазанная по шаблонам и плагинам, даёт три типовые проблемы: тяжёлые запросы на публичных страницах, отказы при обновлении ядра и непрозрачные права доступа. Вынос этой логики в отдельный модуль Craft CMS решает их на уровне архитектуры, а не точечными правками.
Скорость отклика
Модуль регистрирует собственные маршруты и сервисы, поэтому тяжёлые выборки уходят из шаблонов в контролируемый слой с кэшированием и ленивой загрузкой связей. На практике время ответа каталога и личных кабинетов падает в разы, а пиковые нагрузки перестают упираться в рендер шаблона.
Устранённые классы отказов
Логика в модуле не зависит от структуры шаблонов и порядка плагинов — обновление ядра или смена темы её не ломают. Отдельно закрывается класс отказов, связанных с гонками при записи: транзакции и очереди выносят тяжёлые операции из пользовательского запроса, и частично применённых изменений в базе не остаётся.
Предсказуемость обновлений
Модуль ставится и обновляется как отдельный пакет с миграциями схемы и версионированием. Обновление ядра перестаёт быть событием с ручной проверкой каждого шаблона: несовместимость выявляется на этапе миграций, а не на проде.
Контроль доступа
Права описываются декларативно — по ролям, разделам и отдельным действиям, а не разбросанными проверками в шаблонах. Это даёт единую точку аудита: видно, кто и что может, и любое изменение политики доступа проходит ревью, а не правится в десяти местах.
Эффект накапливается: чем больше нестандартных сценариев живёт в модуле, тем меньше поверхность для регрессий при каждом релизе.
Форматы реализации: встроенный модуль, плагин, внешний сервис
В Craft CMS кастомная логика живёт в трёх разных местах, и выбор между ними определяет, как проект будет сопровождаться дальше. Встроенный модуль — это код внутри проекта: он видит модели, события и очереди ядра напрямую, ставится вместе с приложением и не требует отдельного релизного цикла. Плагин — самостоятельный пакет с собственным жизненным циклом: его можно переиспользовать между проектами и обновлять независимо, но каждое обращение к внутренним API Craft нужно держать в совместимых границах.
Внешний сервис выносит логику за пределы приложения и общается с ним по сети — это снимает нагрузку с PHP-процессов, но добавляет сетевой отказ, задержку и отдельный контур развёртывания.
| Вариант | Когда подходит | Ограничения архитектуры |
|---|---|---|
| Встроенный модуль | Логика специфична для одного проекта, нужен прямой доступ к событиям и моделям ядра | Живёт только в этом проекте, обновляется вместе с ним, переиспользовать в другом сайте нельзя |
| Плагин | Функциональность повторяется на нескольких проектах или нужна изоляция версий | Требует стабильного публичного API, при мажорном обновлении Craft нужно поддерживать совместимость |
| Внешний сервис | Тяжёлые вычисления, интеграции, работа с внешними системами и своими данными | Сетевой отказ и задержка, отдельные доступы, логирование и мониторинг, синхронизация состояния |
На практике границы часто комбинируют: модуль держит бизнес-правила и события, внешний сервис забирает тяжёлое, а плагин появляется, когда решение доказало ценность и его пора переносить между проектами. Мы фиксируем этот выбор на этапе проектирования — от него зависят схема развёртывания, стратегия обновлений и то, сколько стоит поддержка через год.
Этапы внедрения: от аудита логики до передачи команде
Работу начинаем с аудита логики: разбираем, как задача решается сейчас — плагинами, ручными операциями редактора или правками в шаблонах. На этом шаге фиксируем точки, где логика дублируется, и места, которые ломаются при обновлении ядра. Результат аудита — карта зависимостей и список того, что модуль должен взять на себя.
- Аудит текущей логики. Собираем реальные сценарии работы редакторов и администраторов, смотрим, какие данные и события затрагивает задача. Определяем границы модуля: что уходит в него, что остаётся в ядре.
- Проектирование схемы модуля. Описываем структуру: сущности, поля, связи, права доступа по ролям. Отдельно проектируем миграции — чтобы структура данных разворачивалась на любом окружении одной командой.
- Настройка и сборка. Реализуем логику, выносим конфигурацию в файлы проекта, подключаем модуль без правок ядра. Так обновление платформы не затирает доработки.
- Проверка сценариев. Прогоняем модуль на реальных данных и граничных случаях: пустые выборки, массовые операции, одновременная работа нескольких редакторов. Каждый сценарий закрываем тестом.
- Приёмка на стенде. Показываем работу на копии боевого контента, сверяем поведение с исходной логикой. Правки вносим до выката, а не после.
- Передача команде. Отдаём документацию по структуре и настройкам, инструкцию для редакторов, порядок отката. Проводим разбор с вашими разработчиками, чтобы модуль можно было развивать без нас.
Каждый этап заканчивается артефактом, который можно проверить: карта зависимостей, схема данных, набор тестов, инструкция по эксплуатации. Так на выходе вы получаете не «чёрный ящик», а предсказуемый компонент с понятной зоной ответственности.
Что заказчик получает на руки: конфигурации, схемы, регламенты
Передаём не «работающий код на нашем сервере», а комплект, с которым ваша команда или другой подрядчик продолжит работу без нас. Ниже — что именно фиксируется в передаче по кастомному модулю.
- Конфигурации модуля — файлы настроек с описанием всех параметров: какие поля и типы контента модуль регистрирует, какие события перехватывает, какие значения по умолчанию. Настройки вынесены из кода, поэтому поведение меняется правкой конфигурации, а не доработкой.
- Схемы связей — карта того, как модуль взаимодействует с ядром системы, другими модулями и внешними сервисами: точки расширения, порядок вызовов, места, где логика зависит от сторонних данных.
- Политики доступа — матрица прав по ролям: кто видит разделы модуля, кто меняет настройки, кто только читает данные. Отдельно описаны проверки на стороне сервера, чтобы права не обходились через прямой запрос.
- Миграции и структура данных — сценарии изменения схемы хранилища с версионированием, чтобы обновление не ломало уже накопленные записи и корректно откатывалось.
- Документация модуля — назначение, публичные методы, примеры вызовов, ограничения и известные допущения. Достаточно, чтобы новый разработчик разобрался без переписки с автором.
- Регламенты обновления и отката — порядок выката изменений, проверки перед релизом, точки возврата к предыдущей версии и условия, при которых откат запускается автоматически.
- Инструкция по эксплуатации — типовые операции: включение и выключение модуля, ротация ключей, чтение логов, реакция на сбои внешних сервисов.
Комплект закрывает главный риск кастомной разработки — зависимость от одного исполнителя. Любой инженер, знакомый со стеком, поднимает модуль на чистом окружении по документации и продолжает развитие. Опишите задачу — вернёмся с оценкой и планом передачи.
Кейс: как модуль убрал ручные операции и ускорил отклик
Заказчик — сеть из нескольких десятков региональных представительств — вёл каталог товаров и остатки на Craft CMS. Контент-менеджеры обновляли цены и наличие руками: выгрузка из учётной системы приходила файлом, дальше построчный перенос, сверка, публикация. На пике — несколько сотен правок в день, и каждая ошибка в остатках уходила на витрину.
Мы разобрали узкое место: проблема была не в объёме данных, а в отсутствии слоя между учётной системой и редактором. Собрали кастомный модуль, который принимает выгрузку по расписанию, сопоставляет записи по внешнему идентификатору и обновляет поля через штатное API Craft — без прямых запросов в базу и без обхода кеша. Конфликты версий (кто правил последним) модуль разрешает по метке времени и пишет их в журнал, а не «молча» перезаписывает.
Что было до и что стало после
| Метрика | До | После |
|---|---|---|
| Обновление каталога | вручную, раз в сутки | по расписанию, каждые 15 минут |
| Правок руками в день | несколько сотен | единицы (только нестандартные случаи) |
| Ошибки в остатках | регулярные, ловились постфактум | отсекаются на приёме данных |
| Отклик витрины на изменение | часы | минуты |
Отдельно закрыли откат: каждое обновление пишет снимок изменённых записей, поэтому неудачную выгрузку можно отменить одной операцией, не восстанавливая базу целиком. Ручные операции из процесса ушли — менеджеры занимаются контентом, а не сверкой таблиц.
Чем отличается кастомный модуль от плагина из маркетплейса?
Плагин из маркетплейса — это готовое решение под типовой сценарий: форма обратной связи, простой импорт, базовая интеграция. Пока задача совпадает с тем, что автор заложил в плагин, всё работает предсказуемо. Проблема начинается там, где бизнес-логика уходит в сторону: нужен нестандартный расчёт, своя схема прав доступа, связка нескольких сущностей в один процесс. Тогда плагин либо не закрывает задачу, либо закрывает её частично — и вокруг него начинают расти обходные решения.
Кастомный модуль пишется под конкретный процесс, поэтому контроль логики остаётся у команды, а не у стороннего автора. Мы сами определяем структуру данных, порядок операций, точки расширения и то, как модуль ведёт себя при ошибках. Это принципиальная разница: в плагине вы принимаете чужие решения как данность, в модуле — проектируете их под свою задачу.
Зависимости — второй источник рисков. У плагина всегда есть цепочка: автор, его сроки поддержки, совместимость с актуальной веткой CMS, сторонние библиотеки внутри. При обновлении ядра такая цепочка рвётся в самый неудобный момент, и вы либо ждёте патч от автора, либо замораживаете обновления. Кастомный модуль мы держим на поддерживаемых интерфейсах ядра и обновляем вместе с ним — без ожидания третьей стороны.
Отсюда и разный класс рисков при обновлении CMS. Плагин может сломаться на мажорном апдейте, и починить его без доступа к исходникам нельзя. Модуль мы сопровождаем сами: видим, что изменилось в ядре, и правим точечно, не трогая остальную систему. Поэтому для процессов, которые дают бизнесу преимущество, модуль почти всегда выгоднее — вы не делите контроль над логикой с чужой командой.
Технические сомнения: обновления, безопасность, откат
Кастомный модуль живёт в кодовой базе проекта, а не в ядре системы, поэтому обновления CMS его не ломают: расширения подключаются через штатные точки расширения, а не правкой вендорных файлов. При мажорном обновлении мы прогоняем модуль по тестовому стенду с копией боевых данных — если контракт точек расширения изменился, адаптация занимает часы, а не недели переписывания с нуля.
Доступы разграничиваем по ролям и правам внутри самой CMS: контент-менеджер видит только свои разделы, администратор — настройки модуля, внешние интеграции ходят по отдельным ключам с ограниченным набором операций. Все действия с данными пишутся в журнал — видно, кто и когда менял запись, это же помогает при разборе инцидентов.
Что будет, если обновление CMS всё-таки сломает модуль?
Обновление ставим сначала на копию боевого окружения, а не на прод. Если модуль не проходит проверки, релиз CMS откатывается на предыдущую ветку, а модуль адаптируется отдельно — боевой сайт в это время работает без простоя. Перед каждым обновлением снимаем снимок базы и файлов, поэтому возврат к рабочему состоянию занимает минуты.
Как откатить изменения, которые внёс модуль?
Изменения контента версионируются: у каждой записи хранится история ревизий, и любую можно восстановить точечно, не откатывая всё остальное. Для изменений схемы данных готовим обратные миграции — они выполняются той же командой развёртывания, что и прямые, и проверяются на стенде до продакшена.
Модуль совместим со сторонними расширениями?
Да, если они используют штатные точки расширения, а не переопределяют ядро. Конфликты обычно возникают на уровне общих таблиц или перехвата одних и тех же событий — такие места мы выявляем на этапе проектирования и разводим по приоритетам обработки. Перед внедрением прогоняем сценарий с полным набором расширений заказчика.
Кто имеет доступ к серверу и базе после сдачи?
Доступы остаются у заказчика: мы работаем через отдельные учётные записи с ограниченными правами и журналированием, а не через общий административный вход. Это значит, что при смене подрядчика или инженера доступ отзывается одной операцией, без риска потерять контроль над системой.
Обсудим задачу: вернёмся с оценкой и планом
Чтобы вернуться с оценкой и планом, а не с общими словами, нам нужен минимум вводных по задаче. Кастомный модуль Craft CMS почти всегда вырастает из конкретного узкого места: нестандартный расчёт скидок, синхронизация каталога с внешней системой, роли и права, которых нет в базовом наборе, или свой тип контента со сложной логикой публикации. Чем точнее вы опишете, что сейчас происходит и что должно происходить, тем меньше допущений заложим в оценку.
Для старта достаточно следующего:
- описание бизнес-процесса: кто и что делает, где сейчас ломается или делается руками;
- примеры данных: выгрузка, скриншоты админки, образцы полей и связей между сущностями;
- как задача решается сегодня — внешним сервисом, таблицами, работой менеджера;
- требования к доступам: какие роли должны видеть и менять данные, что только читать;
- интеграции: с чем модуль обменивается данными и в какую сторону;
- ограничения: сроки, привязка к релизам, что нельзя ломать в текущем сайте;
- контакт человека, который примет работу и подтвердит логику.
В ответ мы возвращаем оценку и план: разбивку на этапы с трудозатратами, черновик технического задания, схему данных и точек интеграции, список рисков и допущений, а также порядок выката — сначала на тестовом окружении, затем на боевом с возможностью отката. Если по ходу разбора всплывают неочевидные зависимости, фиксируем их отдельно, чтобы старт работ не превратился в пересмотр сроков.
Опишите задачу в свободной форме — этого хватит, чтобы вернуться с оценкой и планом.







