Битрикс «по рецепту»: админка, кеш, сортировка, пагинация и мелкие подводные камни
Зачем вторая «поваренная книга»
Подборка практических ситуаций из жизни внедрений: когда продукт ведёт себя предсказуемо для ядра, но неочевидно для команды разработки. Текст переработан с опорой на смысл исходной заметки, без кальки с формулировок оригинала.
Восстановление доступа к админке «из коробки»
Стандартный сценарий «забыл пароль — получил токен на почту» работает только если форма авторизации реально поддерживает цепочку восстановления. Если /bitrix/admin/ ведёт на кастомный /auth/, где эта ветка не реализована, письмо с ссылкой просто не появится в жизненном цикле — это не «сломалось», а отсутствует логика на стороне проекта. Закладывайте отдельный маршрут сброса или резервный вход для суперпользователя ещё на этапе сдачи, а не после блокировки.
Кеш: dev и prod говорят на разных языках
На разработке кеш часто выключён, на бою включён — после «полной очистки» симптомы всё равно могут плавать.
Меню «перепрыгивает» относительно заголовка. Часто виноват порядок вызовов буфера и заголовка: имеет значение, где и как задаётся ShowTitle и что успело попасть в буфер до отрисовки шапки. Сверьтесь со справкой по CMain::ShowTitle и цепочке подключений в шаблоне.
Не доезжают подключённые JS у композитного компонента. Автокеширование может «заморозить» дерево включаемых файлов там, где ожидалась динамика. Выходы типовые: вынести скрипт на уровень шаблона сайта или страницы, отключить кеш проблемного компонента там, где без этого не обойтись, либо пересмотреть схему вывода ресурсов в шаблоне компонента.
На главной «пропадают» блоки, хотя локально всё есть. Убедитесь, что нужный код действительно сработал до выборки: для инфоблоков это часто тривиальное CModule::IncludeModule('iblock') до первого обращения к CIBlockElement; при автозагрузке классов порядок подключений на проде может отличаться от IDE.
Медиабиблиотека и «хочу свой порядок»
Штатная медиабиблиотека удобна для каталогизации файлов, но гибкая сортировка внутри коллекций зачастую не то, что просят в ТЗ вида «сначала рубрика, внутри — область, внутри — имя тома». Через стандартные фильтры выборки API это редко выразить без компромиссов.
Практичный компромисс — один раз забрать идентификаторы с нужным порядком на уровне SQL (с пониманием схемы и бэкапом перед массовыми правками), а затем подставить список ID в условие выборки. Пример упрощённый: упорядочивание по сортировке раздела, затем по названию связанного элемента-свойства, затем по имени самой записи:
SELECT el.ID
FROM b_iblock_element el
JOIN b_iblock_section sec ON sec.ID = el.IBLOCK_SECTION_ID
LEFT JOIN b_iblock_element_property ep
ON ep.IBLOCK_ELEMENT_ID = el.ID AND ep.IBLOCK_PROPERTY_ID = 165
LEFT JOIN b_iblock_element linked ON linked.ID = ep.VALUE
WHERE el.IBLOCK_ID = 41
AND el.ACTIVE = 'Y'
AND (el.ACTIVE_FROM IS NULL OR el.ACTIVE_FROM <= NOW())
AND (el.ACTIVE_TO IS NULL OR el.ACTIVE_TO >= NOW())
ORDER BY sec.SORT, linked.NAME, el.NAME;Подставьте свои IBLOCK_ID и идентификатор свойства; для сложных типов свойств логику джойна проверьте на копии базы.
Пагинация, когда нужен «пользовательский» порядок ID
Если список ID уже отсортирован вне компонента, типовой фильтр по массиву идентификаторов не гарантирует сохранение этого порядка в выдаче. Пересортировать десять записей только в result_modifier легко, но номера страниц тогда становятся бессмысленными для всего набора.
Обходной путь без переписывания всего компонента — считать полное число элементов вашим кодом и подсовывать пагинации объект результата инфоблока с заполненными полями навигации. Упрощённый каркас (имена и объект навигации подставьте из своего места вызова):
function buildStubNavResult(
$navRecordCount,
$navPageSize,
$navPageNomer
) {
$stub = new CIBlockResult();
$stub->NavRecordCount = (int)$navRecordCount;
$stub->NavPageSize = (int)$navPageSize;
$stub->NavPageNomer = (int)$navPageNomer;
$stub->NavPageCount = (int)ceil(
$stub->NavRecordCount / max(1, $stub->NavPageSize)
);
return $stub;
}
// $navComponent — экземпляр компонента из $this в шаблоне
// $stub = buildStubNavResult($totalIds, $pageSize, $currentPage);
// echo $stub->GetPageNavStringEx(
// $navComponent,
// $pagerTemplate,
// $pagerTitle,
// $showAlways
// );Смысл тот же, что и в классической схеме «два набора»: один объект отвечает за строку страниц, второй за фактический срез данных, синхронизированный по номеру страницы.
Визуальный редактор и атрибуты ссылок
В ряде версий типовой редактор при сохранении мог «съедать» пользовательские data-* у тега <a>, хотя после ручной правки они снова оказывались в тексте элемента. Если для аналитики или виджета критичны дата-атрибуты, проверяйте финальный HTML после сохранения и при необходимости включайте соответствующие белые списки в настройках редактора либо обходите «чистку» через уместный режим поля или отдельное свойство.
Капча при авторизации — не всё настраивается интуитивно
Варианты включаются по-разному: капча на регистрации, капча после нескольких неверных попыток входа, но редко «с первой секунды» для формы логина — и это накладывает ограничения на UX и безопасность. Отдельно помните, что для явно несуществующего логина капча может вообще не показываться, что упрощает перебор существующих учётных имён при грубом сценарии. Думайте о лимитах по IP, задержках и журналировании параллельно со штатной капчей.
Итог
Большинство описанных вещей решаются сочетанием осознанной настройки кеша и авторизации и точечной доработки выборки или навигации там, где API не экспортирует нужный порядок «из коробки».
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии