Как добавить кастомный блок главной страницы

Руководство для разработчика и для ИИ-агента. Относится к модулю ithive.homepage версии 12.4.0 и выше.
Описание соответствует коду lib/Blocks/*, lib/Rest/Controllers/Blocks.php и lib/Migration/MainpageThinIndexMigration.php.

Коротко: кастомный блок - это один обычный PHP-файл в /local/ithive.homepage/blocks/center_block/<code>.php (блок центра) или /local/ithive.homepage/blocks/right_block/<code>.php (блок сайдбара). Раскладка такая же, как у стандартных блоков модуля (/mainpage/center_block/<code>.php, /mainpage/right_block/<code>.php): код блока - имя файла без .php, зона - каталог. Манифеста, регистрации и REST-вызова для создания блока нет. Порядок, активность, название, права, мобильный контракт и пункт левого меню настраиваются после выгрузки файлов - на странице «Настроить Главную» и методом homepage.blocks.update.

1. Концепция

Главная страница (/mainpage/) состоит из блоков двух зон:

Зона Код зоны Файл блока Где выводится
Центр center center_block/<code>.php В основной колонке страницы; разметку и оформление блока формирует сам блок
Сайдбар right right_block/<code>.php В правой колонке через view target sidebar; вывод блока автоматически оборачивается в стандартную карточку виджета

Кастомный блок переживает обновления модуля, потому что:

  1. Файлы блока лежат в /local/ithive.homepage/blocks/center_block/ и /local/ithive.homepage/blocks/right_block/. Обновление модуля копирует файлы только в /bitrix/modules/ithive.homepage/, /bitrix/components/ithive/, /bitrix/js/ithive.homepage/ и т. п. и не трогает /local.
  2. /mainpage/index.php тонкий. Он подключает модуль и вызывает \Ithive\Homepage\Blocks\Renderer::renderPage(__DIR__, __FILE__). Вся логика вывода живёт в модуле и обновляется вместе с ним (раздел 8).
  3. Реестр блоков (BlocksRegistry) собирается на лету: встроенные блоки модуля + файлы из /local/ithive.homepage/blocks/center_block/ и right_block/. Никакой регистрации не нужно: положили файл - блок появился.
  4. Настройки хранятся отдельно от файлов в опции componentsettings (по сайтам): порядок (sort), активность (active), название (lang), а для локальных блоков также rights, mobile, menu, left_menu. Эффективное описание блока = то, что обнаружил реестр (код, зона, файл, источник) плюс настройки сайта.

Блок, которого ещё нет в componentsettings, не активен (active = false, на главной не выводится), с sort = 500 и названием, равным коду. Блок виден в «Настроить Главную» и в homepage.blocks.list / homepage.blocks.get; чтобы он появился на главной, его нужно включить (галочка «Акт.» в «Настроить Главную» или homepage.blocks.update с {"active": true}). Запись создаётся при первом изменении настроек.

Источник блока (source):

source Откуда Что можно менять через homepage.blocks.update
builtin Встроенный блок модуля active, sort, title (то же, что даёт «Настроить Главную»)
local /local/ithive.homepage/blocks/center_block/<code>.php или right_block/<code>.php active, sort, title, rights, mobile, menu, left_menu

Блоки не создаются и не удаляются через REST: создаёт файлы разработчик (или ИИ формирует файлы, а пользователь выгружает их), удаляет файл тоже разработчик.

2. Структура блока в /local

/local/ithive.homepage/blocks/
        ├── center_block/
        │   └── <code>.php     # блок центра: код = имя файла без .php
        └── right_block/
            └── <code>.php     # блок сайдбара
        

Каталога на блок нет: один блок - один файл. Если файлы с одним именем лежат и в center_block/, и в right_block/, это два блока одного кода (по одному в каждой зоне) с раздельными настройками (как у встроенных блоков). Свои ассеты и подшаблоны держите в /local вне этих каталогов, например /local/ithive.homepage/assets/<code>/, и подключайте абсолютными путями (подробнее в конце раздела 3).

Правила кода блока (имя файла без .php): только a-z, 0-9, _; длина до 64 символов; без двойного подчёркивания __ и без _ в начале и в конце кода (страница «Настроить Главную» передаёт поля как <код>__<параметр> и разбирает их по __, поэтому такие коды ломают разбор: файл с таким именем не загружается, на странице показывается ошибка ShowError); префиксы custom_ и new_custom_ зарезервированы (HTML-виджеты страницы настроек); коды всех встроенных блоков зарезервированы для обеих зон: код встроенного блока центра нельзя использовать и для блока сайдбара, и наоборот (встроенный блок остаётся, локальный пропускается с ошибкой; например, /local/ithive.homepage/blocks/right_block/news.php пропускается, хотя news - блок центра). Коды встроенных блоков центра: banner, news, news_smi, services, gallery, leader_sales, structure_events, stream; сайдбара: assessment360, birthday, bizproc, changes, events, gamification, goalsmanagement, goalsmanagement2, helpdesk, ipr, knowledgebase, message_blog, popular, pulse, socials, soon, task, urls, vote, vote_polls, workplaces. Выбирайте код с префиксом клиента (acme_memo), он не пересечётся с будущими блоками модуля.

Правила загрузки (BlocksRegistry):

  • Просматриваются только файлы *.php прямо в /local/ithive.homepage/blocks/center_block/ (блоки центра) и /local/ithive.homepage/blocks/right_block/ (блоки сайдбара); код блока - имя файла без .php. Нет каталога зоны - зона пуста, ошибки нет.
  • Файл с недопустимым кодом (символы вне [a-z0-9_], длина больше 64, __ в коде, _ в начале или конце, префиксы custom_ / new_custom_) пропускается, причина показывается на странице ошибкой ShowError.
  • Файлы с другим расширением (x.txt, x.bak) и подкаталоги внутри center_block/ и right_block/ блоками не считаются и молча игнорируются.
  • Символьные ссылки и junction, ведущие за пределы каталога блоков (каталог зоны - ссылка, либо файл блока <code>.php - ссылка), отвергаются с ошибкой.
  • Конфликт кода с кодом встроенного блока любой зоны: локальный блок пропускается с ошибкой на странице.
  • Файл блока, который не является файлом или недоступен для чтения: блок пропускается с ошибкой на странице («Template file is not readable»); если файл исчезает или становится нечитаемым уже после загрузки, на месте блока выводится «Ошибка вывода блока ...: Файл шаблона блока не найден или недоступен для чтения», остальные блоки работают. Фатальные ошибки PHP внутри самого шаблона (например, повторное объявление функции) перехватить нельзя, они прерывают страницу.

Файл подключается в изолированной области: доступны $APPLICATION, $USER и $block (Block - эффективное описание текущего блока: getCode(), getZone(), getTitle(), getSort()). Вывод файла идёт в буфер; при исключении буфер сбрасывается и блок не выводится совсем (без частичной разметки), а на его месте показывается ошибка ShowError с кодом блока и причиной. Остальные блоки продолжают работать.

Шаблон подключается уже внутри страницы: не подключайте в нём header.php/footer.php и не печатайте <html>/<body>. Начинайте файл с защиты пролога (как стандартные блоки):

<?php
        if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
            die();
        }
        

После защиты можно писать обычную разметку и вставки <?php ... ?>, <?= ... ?>, вызывать $APPLICATION->IncludeComponent(...) (например bitrix:news.list с нужными параметрами - так устроены стандартные блоки /mainpage/right_block/urls.php, news.php и др.), подключать свои подшаблоны абсолютным путём вне каталогов зон, например include $_SERVER['DOCUMENT_ROOT'] . '/local/ithive.homepage/assets/<code>/partial.php' (любой *.php, лежащий прямо в center_block/ или right_block/, считается блоком, поэтому подшаблоны туда не кладут). Данные пользователя выводите с экранированием (htmlspecialcharsbx()).

3. Блок центра: center_block/.php

Образец (/local/ithive.homepage/blocks/center_block/acme_memo.php):

<?php
        if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
            die();
        }
        /** @global CUser $USER */
        ?>
        <div class="acme-memo" style="padding: 20px; background: #fff; border-radius: 12px; margin-bottom: 20px;">
            <h3>Добро пожаловать, <?= htmlspecialcharsbx($USER->GetFirstName()) ?>!</h3>
            <ol>
                <li>Заполните свой профиль и добавьте фотографию.</li>
                <li>Познакомьтесь со структурой компании.</li>
            </ol>
        </div>
        

