Собственный модуль генерации sitemap для 1С-Битрикс без правок ядра
На одном из проектов столкнулся с проблемой, что Google не принимает Sitemap, если внутри одного файла, слишком много ссылок. По обсуждениям в профильных темах, для Google количество ссылок в одном файле Sitemap не должно превышать 4000 шт.
Стандартный функционал Битрикса не давал возможности настроить возможность ограничивать количество ссылок на один файл sitemap. Поэтому требовалось реализовать удобный механизм генерации Sitemap без потери штатной функциональности генерации.
Составили список конкретных требований:
- для каждого инфоблока генерировать отдельные файлы;
- ограничить каждый файл значением в 4000 URL, количество устанавливается в настройках генерации;
- именовать файлы так: sitemap-iblock-25-1.xml, sitemap-iblock-25-2.xml, sitemap-iblock-25-3.xml;
- не модифицировать ядро Битрикса;
- сохранить поддержку обновления bitrix/modules/seo;
При необходимости "переделать" штатную работу какого-то функционала Битрис возникает соблазн пойти “красивым” путем: подменить внутренние классы модуля seo, расширить класс Generator, перегрузить Runtime, аккуратно перехватить формат имени файла и реализовать логику разбиения файлов. Однако архитектурно это большой риск и 100% потеря возможнсти "безболезненно" обновлять Битрикс
В итоге выбрал другой путь: написать самостоятельный модуль, со своими настройками, таблицами и функционалом пошаговой генерации Sitemap с требуемыми возможностями.
Почему мы не стали расширять штатный SEO-модуль
В первую очередь изучил, как работает стандартная генерация Sitemap в Битрикс. Если кратко то:
- админская страница seo_sitemap_edit.php только сохраняет настройки профиля генерации;
- запуск генерации идет через внутренний Job-контроллер;
- сам процесс генерации реализован в Bitrix\Seo\Sitemap\Generator;
- для создания XML-файлов используются runtime-классы из Bitrix\Seo\Sitemap\File.
Если изменять/переопределять поведение стандартного генератора, то это приведет к:
- наличие зависимости с модулем bitrix/modules/seo;
- риск "поломки" при обновлениях;
- сложную диагностику в будущем;
- неочевидное поведение штатного функционала Битрикс для других разработчиков
Поэтому архитектурное решение было таким:
- не расширять Bitrix\Seo\Sitemap\Generator;
- не override-ить runtime-классы seo;
- реализовать самостоятельную генерацию в своем модуле;
- реализовать привычный UI интерфейс для контент-менеджеров и разработчиков.
Что именно хотели получить
Финальная требования для решения выглядели так:
- отдельный модуль в local/modules/client.sitemapgenerator;
- собственный список профилей генерации карт и страница редактирования;
- интерфейс, похожий на стандартные seo_sitemap.php и seo_sitemap_edit.php;
- отдельный индексный sitemap;
- отдельные sitemap для статических файлов;
- отдельные sitemap для каждого инфоблока;
- автоматическое разбиение файлов инфоблоков по 4000 URL - настройка задается в профиле генерации;
- обновление robots.txt;
- возможность публикации региональных копий для проектов на Aspro Max с поддоменной региональностью.
Иными словами, по итогу реализовал второй независимый генератор sitemap внутри проекта.
## Структура модуляМодуль расположен в: local/modules/client.sitemapgenerator
Основные части:
- install/index.php — регистрация модуля, создание таблиц, установка admin-файлов.
- admin/client_sitemapgenerator_profile_list.php — список профилей.
- admin/client_sitemapgenerator_profile_edit.php — редактирование профиля.
- admin/client_sitemapgenerator_run.php — экран запуска генерации.
- lib/Model/* — ORM-описания таблиц.
- lib/Service/Generator.php — основной движок генерации.
- lib/Service/ChunkedXmlWriter.php — writer с разбиением XML на части.
- lib/Service/IndexBuilder.php — сборка index-файла.
- lib/Service/JobRunner.php — пошаговый запуск generation job.
- lib/Service/ProfileImporter.php — импорт настроек из штатного SEO-модуля.
- lib/Service/RegionPublisher.php — публикация региональных копий sitemap.
- lib/Service/RobotsManager.php — обновление robots.txt.
Установка модуля и создание таблиц
Установщик находится в local/modules/client.sitemapgenerator/install/index.php
При установке:
- регистрирует модуль через ModuleManager::registerModule;
- создает собственные таблицы в базе;
- копирует административные файлы в /bitrix/admin.
Список таблиц:
- b_client_sitemap_profile
- b_client_sitemap_profile_iblock
- b_client_sitemap_profile_rule
- b_client_sitemap_job
Важный момент: не используем b_seo_sitemap и соседние таблицы штатного SEO-модуля. Все настройки и job-state лежат отдельно.
Модель данных
Таблица профиля
Основная таблица — b_client_sitemap_profile.
В ней хранятся:
- активность профиля;
- название;
- сайт;
- домен;
- протокол;
- имя index-файла;
- шаблон sitemap для статических файлов;
- шаблон sitemap для инфоблоков;
- лимит URL на файл;
- маска файлов;
- флаг обновления `robots.txt`;
- флаг публикации региональных копий;
- JSON-настройки дерева файлов.
ORM описан в ProfileTable.php
Таблица настроек инфоблоков
Для каждого профиля настройки генерации включенных инфоблоков хранится в b_client_sitemap_profile_iblock.
Для инфоблока мы сохраняем:
- активен ли он в sitemap;
- включать ли страницу списка;
- включать ли разделы;
- включать ли элементы;
- сортировку.
ORM описан в ProfileIblockTable.php
Таблица правил по разделам
Если одного флага “включить инфоблок” мало, включаются детальные правила. Эти настройки хранятся b_client_sitemap_profile_rule, где можно задать поведение на уровне разделов:
-
-
- включать разделы в sitemap; -
- включать элементы этого раздела в sitemap.
ORM описан в ProfileSectionRuleTable.php
Таблица jobs
Чтобы не выполнять тяжелую генерацию в одном HTTP-запросе, мы сделали отдельную таблицу b_client_sitemap_job.
Она хранит:
- профиль;
- текущий статус;
- текущий шаг;
- сериализованное состояние генерации;
- текст статуса.
ORM описан в JobTable.php
Это позволит сделать пошаговую генерацию без таймаутов и без необходимости переписывать процесс на агент или cron.
Почему мы повторили UI стандартного SEO-модуля
Важный UX-вывод в проектах на Битриксе звучит так: не нужно удивлять администратора без необходимости.
Если контент-менеджер уже привык к стандартному функционалу настройки генерации sitemap в seo_sitemap.php и seo_sitemap_edit.php, то новая админка должна быть максимально узнаваемой:
- такой же список;
- такие же вкладки;
- такая же логика выбора дерева файлов;
- такой же паттерн настройки инфоблоков;
- похожее поведение полей “Адрес карты сайта”.
Поэтому сознательно повторил реализацию UI стандартного SEO-модуля:
Какие проблемы мы решили на уровне архитектуры
После реализации у нас появились сразу несколько выигрышей.
1. Не затронуто ядро Битрикс
Это, пожалуй, главный плюс. Не вносились изменения в работу штатного модуля seo генерации sitemap:
- bitrix/modules/seo/admin/seo_sitemap_edit.php
- Bitrix\Seo\Sitemap\Generator
- runtime-классы seo
Это означает, что:
- остается поддержка обновления ядра Битрикс;
- решение вынесено в локальный модуль;
- "откат" делается отключением одного модуля.
2. Получили контролируемое разбиение по 4000 URL
Это было основной целью реализации отдельного модуля. Вместо одного большого `sitemap-iblock-25.xml` мы получаем:
- sitemap-iblock-25-1.xml
- sitemap-iblock-25-2.xml
- sitemap-iblock-25-3.xml
И в каждом из них не больше 4000 ссылок.
3. UI остался привычным для команды
Это способствует простоте внедрение в использование нового функционала. Пользователь видит не “какую-то самописную форму”, а почти стандартную страницу SEO-модуля Битрикса.
Итог
Изначально задача выглядела довольно локальной: разбить sitemap инфоблока на части по 4000 ссылок. Но если делать это правильно в продакшен-проекте на Битриксе, становится понятно, что одной правкой в существующем генераторе дело не ограничится. В итоге вместо хака мы сделали отдельный модуль, который:
- живет в local
- хранит свои настройки
- генерирует свои sitemap
- разбивает инфоблоки по 4000 URL
- собирает sitemap index
- умеет публиковать региональные версии
Это оказалось более надежным решением, чем подмена внутренних классов стандартного SEO-модуля.
Если в проекте есть похожая задача, я бы рекомендовал идти именно этим путем: не встраиваться в чужую закрытую реализацию глубже, чем это нужно, а выносить критичную бизнес-логику в собственный модуль с прозрачной архитектурой.