Иногда на сайте нужен небольшой, но «громкий» поп-ап, который появляется на каждой странице и сообщает о важной акции, доставке или 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
— и ваш поп-ап всегда будет показывать актуальную информацию без риска дублирования.