Правила центра:

  • Блок выводится в основной колонке как есть, без обёртки: фон, отступы, скругления и заголовок блок задаёт сам (как в образце). Поле «Свое название» в «Настроить Главную» у блоков центра недоступно для редактирования. Для вида, единого со встроенными блоками, смотрите стандартные файлы /mainpage/center_block/<code>.php и используйте те же компоненты и шаблоны.
  • Блоки выводятся по возрастанию sort. При совпадении sort у двух встроенных блоков второй ставится в конец списка (поведение прежнего index.php). Клиентский блок с тем же sort, что у другого блока, встаёт сразу после него, как в «Настроить Главную»; новый блок получает sort = 500, как и встроенный gallery, поэтому для точного места задайте sort явно.
  • Выводятся только блоки с active = Y (локальные блоки, ещё не сохранённые в настройках, считаются неактивными: сначала включите блок).
  • Пользовательские HTML-виджеты (custom_items) выводятся только в сайдбаре; custom_items центра (наследие опции) не выводятся - как и в прежнем index.php.

Ассеты и подшаблоны блока (CSS, JS, изображения, подключаемые *.php) модуль не ищет и не проверяет: каталога на блок нет. Положите их в /local где удобно, например в /local/ithive.homepage/assets/<code>/, и подключайте абсолютными путями: \Bitrix\Main\Page\Asset::getInstance()->addCss('/local/ithive.homepage/assets/acme_memo/style.css'), include $_SERVER['DOCUMENT_ROOT'] . '/local/ithive.homepage/assets/acme_memo/partial.php'. Не кладите их внутрь center_block/ и right_block/: каждый *.php прямо в этих каталогах считается блоком.

