PageBlocks - мощный инструмент для MODX в стиле Laravel!

В популярных админках Laravel, таких как Nova или Filament, есть удобные конструкторы форм для создания страниц — можно легко добавлять поля, табы, таблицы. А вот в MODX всё иначе: чтобы создать кастомный таб и наполнить его нужными полями, приходится немало повозиться. Всё это делается через админку, что усложняет поддержку.

PageBlocks решает эту проблему! Теперь табы, поля и таблицы можно создавать прямо из PHP-кода, без необходимости копаться в админке. Это значит, что вы можете обновлять интерфейс через GitHub и управлять им из своего любимого редактора кода.

PageBlocks чётко разделяет зоны ответственности:
Контент-менеджеры работают в админке.
Разработчики управляют интерфейсом через код.

PageBlocks приносит Laravel-подход в MODX — удобно, масштабируемо, понятно! 🚀





По умолчанию настройка блоков и таблиц осуществляется через админку, однако теперь вы можете активировать режим разработки, переключившись на developer, и создавать блоки в удобном для вас редакторе кода. Для этого необходимо изменить значение системной настройки pageblocks_development_mode.

Tab


Класс Tab используется для создания вкладок (табов) в ресурсе.

Пример использования:
Tab::make('Custom tab')
    ->id('extra')
    ->position(2)
    ->fields([
        Field::make('notes')->type('textarea')->label('Заметки'),
        Field::make('status')->type('select')->values([
            'active' => 'Активный',
            'inactive' => 'Неактивный'
        ]),
    ]);
В этом примере создается вкладка «Custom tab» с id = extra, которая будет второй по порядку и содержать два поля.

Доступные методы:

  • position(int $position) – Устанавливает позицию вкладки.
  • Если не указано, вкладка добавляется в конец стандартных.
    Tab::make('Основное')->position(1);
  • id(string $id) – Указывает идентификатор вкладки (не обязательно).
  • Tab::make('Настройки')->id('settings');
  • fields(array $fields) – Задает список полей, которые будут внутри вкладки.
  • Tab::make('SEO')->fields([
        Field::make('meta_title')->label('Meta Title'),
        Field::make('meta_description')->type('textarea')->label('Meta Description')
    ]);

Field


Класс Field используется для создания полей в ресурсе, таблице или блоке.

Для создания поля достаточно написать:
Field::make('name'); // Будет создано текстовое поле с именем 'name'.

Чтобы задать название (ярлык) поля, можно использовать метод label:
Field::make('name')->label('Name');
// или еще короче
Field::make('Name');

Базовые методы
Эти методы позволяют настроить основные параметры поля.
  • type(string $type) – Устанавливает тип поля (text, number, date, select и т. д.).
  • label(string $label) – Задает название (ярлык) поля.
  • description(string $description) – Добавляет описание поля.
  • help(string $help) – Показывает вспомогательный текст.
  • default(mixed $default) – Устанавливает значение по умолчанию.
  • required(bool $required = true) – Делает поле обязательным.
  • disabled(bool $disabled = true) – Отключает редактирование поля.
  • readOnly(bool $readonly = true) – Устанавливает поле только для чтения.
  • width(int $width = 100) – Задает ширину поля в процентах.
Текстовые поля (textarea, richtext)
  • height(int $height) – Устанавливает высоту поля (только для textarea и richtext).
Заголовок (heading)
  • html(string $html) – Позволяет вставить HTML-код в заголовок.
Маска ввода (imask)
  • options(string $options) – Устанавливает параметры маски ввода.
Числовое поле (number)
  • allowDecimals(bool $allowDecimals = true) – Разрешает использование десятичных чисел.
  • decimalSeparator(string $decimalSeparator) – Устанавливает символ-разделитель для десятичных чисел.
  • decimalPrecision(int $decimalPrecision) – Определяет количество знаков после запятой.
  • allowNegative(bool $allowNegative = true) – Разрешает отрицательные значения.
  • minValue(int $minValue) – Устанавливает минимальное значение.
  • maxValue(int $maxValue) – Устанавливает максимальное значение.
