Перейти к содержимому
RootPoligon

Лаба: делаем новости управляемыми

Чтение и практика ~60 мин

Редактор добавил новость в админке, а на сайте по-прежнему три старые карточки. Оболочку мы уже перенесли, но содержимое осталось статическим. Ваша задача — связать страницу с инфоблоком так, чтобы дальше редактор обходился без изменения PHP.

Это практика в своей отдельной тестовой CMS, подготовленной в предыдущем уроке. Нужны файлы, админка, PHP CLI от пользователя сайта и Python 3.10+ для самопроверки. Облачный Битрикс здесь не выдаётся. Отметка прочтения главы сохраняет ваш учебный прогресс, но не проверяет сторонний сайт.

Подготовьте отдельные учебные данные

В пакете версии 1 есть tools/prepare.php. Храните tools/ вместе с assets/ вне корня сайта. Уточните пользователя PHP, путь к тестовой CMS и её ID. Пример для Ubuntu с www-data:

sudo -u www-data php /home/student/bitrix-news/tools/prepare.php \
  --document-root=/var/www/html --site=s1 --create

Замените пути и ID своими. Пользователь сайта должен читать учебные файлы; PHP CLI должен соответствовать окружению CMS. Подробности и порядок действий при ошибке — в README.md. Скрипт от root запускать нельзя: при подключении CMS могут выполняться её обработчики. Веб-версии установщика набора нет.

Он создаст новый тип rp_studio, инфоблоки новостей rp_course_news и услуг rp_course_services. Существующий тип не перезаписывает; повторный запуск отклонит. Файлы сайта и прежние инфоблоки не меняет. При частичном сбое остановитесь и восстановите свою учебную резервную копию, прежде чем повторять.

В админке откройте «Контент → Инфоблоки» и найдите «RootPoligon: Новости студии». Названия пунктов отличаются между версиями, ориентируйтесь на имя и код инфоблока. Проверьте семь записей: четыре видимые, один черновик, будущая встреча и прошедшая акция. В соседнем инфоблоке три услуги; их не нужно выводить или менять.

Что должно получиться

Вместо трёх статических карточек сначала появятся четыре: мастерская → офис → встреча → проект. Затем список будет зависеть от текущих записей CMS:

  • Только активные новости, у которых уже начался и ещё не закончился период показа. Пустая граница периода означает отсутствие ограничения с этой стороны.
  • Сортировка по началу публикации от новых к старым; при равенстве — по ID убыванию. Максимум шесть, без пагинации.
  • Заголовок, анонс, дата и плашка BADGE, если непустая. Если начало публикации не задано, показываем дату создания; сортировка остаётся по началу публикации, поэтому такие записи идут после записей с заполненной датой.
  • Прежняя сетка и мобильный вид; HTML в заголовке, анонсе и плашке выводится как текст. Кеширование компонента включено.

Можно добавлять собственные новости. Исходные тексты, свойства «Источник», картинки, привязки и услуги сохраняются. Меняйте свои файлы в local/ и rp-studio/; ядро и чужие страницы не затрагивайте.

Получаем данные компонентом

Удалите статические article из /rp-studio/news/index.php, оставив вводный блок и секцию новостей. Внутри секции вызовите компонент. Этот фрагмент — рабочий вызов; оформление карточек вы сделаете следующим шагом:

<?php
$newsBlock = \Bitrix\Main\Loader::includeModule('iblock')
    ? CIBlock::GetList([], ['TYPE' => 'rp_studio', 'CODE' => 'rp_course_news'])->Fetch()
    : false;
if ($newsBlock) {
    $APPLICATION->IncludeComponent('bitrix:news.list', 'cards', [
        'IBLOCK_TYPE' => 'rp_studio',
        'IBLOCK_ID' => (string)$newsBlock['ID'],
        'NEWS_COUNT' => '6',
        'SORT_BY1' => 'ACTIVE_FROM', 'SORT_ORDER1' => 'DESC',
        'SORT_BY2' => 'ID', 'SORT_ORDER2' => 'DESC',
        'CHECK_DATES' => 'Y',
        'FIELD_CODE' => ['ID', 'NAME', 'ACTIVE_FROM', 'DATE_CREATE', 'PREVIEW_TEXT'],
        'PROPERTY_CODE' => ['BADGE'],
        'DISPLAY_DATE' => 'Y', 'ACTIVE_DATE_FORMAT' => 'd.m.Y',
        'DISPLAY_TOP_PAGER' => 'N', 'DISPLAY_BOTTOM_PAGER' => 'N',
        'SET_TITLE' => 'N', 'SET_BROWSER_TITLE' => 'N',
        'SET_META_KEYWORDS' => 'N', 'SET_META_DESCRIPTION' => 'N',
        'CACHE_TYPE' => 'A', 'CACHE_TIME' => '3600',
        'CACHE_FILTER' => 'N', 'CACHE_GROUPS' => 'Y',
    ]);
} else {
    echo '<p>Сначала подготовьте учебный инфоблок.</p>';
}
?>

Мы находим инфоблок по собственному типу и коду: ID на разных установках отличаются. Не подставляйте ID из чужого скриншота. Параметры компонента определяют выборку, а cards — её оформление. Настройки SET_* сохраняют заданный страницей заголовок. В этом разделе предполагается один учебный инфоблок с указанным кодом.

Возвращаем свою карточку

