Коли стандартної логіки 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;
- інструкцію з безпечного відкату і резервного копіювання;
- опис рівнів доступу і ролей в адмінці;
- регламент оновлення ядра без втрати працездатності модуля.
Опишіть вашу поточну конфігурацію — версію ядра, хостинг і задачі модуля. Повернемося з оцінкою, планом робіт і списком того, що знадобиться з вашого боку для доступу до середовища.