Выпадающий список (select)
  • multiple(bool $multiple = true) – Включает возможность выбора нескольких значений.
  • model(string $model) – Указывает модель для загрузки данных.
  • displayField(string $displayField) – Указывает поле модели для отображения значений.
  • valueField(string $valueField) – Определяет поле модели, из которого берутся значения.
  • where(array $where) – Позволяет задать условия выборки данных.
  • sortby(string $sortby) – Устанавливает поле для сортировки.
  • sortdir(string $sortdir) – Определяет направление сортировки (ASC или DESC).
  • limit(int $limit) – Ограничивает количество загружаемых записей на странице.
  • values(array|callable $values) – Устанавливает статический список значений для выбора.
  • Можно передать массив:
    Field::make('status')->values([
        'active' => 'Активный',
        'inactive' => 'Неактивный',
        'pending' => 'В ожидании'
    ]);
    Или использовать функцию-генератор:
    Field::make('resource')->values(function() {
        $modx = self::getModx();
        $resources = $modx->getCollection(\modResource::class, [
            'published' => true,
        ]);
    
        return array_column($resources, 'pagetitle', 'id');
    })
Дата и время (datetime)
  • hiddenFormat(string $hiddenFormat) – Устанавливает скрытый формат даты.
  • dateFormat(string $dateFormat) – Определяет формат отображаемой даты.
  • startDay(int $startDay) – Устанавливает первый день недели (0 – воскресенье, 1 – понедельник).
  • minDateValue(int $minDateValue) – Указывает минимальную допустимую дату.
  • maxDateValue(int $maxDateValue) – Указывает максимальную допустимую дату.
  • hideTime(bool $hideTime = true) – Скрывает выбор времени.
  • timeFormat(string $timeFormat) – Определяет формат времени.
  • timeIncrement(int $timeIncrement) – Устанавливает шаг изменения времени (например, каждые 15 минут).
  • minTimeValue(string $minTimeValue) – Минимально допустимое время.
  • maxTimeValue(string $maxTimeValue) – Максимально допустимое время.
  • disabledDates(array $disabledDates) – Список недоступных для выбора дат.
  • disabledDays(array $disabledDays) – Список заблокированных дней недели (0 – воскресенье, 1 – понедельник и т. д.).
Файлы (image, video, file, gallery)
  • source(int $source) – Устанавливает источник файлов.
  • sourcePath(string $sourcePath) – Определяет путь к файлам.
  • openTo(string $openTo) – Указывает папку, в которую откроется менеджер файлов.
Галерея (gallery)
  • thumbnails(string $thumbnails) – Задает шаблон эскизов изображений.
  • Field::make('gallery')
            ->label('Images')
            ->type('gallery')
            ->source(1)
            ->sourcePath('/assets/images/')
            ->thumbnails('{"webp":{"w":120,"h":90,"q":90,"zc":"1","bg":"000000","f":"webp"}}')
Ключ-значение (keyvalue)
  • keyLabel(string $keyLabel) – Определяет заголовок для ключа.
  • valueLabel(string $valueLabel) – Определяет заголовок для значения.
Таблица (table)
  • columns($columns) – Устанавливает колонки таблицы.
  • searchable(bool $searchable = true) – Разрешает поиск по таблице.
  • filters(array $filters) – Добавляет фильтры к таблице.
  • fields(array $fields) – Определяет список полей внутри таблицы.
  • Принимает массив полей, которые будут использоваться в таблице:
    Field::make('products')->fields([
        Field::make('name')->label('Название'),
        Field::make('price')->type('number')->label('Цена'),
        Field::make('stock')->type('number')->label('Остаток')
    ]);