Создайте файл:

/local/templates/rp_studio/components/bitrix/news.list/cards/template.php

Компонент передаёт записи в $arResult['ITEMS']. Возьмите одну карточку из исходной вёрстки и поместите её внутрь foreach. Общая .news-list нужна одна, вокруг цикла. Замените постоянные заголовок, анонс и дату значениями текущей записи.

Сохраните article.news-card, добавьте data-news-id с ID записи; заголовок сделайте h2.news-title, анонс — p.news-preview, дату — time с datetime="YYYY-MM-DD". Это полезная структура HTML и контракт нашего скрипта самопроверки.

Подсказка: цикл, поля и экранирование

Ниже минимальное ядро шаблона. Перенесите вокруг него card-art, card-body и card-meta исходной карточки, чтобы сохранить оформление. Плашку размещайте в card-meta. Цветовые классы макета — art-office, art-meeting, art-project.

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) { die(); }
?>
<div class="news-list">
<?php foreach ($arResult['ITEMS'] as $item):
    $timestamp = MakeTimeStamp($item['ACTIVE_FROM'] ?: $item['DATE_CREATE']);
    $name = $item['~NAME'] ?? $item['NAME'];
    $preview = $item['~PREVIEW_TEXT'] ?? $item['PREVIEW_TEXT'];
    $badge = $item['PROPERTIES']['BADGE']['~VALUE']
        ?? $item['PROPERTIES']['BADGE']['VALUE'] ?? '';
?>
    <article class="news-card" data-news-id="<?= (int)$item['ID'] ?>">
        <time datetime="<?= htmlspecialcharsbx(FormatDate('Y-m-d', $timestamp)) ?>"><?= htmlspecialcharsbx(FormatDate('d.m.Y', $timestamp)) ?></time>
        <h2 class="news-title"><?= htmlspecialcharsbx($name) ?></h2>
        <p class="news-preview"><?= htmlspecialcharsbx($preview) ?></p>
        <?php if (is_string($badge) && $badge !== ''): ?>
            <span class="news-badge"><?= htmlspecialcharsbx($badge) ?></span>
        <?php endif; ?>
    </article>
<?php endforeach; ?>
</div>

Поля с ~ берём как исходный текст и экранируем ровно на выводе. Иначе можно получить двойные HTML-сущности или выполнить разметку из данных. Для этого упражнения анонс — простой текст; поддержку полноценного HTML-редактора нужно проектировать отдельно. Свойство BADGE создано одиночным строковым. Для множественного или другого типа данных понадобится другой обработчик.

Проверяем настоящую управляемость

Откройте страницу как гость дважды, затем через CMS добавьте «Контрольную новость» с текущим началом публикации. Обновите гостевое окно: новость появилась без правки PHP. Измените её заголовок и анонс — появились новые значения. Снимите активность — исчезла. Кеш при этом включён; вручную чистить его после каждого изменения данных не нужно.

Выполните на своём компьютере, заменив URL адресом своей тестовой CMS:

python3 tools/check.py http://localhost/rp-studio/news/ --expect-count 4

Это первая проверка до добавления своих записей. После добавления и скрытия выполняйте соответственно:

python3 tools/check.py http://localhost/rp-studio/news/ --expect-title "Контрольная новость"
python3 tools/check.py http://localhost/rp-studio/news/ --absent-title "Контрольная новость"

Скрипт делает HTTP-запрос без пароля. Проверяет структуру, ID, даты, число карточек и указанное контрольное значение. Он не видит вашу базу, настройки кеша и файлы; это помощник для самопроверки, не доверенный проверяющий и не серверный зачёт.

Пройдите весь CHECKLIST.md из пакета. Особо проверьте девять видимых записей: на странице шесть в правильном порядке. Исходная новость может уйти за границу шести; это не ошибка. У своей записи попробуйте пустую дату начала, будущую дату и прошедшее окончание. Текст <b>Проверка</b> в её заголовке, анонсе и плашке должен оставаться текстом с угловыми скобками.

Если список не совпал
  • По-прежнему три прежние новости: убедитесь, что статические article удалены, а вызов стоит на той странице, которую открыли. Четвёртая новость «Мастерская» специально отсутствует в исходной вёрстке.
  • Стало семь карточек: рядом с компонентом могла остаться старая тройка.
  • Появились услуги: проверьте тип и код инфоблока в вызове.
  • Видна будущая акция: проверьте CHECK_DATES и часы/часовой пояс своей CMS и базы.
  • Данные обновляются только после сброса: начните с разбора кеша. Не закрепляйте выключенный кеш как решение; в своей среде проверьте управляемый кеш и способ изменения данных.
  • Вёрстка другая: сопоставьте имя cards, активный шаблон сайта rp_studio и путь локального шаблона компонента. Файл в соседнем шаблоне не влияет на эту страницу.

Работа закончена, когда редактор меняет список через CMS, гость видит правильные шесть или меньше карточек, оформление сохранено, исходные данные и ядро целы. Автор проверил такой вариант на настоящей CMS, включая отказы при неверной сортировке, отсутствии ограничения и отключённой проверке периода. Это самопроверка автора; ваша установка и работа проверяются вами по памятке.

Официальный справочник: параметры news.list, компоненты и их шаблоны. Уведомление об использовании документации.

Прочитали и разобрались? Отметьте урок — прогресс сохранится в этом браузере.