С версии 2.8.5 в системе появился новый способ организации php-скриптов, расширяющих функционал системы. Теперь для каждого шаблона на сайте можно писать свои кастомные макросы, расширяющие функционал стандартных модулей. При этом не нужно писать все макросы в один файл customMacros.php - можно распределять их по отдельным скриптам, подключая в один главный, так же как это сделано в стандартных модулях. Потом эти скрипты можно легко переносить в другие шаблоны, подключать, поддерживать и вносить необходимые правки.

Структура файлов

Новый формат расположения папок и файлов, относящихся к шаблонам и расширению функциональности сайта, предполагает наличие в корне сайта папки ~/templates/, в которой, в свою очередь, находятся директории шаблонов (их количество не ограничено) ~/templates/{имя_шаблона}/. В каждой из них может находиться собственная папка /classes/modules/, содержащая папки с именами модулей (/content/, /catalog/ и т.д.), в которые необходимо поместить файл class.php, который будет подключаться автоматически.

Пример скрипта

Рассмотрим новый формат расширения функциональности на примере модуля Структура:
Для начала, создадим файл class.php в папке модуля content того шаблона, который используется на нашем сайте - ~/templates/newTemplate/classes/modules/content/class.php. В этом файле нам нужно указать, что наш класс будет расширять стандартный класс "def_module". Имя создаваемого класса должно быть имямодуля_custom.

Важно:

Нельзя использовать в качестве имен классов и методов названия системных классов и методов!

Добавим новый макрос:

<?php
    class content_custom extends def_module {

        public function testMenu() {
            $temp = [
                'foo' => 'foo',
                'bar' => 'bar'
            ];

            return def_module::parseTemplate('', $temp);
        }

    };
?>

Обратите внимание, что файлы ~/classes/components/custom.php и ~/classes/components/{имя_модуля}/customMacros.php продолжают подключаться как и прежде.

Права доступа

Теперь мы можем использовать макрос content::testMenu в нашем шаблоне. Пока что он доступен только супервайзеру. Для того чтобы открыть макрос всем пользователям - создаём стандартную запись в файле permissions.php (рекомендуем ознакомиться с Cистемой прав доступа UMI.CMS), в той же директории что и class.php:

<?php
    $permissions['content'][] = 'testMenu';
?>

Обратите внимание на порядок подключения файлов с правами: Первым делом система производит поиск в файле ~/classes/components/{имя_модуля}/permissions.custom.php, затем в файле ~/classes/components/{имя_модуля}/permissions.php, и только потом в ~/templates/{имя_шаблона}/classes/modules/{имя_модуля}/permissions.php.

События

Работа с "Событиями" теперь также доступна в файле ~/templates/{имя_шаблона}/classes/modules/{имя_модуля}/events.php. Обратите внимание на порядок подключения файлов с перехватчиками событий: Первым делом система производит поиск в файле ~/templates/{имя_шаблона}/classes/modules/{имя_модуля}/events.php, затем в файле ~/classes/components/{имя_модуля}/custom_events.php, и затем в ~/classes/components/{имя_модуля}/events.php.
Такая последовательность подключения файлов даёт разработчику возможность прервать цепочку событий (для этого используется специальное системное исключение (throw new breakException();), что позволяет "перебить" системные события пользовательскими.

Распределение кода

Теперь, для удобной работы с кодом, мы рекомендуем распределить его по нескольким php-файлам. Допустим, мы создали файл temp.php в той же директории, что и class.php. Внесли в него некий код (ещё один макрос):

<?php
    class content_custom_temp {

        public function testMenu2() {
            $temp = [
                'foo' => 'foo',
                'bar' => 'bar',
                'baz' => 'baz'
            ];
            
            return def_module::parseTemplate('', $temp);
        }

    };
?>

Затем мы подключаем новый класс content_custom_temp в файле class.php - создаём функцию __construct, в которой принимаем экземпляр класса (в данном случае - экземпляр класса "content") из переменной $self:

<?php
    class content_custom extends def_module {

        public function __construct($self) {
            $self->__loadLib("/temp.php", (dirname(__FILE__)));
            $self->__implement("content_custom_temp");
        }

        public function testMenu() {
            $temp = [
                'foo' => 'foo',
                'bar' => 'bar'
            ];

            return def_module::parseTemplate('', $temp);
        }

    };
?>

И прописываем второй созданный макрос в файле permissions.php:

<?php
    $permissions['content'][] = 'testMenu';
    $permissions['content'][] = 'testMenu2';
?>

Теперь оба наших макроса можно использовать в шаблоне сайта.
Обратите внимание, что при использовании на сайте шаблонов нового формата, работа расширений функциональности (PHP) происходит следующим образом: при вызове вашего макроса через протокол udata (site.ru/udata://content/testMenu) и "напрямую" (site.ru/content/testMenu), отрабатывать будут те php-скрипты, которые находятся в той же директории (~/templates/{имя_шаблона}/), что и шаблон, назначенный "Основным" для данного домена.
В случае необходимости вызвать напрямую макрос из шаблона, не назначенного основным - следует добавить к строке вызова параметр "?template_id={идентификатор шаблона в админ-панели}".
При вызове же макроса на странице, будут отрабатывать php-скрипты, принадлежащие шаблону данной страницы.