Зависимость полей
  • hidden(string $field, string $operator, mixed $value) – Скрывает текущее поле в зависимости от значения другого поля.
    • $field – Название поля, от которого зависит текущее.
    • $operator – Оператор сравнения (>, <, >=, <=, =, !=, ><, !><, IN, NOT IN).
    • $value – Значение, с которым сравнивается поле.
    Field::make('discount')->type('number')->hidden('has_discount', '!=', 1);
    В этом случае поле discount будет скрыто, если has_discount не равно 1.

Column


Класс Column предназначен для создания колонок внутри поля с типом table. Позволяет задавать заголовки, идентификаторы, ширину, сортировку и тип рендеринга.

Пример использования:
Field::make('products')->type('table')->columns([
    Column::make('name')->label('Название')->sortable()->width(200),
    Column::make('price')->label('Цена')->sortable()->width(100),
    Column::make('createdon')->label('Дата добавления')->render('date')->sortable(),
    Column::make('published')->label('Опубликовано')->render('boolean'),
    Column::make('image')->label('Изображение')->render('image')->width(150),
]);

Доступные методы:
  • label(string $label) – Устанавливает заголовок колонки.
  • id(string $id) – Устанавливает уникальный идентификатор колонки.
  • render(string $render) – Определяет способ отображения данных. Доступные значения:
  • sortable(bool $sortable = true) – Включает или отключает сортировку по этой колонке.
  • width(int $width) – Устанавливает ширину колонки в пикселях. Если не указано, ширина будет определяться автоматически.

Block


Класс Block используется для создания блоков в ресурсе, позволяя организовывать поля в логические группы.

Пример использования:
Block::make('Основная информация')
    ->chunk('main_chunk')
    ->description('Основные данные ресурса')
    ->fields([
        Field::make('title')->label('Заголовок'),
        Field::make('content')->type('textarea')->label('Контент'),
    ]);

Доступные методы:
  • chunk(string $chunk) – Устанавливает чанк, к которому будет привязан блок.
  • description(string $description) – Устанавливает описание блока.
  • fields(array $fields) – Задает список полей, которые будут внутри блока.

Проблемы:


На данный момент обнаружены следующие проблемы:
  1. Не работает удаление строк для поля с типом keyvalue в MODX3
  2. Ошибка в JavaScript после сохранения ресурса, если в текстовые поля ресурса были добавлены теги, но при этом все данные сохраняются.


Предстоящие задачи:


  • Исправление проблем, что выше описаны
  • Разработка модели User для управления профилями пользователей.
  • Создание конструктора pbResources, упрощающего создание коллекций ресурсов.
  • Интеграция Eloquent ORM для удобной работы с базой данных.
  • Расширение возможностей шаблонизатора Fenom добавлением необходимых модификаторов.
  • Реализация класса Validation для валидации данных, поступающих в REST API.
  • Создание класса Request для упрощения работы с HTTP-запросами.
Aleksandr Huz
07 февраля 2025, 12:12
modx.pro
2
993
+15
Поблагодарить автора Отправить деньги

Комментарии: 20

Miša Bulic
07 февраля 2025, 20:33
+1
Браво!
    Andrew
    09 февраля 2025, 17:37
    +1
    Крутяк)
      Дмитрий
      10 февраля 2025, 18:25
      +1
      Отличный компонент, иногда кажется громоздким, но его возможности и гибкость при правильном подходе позволяют получать очень хорошие результаты. Нужно немного разобраться, а дальше любая сложность и структура страницы набирается довольно просто и быстро. Очень широкий функционал и набор типов полей, таблицы. Для сложных сайтов необходимая вещь.
        Сергей Сергеевич
        10 февраля 2025, 21:07
        0
        А в чем его преимущество перед MIGX, помимо нового функционала из этой новости? Я просто не понимаю, в чем его преимущество, и останавливает то, что нет файловых элементов. Все надо через админку.
          Дмитрий
          10 февраля 2025, 21:41
          0
          создаёте файл, создаете статический чанк и указываете путь до файла в нём. Но сам чанк в админке создать всё равно придётся, это да. Как и сами блоки. C migx тоже всё через админку: собрать конфу, создать TV поле. Никак не обойтись без админки так или иначе.

          Ну а в целом на вкус и цвет, наверно чтобы понять, «в чем его преимущество» — нужно поставить и попользоваться, чтобы сделать для себя какие-то выводы.
            Aleksandr Huz
            10 февраля 2025, 22:02
            0
            Но сам чанк в админке создать всё равно придётся, это да.
            Нет, это не обязательно. Можно создавать только файловые чанки.

            Как и сами блоки.
            С последнем обновлением, это тоже не обязательно. Можно в файле core/App/Models/Resource.php создавать блоки и таблицы
            Aleksandr Huz
            10 февраля 2025, 21:59
            +3
            1. Интуитивный интерфейс
            Проще и понятнее, чем в MIGX.

            2. Поддержка разных типов полей
            В MIGX, чтобы добавить, например, галерею, придётся повозиться. В PageBlocks это делается в пару кликов.

            3. Готовые блоки
            Создаёшь блок один раз, а потом используешь его на любых страницах. Если редактируешь блок, изменения автоматически применяются везде.

            4. Надёжное хранение данных
            Вся информация хранится в отдельной таблице, так что даже при ошибках данные не теряются. В MIGX всё хранится в JSON, и если что-то пойдёт не так (что бывает при большой вложенности), все данные могут быть утеряны.

            5. Мультиязычность
            Легко переводить контент через Deepl или ChatGPT.

            6. UTM-метки
            Есть поддержка тестирования разных меток, что полезно для аналитики.

            7. Версионирование
            Каждое изменение сохраняется, и можно откатиться к любой версии. А при удалении помещается в корзину, откуда тоже можно восстановить.

            8. Коллекции
            Можно создавать полностью настраиваемые таблицы с фильтрацией по любым данным.

            9. Синхронизация блоков
            Можно синхронизировать блоки между собой, даже если они не являются готовыми блоками.

            10. Мощное копирование
            Копировать можно по ID, по контексту или все блоки с определённого ресурса.

            11. События
            Доступно 17 событий для управления контентом. pageblocks.boshnik.com/docs/events.

            12. Роутинг
            Гибкая система роутинга, как в Laravel. Легко настраивать кастомные маршруты для страниц или API.

            13. Form Builder
            Можно создавать блоки, таблицы, табы и добавлять поля прямо через PHP-код.

            и останавливает то, что нет файловых элементов
            Это поддерживалось почти с самой первой версии.
            {'!pbBlocks'|snippet: [
                'fileElements' => 1
            ]}
            Все чанки находятся в core/elements/ (настраивается в pdoTools) и, соответственно, загружается файл из:
            core/elements/chunks/chunknameblock.tpl,
            где chunknameblock — это имя чанка блока.

            Но вскоре поддержка pdoTools будет удалена, так как в PageBlocks уже встроен Fenom, но еще не настроен.
          Наумов Алексей
          19 февраля 2025, 11:00
          0
          Привет! не до конца понял по версиям компонента! Вторая мажорная версия только платная, так? А первая (выложенная на modx.com) бесплатна? Но при этом я вижу что у нее относительно свежий релиз.
          Я сейчас начал работу с бесплатной, если пойму, что её возможностей мало — на 2-ю версию будет трудно уйти?

          И еще есть небольшой вопрос: 1) создал блок, указал имя чанка, 2) добавил этот блок к ресурсам, заполнил контентом, 3) переименовал чанк у блока, 4) у ресурса осталось старое имя чанка, всё сломалось, поменять его нельзя?
            Aleksandr Huz
            19 февраля 2025, 11:17
            +2
            Привет.

            Вторая мажорная версия только платная, так? А первая (выложенная на modx.com) бесплатна?
            Совершенно верно

            Но при этом я вижу что у нее относительно свежий релиз.
            Исправлять ошибки тоже нужно.

            Я сейчас начал работу с бесплатной, если пойму, что её возможностей мало — на 2-ю версию будет трудно уйти?
            Нет, просто обновляешь поверх нее — и все. Первая версия сильно ограничена в возможностях, но все равно полезна для легких сайтов, например, для лендинга.

            4) у ресурса осталось старое имя чанка, всё сломалось, поменять его нельзя?
            Имя чанка должно автоматически измениться для всех сопутствующих блоков, поэтому это ошибка в бесплатной версии. Исправлю сегодня.
              Наумов Алексей
              19 февраля 2025, 11:29
              0
              просто обновляешь поверх нее — и все
              В документации для 2й версии увидел что сниппеты другие (в первой просто один PageBlocks), вот и спросил)

              Исправлю сегодня.
              Спасибо за оперативность! Правда парни из modx.com наверное не сразу пакет опубликуют?)
                Aleksandr Huz
                19 февраля 2025, 11:43
                +1
                В документации для 2й версии увидел что сниппеты другие (в первой просто один PageBlocks), вот и спросил)
                Во второй версии нужно заменить на pbBlocks

                Спасибо за оперативность! Правда парни из modx.com наверное не сразу пакет опубликуют?)
                Уже отправил. Обычно это быстро.
                  Aleksandr Huz
                  19 февраля 2025, 12:04
                  0
                    Наумов Алексей
                    19 февраля 2025, 12:27
                    0
                    Что-то сломалось:

                    Ошибка установки
                    Error в /core/packages/pageblocks-1.0.5-pl/modCategory/5a3f1955c1726110b623e8d154a7e154.setupoptions.resolver:47:
                    Undefined class constant 'version'
                    Невозможно установить пакет с подписью: pageblocks-1.0.5-pl
                      Aleksandr Huz
                      19 февраля 2025, 12:38
                      0
                      Исправил. Проверьте мин. через 20
              Наумов Алексей
              19 февраля 2025, 15:03
              +3
              Спустя аж полдня работы хотел бы предложить группировку для блоков, ибо когда их становится более 10 штук — все в кучу смешивается:
                Aleksandr Huz
                19 февраля 2025, 15:50
                +2
                Да, хорошая идея, это тоже в планах. Сейчас в платной версии есть поиск по блокам, если их более 15, но группировка будет получше. Реализую.
                  Дима Касаткин
                  19 февраля 2025, 17:49
                  +1
                  На этом скриншоте ещё визуально хочется выровнять по левому краю надписи внутри кнопок.

                  Когда кнопок мало (одна, две) надписи в центре смотрятся гармонично, а когда много, ищешь глазами название, а они все начинаются на разной вертикальной оси — когнитивная нагрузка возрастает, поиск усложняется и замедляется.

                  @Aleksandr Huz рассмотри плиз возможность сделать выравнивание надписей!

                  P.S. Я такое уже встречал, когда занимался пакетом Formalicious — видимо в дизайне админки MODX никто не планировал много кнопок)) На скриншоте в той заметке тоже некрасиво, я позже исправлял…
                    Aleksandr Huz
                    19 февраля 2025, 18:51
                    +1
                    Вот так? Я подумаю, куда можно вывести стилизацию списка блоков.
                      Дима Касаткин
                      19 февраля 2025, 19:10
                      +1
                      Ну да, лучше, причем намного, если искать по первым буквам глазами. С группировкой будет ещё лучше, но это уже. Я в 90% случаев использую поиск через Crtl+F, но это когда знаешь название, а когда не знаешь — только вычитывать, и ровные колонки тут выигрывают у любых мясных кнопок))
                        Aleksandr Huz
                        19 февраля 2025, 19:16
                        +3
                        Я в 90% случаев использую поиск через Crtl+F
                        Есть встроенный поиск:
                  Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                  20