4. Блок сайдбара: right_block/.php

Образец (/local/ithive.homepage/blocks/right_block/acme_links.php) - только содержимое карточки:

<?php
        if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
            die();
        }
        ?>
        <ul>
            <li><a href="/company/">О компании</a></li>
            <li><a href="/docs/">Документы</a></li>
            <li><a href="/company/structure.php">Структура компании</a></li>
        </ul>
        

Правила сайдбара:

  • Сайдбар выводится, только если в настройках главной включена правая колонка (right_block.active = Y), а страница выводится шаблоном bitrix24 (иначе Renderer ничего не выводит).
  • Renderer сам кладёт вывод блока в view target sidebar: $APPLICATION->AddViewContent('sidebar', $html, $sort). Блок не должен сам вызывать AddViewContent и выводить обёртку карточки - достаточно вывести содержимое.
  • Вывод оборачивается в разметку, идентичную ithive:widget.wrapper:
<div class="widget-mainpage" id="homepage-block-<code>-<N>">
          <div class="widget-mainpage-top"><div class="widget-mainpage-top-title">Название блока</div></div>
          <div class="widget-mainpage-content"><div class="widget-mainpage-content-container">
             ...вывод блока...
          </div></div>
        </div>
        
  • Заголовок карточки добавляет модуль: сохранённое администратором название (title), иначе код блока. Свой заголовок в файле блока сайдбара не выводите, иначе он задвоится. Чтобы карточка называлась по-человечески, после выгрузки задайте title (раздел 5).
  • Оформление: рамку, отступы и заголовок карточки дают классы widget-mainpage* (стили sidebar.css шаблона bitrix24, страница подключает его сама); содержимое оформляйте своей разметкой (списки, ссылки, <p>), специальных классов контента модуль не предоставляет. Для вида, единого со встроенными виджетами, ориентируйтесь на стандартные файлы /mainpage/right_block/<code>.php и их шаблоны компонентов.
  • Сайдбар выводится по возрастанию sort (при совпадении sort действует то же правило, что в центре); в нём же выводятся пользовательские HTML-виджеты.

5. Настройки блока после выгрузки

Блок, выгруженный в /local, сразу появляется на странице «Настроить Главную» (вкладки центра и сайдбара) и в homepage.blocks.list, но выключенным: на главной он не виден, пока его не включат. Включается и настраивается там же (галочка «Акт.») или методом homepage.blocks.update (нужны права администратора). Все значения хранятся в настройках сайта (componentsettings), а не в файлах; страница «Настроить Главную» не редактирует rights, mobile, но не теряет их при сохранении; menu и left_menu блока центра редактируются там же (раздел 5.2).

