Блог разработчика 1С-Битрикс

Единственный активный элемент в инфоблоке: автодеактивация баннера в 1С-Битрикс

Иногда на сайте нужен небольшой, но «громкий» поп-ап, который появляется на каждой странице и сообщает о важной акции, доставке или cookie-политике.

Главное условие: одновременно должен показываться только один баннер. Значит, в инфоблоке, из которого мы берём данные, всегда должен быть ровно один активный элемент.

Только один активный элемент в инфоблоке

Ниже - готовый код, который автоматически следит за этим правилом: если редактор включает новый элемент, скрипт сам отключает прежний. Администратору не нужно помнить про ручную деактивацию, а во фронтенде вы всегда получаете ровно один элемент для поп-апа.

<?php
/**
 * /local/php_interface/init.php
 * Гарантирует, что в инфоблоке SINGLE_ACTIVE_IBLOCK_ID активным остаётся ровно один элемент.
 * При активации нового баннера предыдущий автоматически деактивируется.
 */
use Bitrix\Main\EventManager;
use Bitrix\Iblock\ElementTable;
const SINGLE_ACTIVE_IBLOCK_ID = 1;   // ← подставьте ID своего инфоблока
$em = EventManager::getInstance();
$em->addEventHandler('iblock', 'OnAfterIBlockElementAdd',    'keepSingleActive');
$em->addEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'keepSingleActive');

/**
 * Оставляет один активный элемент.
 *
 * @param array $arFields поля сохранённого элемента
 */
function keepSingleActive(array $arFields): void
{
    // интересуемся только нужным инфоблоком
    if ((int)$arFields['IBLOCK_ID'] !== SINGLE_ACTIVE_IBLOCK_ID) {
        return;
    }
    $currentId = (int)$arFields['ID'];
    // получаем актуальное состояние элемента
    $current = ElementTable::getById($currentId)->fetch();
    if (!$current || $current['ACTIVE'] !== 'Y') {      // сохраняют неактивный — выходим
        return;
    }
    // защита от рекурсии
    static $inProcess = false;
    if ($inProcess) {
        return;
    }
    $inProcess = true;
    // ищем все остальные активные элементы
    $cursor = ElementTable::getList([
        'select' => ['ID'],
        'filter' => [
            '=IBLOCK_ID' => SINGLE_ACTIVE_IBLOCK_ID,
            '=ACTIVE'    => 'Y',
            '!ID'        => $currentId,
        ],
    ]);
    $el = new CIBlockElement;
    while ($row = $cursor->fetch()) {
        // переводим найденные элементы в неактивные
        $el->Update($row['ID'], ['ACTIVE' => 'N']);
    }
    $inProcess = false;
}

Как работает скрипт

Шаг Что происходит
1. Подключение После загрузки ядра Bitrix код регистрирует события OnAfterIBlockElementAdd и OnAfterIBlockElementUpdate.
2. Проверка инфоблока Обработчик реагирует только на элементы инфоблока SINGLE_ACTIVE_IBLOCK_ID.
3. Проверка активности Если сохраняемый элемент неактивный, скрипт ничего не делает.
4. Защита от рекурсии Статическая переменная $inProcess блокирует повторный запуск обработчика, когда мы сами меняем ACTIVE у старого баннера.
5. Поиск активных ORM-запрос выбирает все другие активные элементы того же инфоблока.
6. Авто-деактивация Каждый найденный элемент переводится в ACTIVE = N методом $el->Update().
7. Финиш Новый баннер остаётся единственным активным, а сохранение завершается без блокировок и ошибок.

Вывод поп-апа во фронтенде

<?php
$arPopup = CIBlockElement::GetList(
    [],
    ['IBLOCK_ID' => SINGLE_ACTIVE_IBLOCK_ID, 'ACTIVE' => 'Y'],
    false,
    ['nTopCount' => 1],
    ['ID', 'NAME', 'PREVIEW_TEXT', 'PREVIEW_PICTURE', 'PROPERTY_LINK']
)->Fetch();
if ($arPopup) {
    ?>
    <div id="promo-popup" class="popup">
        <h3><?= htmlspecialcharsbx($arPopup['NAME']) ?></h3>
        <p><?= $arPopup['PREVIEW_TEXT'] ?></p>
        <? if ($arPopup['PROPERTY_LINK_VALUE']): ?>
            <a href="<?= $arPopup['PROPERTY_LINK_VALUE'] ?>" class="btn">Подробнее</a>
        <? endif; ?>
    </div>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            document.getElementById('promo-popup').style.display = 'block';
        });
    </script>
    <?php
}

Совет: оберните выборку в CPHPCache или подключите готовый компонент с умным кешем, чтобы не выполнять запрос на каждой странице.

Полезные расширения

Идея Как реализовать
Ограничение по времени Добавьте в публичный фильтр ACTIVE_DATE => 'Y' и ставьте элементам ACTIVE_FROM/ACTIVE_TO.
Мультиязычность Храните тексты в множественных свойствах (PREVIEW_TEXT_EN, ) или заведите по инфоблоку на язык.
Несколько типов поп-апов Добавьте свойство «Тип» (cookies / promo / alert) и фильтруйте в обработчике и фронтенде по нему.
Включение по расписанию Используйте агенты или CRON-скрипт для автоматической активации нужного элемента ― обработчик сам выключит старый.

Итог

  • Администраторы больше не думают, какой баннер выключить — скрипт делает это автоматом.
  • Фронтенд всегда получает ровно один активный элемент, поп-ап не дублируется.
  • Производительность не падает: после сохранения выполняется лишь один лёгкий ORM-запрос + несколько апдейтов при необходимости.

Подключите файл в /local/php_interface/init.php — и ваш поп-ап всегда будет показывать актуальную информацию без риска дублирования.


Теги:  баннеры, автодеактивация, PHP, инфоблоки, поп-ап


Стоимость услуг по разработке и сопровождению сайтов на 1C-Битрикс

Интернет-магазин на готовом решении

от 7 дней

от 40 000 рублей
запуск сайта в максимально короткие сроки

* указана минимальная стоимость. Стоимость выбранной лицензии «1С-Битрикс» оплачивается отдельно.

Перенос сайтов на «1С-Битрикс»

сайты на платформе «1С-Битрикс» — это удобство, надежность и высокая посещаемость

от 12 000 рублей
Перенос сайтов с любых CMS и статичных страниц на платформу «1С-Битрикс», с учетом дизайна, верстки и урл-адресов. С сохранением всей информации и структуры сайта.

* зависит от объема выполняемых работ.

Лендинг

от 3 дней

от 25 000 рублей

Разработка одностраничного сайта на платформе Битрикс

* стоимость зависит от наличия верстки, использования готового решения и т.д.