В Albireo CMS нет плагинов и некоторых это удивляет. Большинство систем используют плагины для расширения своего функционала, но я считаю, что это неверный путь, поскольку он порождает множество проблем.

Функционал плагинов
Если вы посмотрите на любой плагин любой CMS, то увидите, что он состоит из «обвязки», через которую он интегрируется в систему, а также функцию, которая выполняет основную работу плагина. Например вывод текста «Hello, World!».
То есть любой плагин состоит из «основного кода», который может быть вынесен отдельно и использован отдельно:
function hello()
{
return 'Hello, World!';
}
Интеграция
Но система ничего не знает о функции плагина, поэтому требуется какой-то механизм, через который нужно это сделать.
Подход разный, но в целом — это некие предопределенные имена файлов или шаблоны, внутри которых располагается предопределенная функция «активации» или «регистрации» плагина, как такового.
Система сканирует каталог плагинов, получает имена каталогов, внутри ищет подходящий файл. Подключает его через require и проверяет некую функцию «регистрации», скажем hello_init().
Уже внутри этой функции, используется системная, которая вносит плагин в общий массив плагинов.
Дальше тонкости и нюансы CMS. Скажем может быть функция «активации», «деактивации» и т.п. То есть система предлагает набор функций для обеспечения «жизненного цикла» плагина.
Если в CMS плагины активируются только через админ-панель, то добавляется ещё обвязка по обслуживанию post-запросов от форм админки.
Реагирование
Плагин сам по себе не сработает, поскольку нужно «дёрнуть» его основную функцию hello(). И тут начинается интересное: кто именно её запустит?
CMS, построенные как аля-Вордпресс, используют систему хуков (hooks), или точнее действий (actions), которые срабатывают в разных частях системы. Хуков может быть очень много, но принцип работы у них один.
Например есть функция публикации записи. Внутри неё прописывается функция, которая выполнит все заданные actions:
function setPost()
{
// срабатывает хук «set_post»
runHooks('set_post');
// ...
}
Соответственно, в плагине при его активации нужно «привязать» основную функцию к хуку:
function hello_init()
{
addToHooks('set_post', 'hello');
}
В целом это типовой механизм hooks/actions, которые используют CMS.
Проблемы хуков/действий
Хуки имеют массу проблем. Например к хуку привязано 10 функций. В какой именно последовательности их выполнять? Очень часто это имеет высокую важность.
Другая проблема: что делать если хук должен возвращать какое-то значение? Скажем мы хотим добавить к заголовку страницы какой-то свой текст. То есть необходимо обеспечить правильную цепочку выполнения функций хуков так, чтобы их результат также правильно передавался по этой цепочке.
Из-за этого механизм хуков сильно разрастается и требует особой внимательности со стороны автора плагина. Если например, неверно указать тип возвращаемого значения, или забыть прописать return, то это скажется на всей цепочке выполнения, что приведет к краху работу всей системы.
Есть ещё и проблема множественности хуков. Скажем при публикации записи нужно прописать сразу несколько хуков: для проверки верности заголовков, текста, корректность рубрик и т.д. При этом, скажем текст можно обработать через хуки как «до», так и «после» его парсинга (скажем Markdown или BBCode). Или скажем, шорткоды должны срабатывать до основного парсинга текста или после?
То есть работа с хуками — это довольно сложная и запутанная задача. Но главная проблема в том, что система никак не контролирует уровень доступа к системе. Например можно написать безобидный плагин, который будет цепляться за хук «init» и тем самым иметь возможность влиять на любую другую часть системы. Скажем менять адреса страниц или делать скрытый редирект.
Поэтому сама по себе система хуков достаточно неэффективна и опасна.
Как это сделано в Albireo CMS
В моей системе нет хуков/действий, как у других. Поэтому любой «плагин» представляет собой ровно тот функционал, который ему необходим. У «плагина» нет задач по интеграции в систему.
Вместо этого используется нормальная логика подключения: например если нужно вывести текст в теле записи, то ровно так это и происходит:
Текст. <?= hello() ?> Еще текст.
Если разместить php-файл функции в предопределенный каталог, то система сама его подключит при загрузке. Если это php-класс, то сработает PSR4-автозагрузка.
Работа php-функции через другие механизмы
Функцию hello() можно разместить не только прямо в тексте, но и в сниппете, extras-файле или tpl-шаблонизаторе. Все они представляют собой обычный PHP, поэтому для них не требуется особая интеграция.
Дальше выполнение функции происходит либо в теле страницы через соответствующие функции системы, либо через поля. Например если сделать сниппет hello, то его можно указать в поле страницы:
snippet.content[hello]: +
Работа с текстом
Если php-функция предназначена для работы с текстом, то можно использовать поле text-function:
text-function: hello
При этом сама функция должна принимать и возвращать строку:
function hello(string $text): string
{
return $text . 'Hello, World!';
}
Если php-функция работает как парсер текста, то она строится аналогично:
parser: textsimple, hello
Во всех этих случаях Albireo CMS предлагает прямую интеграцию сторонней php-функции.
События (events)
События — это не хуки, хотя они в чём-то похожи. В Albireo CMS есть два предопределенных события: pageOut-start и pageOut-end, которые срабатывают до и после вывода контентного файла. Событие pageOut-start используется для подключения статистики прочтений записи (поле stat.page).
Управлять events можно через одноимённый конфиг-файл, где указывается само событие и php-класс с методом «срабатывания».
То есть в отличие от хуков, событие просто срабатывается и больше ничего не делает. При этом именно вебмастер контролирует все события и все функции, которые должны работать. Здесь невозможна ситуация, что какой-то php-код сам «прицепился» к какому-то событию (что постоянно происходит в системах аля-WordPress).
Событие может быть php-файлом
Строго говоря, в Albireo CMS свои события можно сделать ещё проще.
В основной конфигурации есть ключ functionsFile, где можно указать имя своего php-файла со своими функциями. Этот файл подключается перед событием pageOut-start и может содержать вообще произвольный код.
Итого
На мой взгляд концепция хуков ущербная и требует слишком много нагромождений там, где можно спокойно обойтись нативным PHP. Многие вебмастера привыкли к хукам, но на самом деле вопрос только в логике мышления. 😎