Поле update Что задаёт Границы
active Включён ли блок на сайте true / false
sort Порядок вывода (меньше - выше) целое 0..1000000
title Название блока (заголовок карточки сайдбара) 1-255 символов, теги вырезаются
rights Права (раздел 5.1) {admin: bool, groups: int[]}
mobile Контракт мобильного приложения (раздел 5.3) {type, url, dataMethod}
menu Пункт левого меню (раздел 5.2), только зона center {url, title}
left_menu Показывать пункт menu в левом меню true / false, нужен menu

Пример (название, порядок, доступ только администраторам):

curl -X POST "https://{portal}/rest/{user_id}/{webhook_code}/homepage.blocks.update.json" \
          -H "Content-Type: application/json" \
          -d '{"code":"acme_links","zone":"right","fields":{"title":"Полезные ссылки","sort":300,"active":true,"rights":{"admin":true,"groups":[]}}}'
        

rights, mobile, menu, left_menu у встроенных блоков отклоняются (VALIDATION_ERROR); menu/left_menu у блока сайдбара - тоже. Любая ошибка валидации отменяет всё изменение целиком. Метод меняет один блок за вызов; остальные блоки и состояние зон не затрагиваются, недостающие в сохранённых настройках встроенные блоки и флаги зон перед записью берутся из значений по умолчанию.

5.1. Права

Поле rights:

Поле Тип Описание
admin bool Блок виден администраторам портала
groups int[] ID групп пользователей, которым виден блок

Правила (Block::canView() по эффективным rights из настроек):

  • Пустые права (admin = false, groups = []) - блок виден всем, кто видит главную.
  • Иначе пользователь должен быть администратором (при admin = true) или состоять хотя бы в одной группе из groups.
  • Проверка выполняется при выводе блока на странице, в пункте меню раздела /mainpage/ (пункт показывается, только если блок доступен пользователю; в левом меню портала блок с rights пункта не получает, раздел 5.2), в homepage.blocks.list (недоступные блоки не возвращаются), в homepage.blocks.get и homepage.blocks.data (ACCESS_DENIED), а также в homepage.widgets.list / homepage.widgets.get для локальных блоков (скрытый блок не возвращается, get отвечает NOT_FOUND).
  • homepage.blocks.update (только администратор) возвращает блок даже если после сохранения rights вызывающий администратор сам потерял к нему доступ: ответ строится по сохранённым настройкам без проверки прав. Последующие get/list/data для него блок уже скрывают.
  • Права скрывают сам блок, но не данные: код блока (шаблон, компонент) отвечает за проверку доступа к тому, что он показывает.
  • Снять ограничение: "rights": [].

5.2. Пункт левого меню

Блок центра может добавить пункт в левое меню портала (и в меню раздела /mainpage/, /mainpage/.left.menu.php). Для этого задайте menu и включите left_menu:

{"menu": {"url": "/company/news/", "title": "Новости компании"}, "left_menu": true}
        
  • url: относительный путь, начинающийся с / (но не //), либо https://.... Другие схемы (javascript:, http:, data:) отклоняются.
  • title: по умолчанию равен названию блока.
  • Ограничение по rights. Левое меню портала задаётся на уровне сайта и не умеет скрывать пункт от отдельных пользователей. Поэтому блок с ограничением rights (администраторы и/или группы) не добавляет пункт в левое меню портала вообще; в меню раздела /mainpage/ пункт показывается только пользователям с доступом к блоку (проверка та же, что при выводе блока). Нужен пункт в меню портала - не ограничивайте блок по rights или ограничьте содержимое самим блоком.
  • Когда пункт появляется и исчезает. Модуль сам синхронизирует пункты блоков из /local с левым меню портала при сохранении настроек: в «Настроить Главную», в настройках модуля и при вызове homepage.blocks.update (любое поле) для блока центра. Пункт появляется, когда блок активен, включён left_menu, задана ссылка menu.url и нет rights. Пункт исчезает при снятии флага, выключении блока, удалении ссылки (menu), добавлении rights и удалении записи блока из настроек. Удалили файл блока из /local - пункт уйдёт при следующем сохранении настроек блоков или вызове homepage.menu.refresh. Пункты встроенных блоков и пункты, добавленные администратором портала вручную, синхронизация не меняет; повторное сохранение пункт не дублирует. Текст пункта - название блока (title, оно же lang), иначе menu.title; ссылка - menu.url. Изменения видны после перезагрузки страницы.
  • Пункт появляется только у активных блоков центра и только если включён left_menu (его же отмечает администратор флагом «Вывести в левое меню» в «Настроить Главную»; флаг и поле ссылки рядом с ним есть у каждого блока центра из /local, ссылка вводится прямо там и хранится в тех же настройках, что и menu.url). Флаг хранится в componentsettings (left_menu), по умолчанию выключен. Если флаг отмечен, а ссылка пустая или недопустима (правила menu.url: путь на портале или https), «Настроить Главную» не сохраняет изменения и показывает ошибку. Если флаг снят, введённая допустимая ссылка сохраняется, пункт не показывается; очистка поля удаляет menu.
  • Название пункта: сохранённое название блока, иначе menu.title.
  • Удалить пункт: "menu": [] (флаг left_menu сбрасывается).

5.3. Мобильное приложение

Мобильное приложение (МП) получает список блоков через homepage.blocks.list, а данные блока - через homepage.blocks.data. Клиент МП находится вне этого репозитория; контракт задаёт поле mobile:

mobile.type Дополнительные поля Что получает приложение
none (по умолчанию) - Блок не отдаётся в МП; homepage.blocks.data вернёт NOT_SUPPORTED
webview-url url (/... или https://...) url и absoluteUrl - страница открывается во встроенном браузере
native-json dataMethod (необязательно) Данные блока в JSON для нативной отрисовки либо имя REST-метода, который приложение вызывает само

mobile.dataMethod для native-json - только имя REST-метода формата <scope>.<entity>.<action> (например acme.news.list). Сервер этот метод не вызывает и PHP-класс по строке не разрешает: имя возвращается приложению в поле dataMethod ответа homepage.blocks.data. Формат Class::method не поддерживается и отклоняется (VALIDATION_ERROR).

Данные блока на стороне сервера поставляет событие ithive.homepage:OnBlockMobileData с параметрами code, zone, userId, siteId. Подписчик отвечает EventResult с параметром data (массив); используется первый ответ с данными, он попадает в data ответа homepage.blocks.data. Если событие данных не дало, а задан dataMethod - возвращается имя метода (data = null); иначе NOT_SUPPORTED.

\Bitrix\Main\EventManager::getInstance()->addEventHandler(
            'ithive.homepage',
            'OnBlockMobileData',
            static function (\Bitrix\Main\Event $event) {
                if ($event->getParameter('code') !== 'acme_memo') {
                    return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::UNDEFINED);
                }
        
                return new \Bitrix\Main\EventResult(
                    \Bitrix\Main\EventResult::SUCCESS,
                    ['data' => ['items' => [['title' => 'Пункт 1']], 'userId' => (int)$event->getParameter('userId')]]
                );
            }
        );
        

homepage.blocks.data требует, чтобы блок был активен и доступен пользователю по rights.

6. Что выгрузить и что делать дальше (порядок для пользователя)

  1. Выгрузите файл блока на портал (FTP/SFTP/scp/файловый менеджер хостинга): /local/ithive.homepage/blocks/center_block/<code>.php (центр) и/или /local/ithive.homepage/blocks/right_block/<code>.php (сайдбар), а свои ассеты и подшаблоны - в любое место в /local, например /local/ithive.homepage/assets/<code>/. Каталоги /local/ithive.homepage/blocks/center_block/ и right_block/ создаёт установка и обновление модуля, если их нет; если при обновлении не хватило прав на запись, создайте их сами.
  2. Сбросьте opcache (если включён и не проверяет время изменения файлов): иначе портал может отдавать старую версию файла.
  3. Откройте страницу «Настроить Главную»: блок уже в списке, но не активен, sort = 500, название = код. На /mainpage/ он пока не выводится. Если над блоками показана красная ошибка - прочитайте причину (раздел 9).
  4. Включите блок (галочка «Акт.» в «Настроить Главную» или homepage.blocks.update с {"active": true}), при необходимости отсортируйте и переименуйте (sort, title). Блок сайдбара виден на главной, если включена правая колонка.
  5. При необходимости выставьте права, мобильный контракт и пункт левого меню через homepage.blocks.update (раздел 5).
  6. Проверьте homepage.blocks.get (код и зона) и главную под обычным сотрудником.

Изменить блок позже - заменить файл в /local (и сбросить opcache). Удалить блок - удалить файл (запись в настройках остаётся и подхватится, если блок с тем же кодом выгрузят снова).

7. Примеры

Два готовых примера лежат в репозитории модуля: docs/examples/blocks/center_block/example_onboarding_memo.php (центр) и docs/examples/blocks/right_block/example_useful_links.php (сайдбар). Копируйте их в /local/ithive.homepage/blocks/center_block/ и /local/ithive.homepage/blocks/right_block/ соответственно.

8. Обновления модуля и файлы /mainpage/index.php и /mainpage/.left.menu.php

Файлы блоков в /local и их настройки обновление не затрагивает. Файлы вне /local, от которых зависит механизм, - /mainpage/index.php и /mainpage/.left.menu.php портала: они должны быть тонкими (вызывать код модуля).

Тонкий index.php:

<?php
        require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/header.php");
        
        // The homepage logic lives in the module (Ithive\Homepage\Blocks\Renderer) and is updated together with it.
        if (CModule::IncludeModule('ithive.homepage') && class_exists(\Ithive\Homepage\Blocks\Renderer::class)) {
            if (!\Ithive\Homepage\Blocks\Renderer::renderPage(__DIR__, __FILE__)) {
                return;
            }
        }
        
        require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/footer.php"); ?>
        

Автоматическая замена при обновлении. Обновление 12.4.0 (updater.php) для корня портала и каждого активного сайта проверяет /mainpage/index.php и /mainpage/.left.menu.php:

  1. Если в файле уже есть вызов модуля (Renderer::renderPage( для index.php, LeftMenu::build( для .left.menu.php) - файл пропускается.
  2. Иначе рядом создаётся резервная копия <файл>.bak-<ГГГГММДД> и файл заменяется тонким вариантом из модуля (/bitrix/modules/ithive.homepage/install/public/mainpage/). Заменяется любой файл, в том числе изменённый вручную.
  3. Если резервную копию создать не удалось (нет прав на запись в каталог), файл не меняется.

Если клиент менял index.php или .left.menu.php вручную, свои правки после обновления нужно вернуть из резервной копии .bak-<дата> вручную: перенесите их в блоки по этому руководству (для меню - добавьте свои пункты после вызова LeftMenu::build). Отдельных настроек, вкладки в настройках модуля или предупреждений на странице для этого нет.

Левое меню. Тонкий /mainpage/.left.menu.php содержит один вызов:

<?php
        if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
        $aMenuLinks = [];
        if (\CModule::IncludeModule("ithive.homepage")) {
            $aMenuLinks = \Ithive\Homepage\Blocks\LeftMenu::build(SITE_ID, SITE_DIR);
        }
        

Пункты меню раздела /mainpage/ (встроенных блоков и блоков клиента с menu, с учётом rights) строит класс модуля \Ithive\Homepage\Blocks\LeftMenu, поэтому правки логики меню приходят с обновлением модуля. Пункты в левом меню портала (меню интранета) этот файл не определяет: для блоков клиента их записывает модуль при сохранении настроек (раздел 5.2).

Если блок не появился после обновления. Проверьте, что /mainpage/index.php вызывает Renderer::renderPage( (например, обновление не смогло записать файл из-за прав). Если нет, замените содержимое файла вручную на тонкий вариант выше, образец - /bitrix/modules/ithive.homepage/install/public/mainpage/index.php; для меню - вызов $aMenuLinks = \Ithive\Homepage\Blocks\LeftMenu::build(SITE_ID, SITE_DIR); после подключения модуля. Встроенные блоки по-прежнему выводятся файлами /mainpage/center_block/<code>.php и /mainpage/right_block/<code>.php.

9. Безопасность и диагностика

  • REST ничего не пишет и не исполняет. Блоки не создаются и не удаляются через REST, файлы не записываются. homepage.blocks.update меняет только опцию componentsettings; значения (title, sort, rights, mobile, menu) проверяются и не исполняются как код.
  • Серверных вызовов по строке из данных нет. mobile.dataMethod - только имя REST-метода, его вызывает приложение, не сервер. Данные для МП поставляет событие ithive.homepage:OnBlockMobileData.
  • Единственный динамический include локальных блоков - файл блока <code>.php, который разработчик положил в /local/ithive.homepage/blocks/center_block/ или right_block/ (файловый доступ к серверу = доверенный). Путь файла проверяется realpath строго внутри каталога зоны (при загрузке и при каждом выводе), файл-ссылка отвергается; каталог зоны не может быть символьной ссылкой за пределы /local/ithive.homepage/blocks/.
  • В menu.url и mobile.url разрешены только относительные пути и https://.
  • Данные пользователя выводите с экранированием (htmlspecialcharsbx()); не подключайте файлы по путям из запроса.
  • Права блока (rights) ограничивают видимость блока, но не защищают данные, которые блок получает сам.
  • Ошибки показываются на странице, серверный лог модуль не пишет. Блок, который не удалось загрузить (недопустимый код файла, в том числе с __ или с _ в начале/конце; конфликт с кодом встроенного блока любой зоны; нечитаемый файл, файл или каталог зоны - ссылка), пропускается, а над блоками центра показывается ShowError вида «Блок «» (зона: ..., источник: local) не загружен: <причина>» (одна ошибка на пару «зона + код» за запрос; видна всем пользователям). Ошибка при выводе блока (исключение в шаблоне, файл не найден) показывается на месте блока: «Ошибка вывода блока «» (зона: ): <причина>».

Блок не виден - проверьте по порядку

  1. Тонкий ли /mainpage/index.php. В файле должен быть вызов Blocks\Renderer::renderPage. Если нет - раздел 8.
  2. Версия модуля 12.4.0 или выше, класс \Ithive\Homepage\Blocks\Renderer существует.
  3. Путь и имя. Файл /local/ithive.homepage/blocks/center_block/<code>.php (или right_block/<code>.php); код блока - имя файла без .php ([a-z0-9_], без __ и без _ в начале/конце, не custom_*/new_custom_*, не код встроенного блока ни центра, ни сайдбара); расширение именно .php, файл лежит прямо в каталоге нужной зоны (не в подкаталоге).
  4. Причина пропуска. Откройте главную: ошибка ShowError над блоками центра назовёт код, зону и причину (недопустимый код, конфликт со встроенным блоком любой зоны, нечитаемый файл, файл или каталог зоны - ссылка). Вызов homepage.blocks.get вернёт NOT_FOUND, если реестр блок не распознал.
  5. Блок включён. Новый блок из /local по умолчанию выключен: включите его в «Настроить Главную» или homepage.blocks.update ({"active": true}); в REST смотрите поле active у homepage.blocks.get.
  6. Сайдбар. Для зоны right должна быть включена правая колонка; страница должна выводиться шаблоном bitrix24.
  7. Права. Если заданы rights, вы должны быть администратором или состоять в группе из groups.
  8. Ошибка при выводе. На месте блока выведена ошибка «Ошибка вывода блока ...»: исключение в шаблоне, неверный компонент или параметры. Проверьте синтаксис (php -l <code>.php).
  9. Кэш PHP. Реестр не кэшируется между запросами, но opcache может отдавать старую версию PHP-файла: сбросьте opcache.
  10. Не появился пункт меню. В левом меню портала: нужны menu, зона center, активный блок, left_menu = true, отсутствие rights и сохранение настроек после включения (в «Настроить Главную» или homepage.blocks.update); для настроек, сохранённых до этой версии, выполните homepage.menu.refresh. В меню раздела /mainpage/ те же условия, но rights допустимы (по доступу) и нужен тонкий /mainpage/.left.menu.php (вызов Blocks\LeftMenu::build; обновление заменяет файл с резервной копией, см. раздел 8).

Проверка без браузера: homepage.blocks.list с filter={"source":"local"} показывает все распознанные локальные блоки; homepage.blocks.get с кодом и зоной - один блок. Сам вывод блока на странице без браузера проверить нельзя.

Известное поведение: если блок удалить из /local вручную, его запись в componentsettings остаётся (в homepage.widgets.list она приходит с source = settings). Запись безвредна и подхватывается, если блок с тем же кодом выгрузят снова.

10. Инструкция для ИИ-агента

ИИ сам формирует файлы блока и сообщает пользователю, куда их выгрузить и что делать дальше. REST для создания блока не используется: его нет.

10.1. Что выяснить до начала

  1. Что должен показывать блок (контент, данные, ссылки) и в какой зоне: центр (center_block/<code>.php), сайдбар (right_block/<code>.php) или обе.
  2. Откуда берутся данные: статичная разметка, штатный компонент (bitrix:news.list и т. п., нужен IBLOCK_ID), данные пользователя.
  3. Нужны ли ограничение по правам, пункт левого меню, контракт для мобильного приложения.
  4. Код блока: коротко, a-z0-9_, с префиксом клиента, без __ и без _ в начале/конце, не код встроенного блока (ни центра, ни сайдбара) и не custom_*/new_custom_*. Если пользователь не назвал - предложите и подтвердите.

10.2. Шаги

  1. Сформируйте файл(ы) блока по образцам разделов 3 и 4 и примерам docs/examples/blocks/: защита B_PROLOG_INCLUDED, экранирование вывода, для сайдбара только содержимое без карточки и заголовка, без header.php/footer.php. Свои ассеты/подшаблоны, если нужны, сформируйте отдельно (например, /local/ithive.homepage/assets/<code>/, не внутри каталогов зон) и подключайте абсолютными путями.
  2. Проверьте код блока по правилам раздела 2 и синтаксис файлов (php -l, если есть доступ к PHP).
  3. Сообщите пользователю пути выгрузки (/local/ithive.homepage/blocks/center_block/<code>.php и/или /local/ithive.homepage/blocks/right_block/<code>.php) и список файлов для выгрузки, включая ассеты вне каталогов зон.
  4. Опишите следующие шаги (раздел 6): выгрузить файлы -> сбросить opcache при необходимости -> блок появится в «Настроить Главную» и в homepage.blocks.list выключенным -> включить (галочка «Акт.» или homepage.blocks.update с {"active": true}), отсортировать, переименовать, выставить права.
  5. Если нужны название, порядок, права, меню или контракт МП - подготовьте готовый вызов homepage.blocks.update с code, zone и fields (раздел 5) и отдайте пользователю (или выполните, если у вас есть вебхук администратора, после того как пользователь подтвердил, что файлы выгружены: до выгрузки update вернёт NOT_FOUND).
  6. Проверка результата: homepage.blocks.get с code и zone (источник local, нужные title, sort, active, rights), затем главная.

Шаблон ответа пользователю:

Блок «<название>» готов. Файлы:
        - center_block/<code>.php (или right_block/<code>.php)
        - <ассеты, если есть: /local/ithive.homepage/assets/<code>/...>
        
        Куда выгрузить: /local/ithive.homepage/blocks/center_block/<code>.php (или .../right_block/<code>.php)
        Дальше:
        1. Выгрузите файлы на портал (при необходимости сбросьте opcache).
        2. Блок появится в «Настроить Главную» и в homepage.blocks.list выключенным - включите его (галочка «Акт.» или `homepage.blocks.update` с `{"active": true}`) и задайте порядок.
        3. Название/права/меню - homepage.blocks.update (готовый вызов ниже).
        

10.3. Чего делать нельзя

  • Не создавать блок через REST (методов homepage.blocks.add и homepage.blocks.delete нет) и не писать манифест block.php: он не используется.
  • Не выводить в файле блока сайдбара собственную карточку widget-mainpage и заголовок (модуль добавляет их сам) и не вызывать AddViewContent из блока.
  • Не использовать в mobile.dataMethod форму Class::method: только REST-имя scope.entity.action.
  • Не называть блок кодом встроенного блока (любой зоны), кодом с префиксом custom_/new_custom_, кодом с __ или с _ в начале/конце.
  • Не подключать файлы по путям из запроса, не выводить данные без htmlspecialcharsbx().
  • Не писать в серверные логи: ошибки блока показываются на странице.

10.4. Критерии готовности

  • Файлы блока созданы, начинаются с защиты B_PROLOG_INCLUDED, синтаксически верны.
  • Пользователю названы пути выгрузки (/local/ithive.homepage/blocks/center_block/<code>.php, .../right_block/<code>.php) и дальнейшие шаги.
  • Для нужной настройки (название, порядок, права, меню, МП) дан корректный вызов homepage.blocks.update.
  • После выгрузки блок виден в homepage.blocks.get (source = local) и на главной.
Предыдущая