Когда стандартной логики CMS не хватает: кастомный модуль ProcessWire
Штатные поля и шаблоны закрывают типовой контент-сайт: страницы, категории, связи, вывод по условию. Предел наступает, когда логика начинает зависеть от данных, а не от структуры: расчёт стоимости по набору параметров, синхронизация каталога с внешней системой, права на уровне отдельной записи, сценарии, где одна операция меняет состояние нескольких связанных сущностей. В этот момент штатных полей перестаёт хватать, и в шаблонах появляются обходные решения — выборки в цикле, логика в разметке, дублирующиеся проверки.
Такой код работает до первой правки требований, а дальше каждая доработка тянет за собой перепроверку всего, что рядом.
Расширение CMS через кастомный модуль ProcessWire переносит эту логику туда, где её видно и можно проверить: в отдельный класс с точками подключения к ядру. Хуки позволяют встроиться в нужный момент жизненного цикла — до сохранения страницы, после изменения поля, при выборке — и не трогать остальной код. Собственный тип поля (Fieldtype) описывает хранение и валидацию данных на уровне ядра, поэтому значение ведёт себя как штатное: его видно в админке, по нему работают выборки, оно переживает обновления.
Процесс (Process) добавляет в панель управления свой экран — например, для запуска синхронизации или разбора очереди, — вместо того чтобы держать эти операции в отдельных скриптах.
Цена такого подхода ниже, чем кажется на старте. Логика лежит в одном месте, её покрывают тестами, а не проверяют руками на бою; при обновлении ядра модуль остаётся совместимым, потому что опирается на документированные точки расширения, а не на внутренности шаблонов. Нестандартная логика перестаёт быть хрупкой надстройкой и становится частью системы с предсказуемым поведением.
Дальше разбираем, как это закрывается на практике: какие точки расширения выбираем под задачу, как разделяем хранение и поведение и что остаётся заказчику после сдачи.
Что даёт кастомный модуль ProcessWire: хуки, Fieldtype, Process
Кастомный модуль ProcessWire собирается из трёх независимых механизмов расширения: перехвата событий, собственных типов полей и административных процессов. Их комбинируют под задачу — каждый закрывает свой класс ограничений и даёт измеримый эффект.
Перехват событий: логика без правки ядра
Хуки (addHookBefore, addHookAfter, addHookProperty) навешиваются на методы ядра и вызываются до или после них. Это позволяет менять поведение сохранения страниц, выборок и рендеринга, не трогая исходники и не теряя обновляемость: после апгрейда ветки правки остаются в модуле, а не в форке. На практике это убирает целый класс регрессий — типовой сценарий «правка ядра, которую забыли перенести» просто перестаёт возникать.
Собственный тип поля: структура данных вместо свалки
Fieldtype в паре с Inputfield описывает новый тип поля: как значение хранится в таблице, как валидируется, как выводится в редакторе. Вместо текстового поля с сериализованным JSON заказчик получает типизированную структуру — составной адрес, справочник, набор связанных записей. Выборки по такому полю идут через индексы, а не через разбор строки на каждом запросе, поэтому каталог на десятки тысяч страниц отвечает предсказуемо.
Process-модуль: свой раздел админки
Process-модуль регистрирует отдельную страницу в административной панели с собственным обработчиком запросов и правами доступа. Это выносит рутинные операции — импорт, массовую правку, сверку с внешней системой — в интерфейс для контент-менеджера, вместо скрипта, который запускает разработчик. Редактор перестаёт ждать инженера на каждую пачку правок.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Хуки | Меняем поведение существующей логики | Не создают новых сущностей и полей |
| Fieldtype + Inputfield | Нужна новая структура данных с валидацией | Требует продуманной схемы хранения |
| Process-модуль | Свой раздел админки и права | Не влияет на фронтенд-вывод |
| Внешний сервис | Логика живёт вне CMS | Дублирование доступа и синхронизация |
Механику удобно проверять на живом примере — документация ProcessWire описывает каждый из трёх интерфейсов отдельно, включая порядок вызова хуков и требования к методам Fieldtype.
Что это даёт по итогу: обновления ядра ставятся без конфликтов, структура данных остаётся типизированной, а рутинные операции уходят из очереди к разработчику в интерфейс редактора.
Как мы проектируем и внедряем модуль: от аудита до передачи
Работа над кастомным модулем ProcessWire идёт от текущего состояния проекта, а не от абстрактного шаблона: сначала разбираем, как логика устроена сегодня, затем фиксируем схему модуля и только потом пишем код. Такой порядок снимает главный риск — модуль, который формально работает, но конфликтует с существующими хуками и полями.
- Аудит текущей логики. Смотрим, какие хуки уже перехватывают события, где дублируется бизнес-логика в шаблонах, какие поля и типы страниц задействованы. На выходе — карта точек расширения и список мест, куда встраиваться безопасно.
- Проектирование модуля. Определяем состав: какие хуки подключаем, нужен ли собственный Fieldtype для хранения данных, требуется ли Process-страница в админке для управления. Фиксируем конфигурацию модуля, права доступа и поведение при отказе.
- Схема данных и миграции. Описываем, какие поля и таблицы появляются, как они связаны с существующими страницами, что происходит при обновлении модуля. Отдельно продумываем обратимость: как откатиться, если новую версию придётся снять.
- Реализация. Пишем модуль с разделением на слои: хуки отвечают за перехват событий, Fieldtype — за хранение и валидацию, Process — за интерфейс администратора. Логика не расползается по шаблонам, её можно менять в одном месте.
- Проверка на копии. Разворачиваем модуль на копии боевого сайта с реальными данными: прогоняем сценарии создания, редактирования и удаления, проверяем поведение под нагрузкой и на граничных случаях. Ошибки ловим до выкладки, а не после.
- Выкладка и мониторинг. Устанавливаем модуль на боевой сайт с возможностью быстрого отключения, следим за журналами и откликом. Если что-то идёт не так — возвращаемся к предыдущему состоянию без потери данных.
- Передача кода и документации. Отдаём репозиторий с историей изменений, описание хуков и полей, инструкцию по обновлению и откату, заметки по конфигурации. Ваши инженеры могут сопровождать модуль дальше без нас.
Каждый этап заканчивается артефактом: карта логики, схема модуля, набор тестовых сценариев, документация. Это делает передачу кода предсказуемой — вы получаете не «чёрный ящик», а модуль, устройство которого понятно вашей команде.
Чем хук отличается от собственного Fieldtype и когда нужен Process?
Хук — это перехват уже существующего поведения ядра или другого модуля без правки их кода. Он срабатывает в конкретной точке жизненного цикла: до или после сохранения страницы, при формировании выборки, на рендере шаблона. Хук не создаёт новых сущностей — он меняет то, как система обрабатывает уже существующие данные. Если задача звучит как «при сохранении страницы пересчитать связанное поле» или «подменить вывод в листинге», точка расширения — хук, и ничего больше городить не нужно.
Fieldtype отвечает за другой слой: он вводит новый тип данных со своей схемой хранения, формой ввода в админке и правилами валидации. Это выбор, когда штатных типов не хватает — например, нужно поле со составным значением, которое хранится не как строка, а как структура, и должно корректно вести себя в выборках, сортировке и поиске. Fieldtype тянет за собой Inputfield для интерфейса и, при необходимости, собственный тип страницы-хранилища. Это самый тяжёлый из трёх вариантов: ошибка в схеме хранения проявляется на всех страницах с этим полем, а миграция данных потом стоит дорого.
Process создаёт отдельный административный раздел — свою страницу в админке со списком, формами и действиями. Он нужен, когда у задачи есть самостоятельный интерфейс: импорт из внешнего источника, массовые операции над деревом страниц, панель настроек, не привязанная к одной странице. Process не меняет поведение существующих данных напрямую — он даёт оператору инструмент, который эти данные создаёт или изменяет.
Выбор точки расширения — это выбор минимально достаточного вмешательства. Сначала проверяем, закрывает ли задачу хук; если нужен новый тип данных — Fieldtype; если нужен отдельный экран для работы с данными — Process. На практике архитектура модуля часто комбинирует все три: Process даёт админ-раздел, Fieldtype хранит структуру, хуки связывают их с остальной системой. Такое разделение оставляет каждый слой тестируемым по отдельности и не превращает модуль в монолит, который страшно обновлять.
Кейс: как кастомный модуль убрал ручную работу и класс отказов
До внедрения каталог из нескольких тысяч карточек вёлся руками: контент-менеджер открывал каждую запись, переносил значения из таблицы поставщика в поля, вручную проставлял категории и связи между товарами. На одной партии это занимало несколько часов, а копии одной и той же карточки расходились по структуре — часть полей заполнена, часть пуста, где-то категория указана текстом вместо ссылки.
Ошибки были предсказуемы и однотипны: дубли карточек, битые связи, поля с неверным типом данных. Каждая такая запись ломала выборки и выдачу — страница либо не открывалась, либо показывала пустой блок. На поиск и починку уходило больше времени, чем на саму загрузку.
Что изменили
Собрали кастомный модуль ProcessWire, который закрывает весь путь импорта внутри админки. Хук на сохранение страницы проверяет типы полей и обязательные значения до записи в базу — некорректная карточка просто не сохраняется, а менеджер видит, какое поле нужно поправить. Собственный Fieldtype хранит составной набор атрибутов как единое значение, поэтому связи и категории больше не рассинхронизируются между собой.
Отдельный Process добавляет в админку экран пакетной загрузки: файл поставщика разбирается, сопоставляется с существующими карточками по внешнему идентификатору, обновляет совпадения и создаёт только новые записи. Повторный импорт того же файла не плодит дубли — операция идемпотентна.
Метрики до и после
| Показатель | До | После |
|---|---|---|
| Ручных операций на партию | сотни | одна загрузка файла |
| Время публикации партии | несколько часов | минуты |
| Дубли и битые связи | регулярно | класс ошибок устранён |
| Откат неудачного импорта | ручная правка | возврат к предыдущему состоянию |
Ключевой эффект — не скорость сама по себе, а исчезнувший класс отказов: неверные типы и дубли отсекаются на входе, а не обнаруживаются через неделю в выдаче. Логика проверок и сопоставления построена на штатном API ядра ProcessWire, поэтому обновление системы не ломает модуль.
Контент-менеджер теперь тратит время на проверку результата, а не на перенос значений. Если у вас похожий ручной процесс — опишите задачу, вернёмся с оценкой и планом.
Совместимость, откат и доступы: что обсудить до старта
Кастомный модуль processwire живёт внутри ядра, поэтому первое, что проверяем до старта, — совместимость модуля с текущей веткой ProcessWire и версиями PHP на ваших серверах. Если проект на LTS-ветке, а хостинг держит старый интерпретатор, часть API может вести себя иначе: хуки цепляются, но поведение меняется на граничных вызовах. Поэтому фиксируем матрицу «версия ядра / версия PHP / используемые хуки и Fieldtype» и прогоняем её на копии вашего окружения, а не на чистой сборке.
Что если обновление ядра сломает модуль? Мы не патчим ядро — модуль ставится отдельным пакетом и подключается штатным механизмом. Перед выкаткой готовим безопасный откат: снимок базы, резервную копию файлов модуля и точку возврата на предыдущий релиз. Откат — это одна операция, а не восстановление из архива вручную, поэтому окно недоступности измеряется минутами.
Как разграничиваются права? Уровни доступа описываем сразу: роли в админке, права на Process-страницы, ограничения на поля и операции записи. Отдельно проговариваем, кто из вашей команды получает доступ к управлению модулем, а кто — только к контенту, чтобы правка настроек не оставалась за одним человеком.
Что войдёт в передачу документации?
Схема модуля с точками подключения хуков, описание Fieldtype и Process-страниц, матрица совместимости, инструкция по откату и разграничению ролей. Плюс регламент обновления ядра — что проверять перед сменой ветки, чтобы модуль не отвалился.
На руки вы получаете:
- исходники модуля с историей изменений;
- схему подключения хуков и кастомных типов полей;
- матрицу совместимости с версиями ядра и PHP;
- инструкцию по безопасному откату и резервному копированию;
- описание уровней доступа и ролей в админке;
- регламент обновления ядра без потери работоспособности модуля.
Опишите вашу текущую конфигурацию — версию ядра, хостинг и задачи модуля. Вернёмся с оценкой, планом работ и списком того, что понадобится с вашей стороны для доступа к окружению.







