/ Добавляем региональные sitemap для умного фильтра в Aspro SmartSEO без модификаций ядра

Добавляем региональные sitemap для умного фильтра в Aspro SmartSEO без модификаций ядра

2 июн 2026
Дмитрий М.
11
Добавляем региональные sitemap для умного фильтра в Aspro SmartSEO без модификаций ядра

Для обычных разделов Aspro уже умеет работать с региональными sitemap, а вот генерировать поддоменные sitemap для умного фильтра не умеет. Из-за этого на поддоменах поисковые роботы не видят отдельные региональные XML-карты для SEO сраниц умного фильтра.

При выполнения задачи руководствовались требованиями:

  • не модифицировать ядро битрикса bitrix/modules
  • не вносить правки в исходники модулей aspro.smartseo и aspro.max
  • реализовать дополнение через устанавливаемый модуль в local
  • модицифировать страницу управления картой в модуле SmartSEO
  • использовать тот же принцип региональности, что применяется в Aspro Max для генерации региональных sitemap

В итоге получился отдельный локальный модуль client.smartseo, который:

  • добавляет флаг Генерировать карту для поддоменов в стандартную форму настройки sitemap в SmartSEO
  • хранит настройку отдельно в таблица стороннего модуля
  • после штатной генерации SmartSEO создает региональные копии sitemap
  • создает proxy PHP-файлы для выдачи нужной XML-карты в зависимости от хоста
  • поддерживает rewrite-правила для доступа к региональным sitemap по тем же URL, что и в основной карте сайта
  • синхронизирует индексную sitemap по регионам

Разберем выбранную архитектуру, причины выбранного подхода и детали реализации.

Постановка задачи

Для генерации sitemap умного фильтра используется метод updateSitemapFile() в классе Aspro\Smartseo\Engines\SitemapEngine. Метод создает XML-файл sitemap с адресами посадочных страниц для смарт фильтра, однако в ссылках используется только основной домен сайта.

Проблема в том, что сайт использует мульти-региональность на поддоменах. Для SEO это означает, что:

  • у каждого региона свой поддомен
  • ссылки в sitemap должны указывать именно на региональный хост
  • для каждого поддомена должен отдаваться свой XML-файл с корректными URL

Посмотреть, как работает региональная логика sitemap, можно в существующих файлах вроде sitemap-files.php и в логике генерации обычных поддоменных sitemap в Aspro Max. Но встроить эту логику в SmartSEO путем изменения кода модуля было нельзя: любое изменение превратилось бы в проблему при обновлении модулей.

Поэтому задача по сути свелась к разработке адаптера между SmartSEO и поддоменной региональностью в Aspro Max.

Архитектура итогового решения

Решили реализовать архитектуру:

  • на фронте дорабатываем штатную форму редактирования настроек sitemap через JS-инъекцию
  • серверную логику подключаем как post-processing после штатной генерации карты в SmartSEO

Модуль состоит из трех основных частей:

  1. Bootstrap для встраивания в жизненный цикл Bitrix и SmartSEO
  2. ORM-таблица для хранения флага генерации поддоменных sitemap
  3. сервис RegionalSitemapManager, который выполняет генерацию XML, proxy и rewrite

Файлы модуля:

  • local/modules/client.smartseo/include.php
  • local/modules/client.smartseo/lib/Bootstrap.php
  • local/modules/client.smartseo/lib/Model/SitemapSettingsTable.php
  • local/modules/client.smartseo/lib/Service/RegionalSitemapManager.php
  • local/modules/client.smartseo/assets/smartseo-detail.js
  • local/modules/client.smartseo/install/index.php

Подключение модуля: при установке, модуль сам регистрирует обработчик события main:OnBeforeProlog внутри которого происходит инициализация и подключения модуля. Это важная деталь: вся кастомизация включается и выключается установкой модуля, без правок сторонних пакетов и без привязки к local/php_interface/init.php.

Для хранения настроек генерации для sitemap была созданна отдельная таблица b_client_smartseo_sitemap. ORM-слой описан в SitemapSettingsTable:

class SitemapSettingsTable extends DataManager
{
    public static function getTableName()
    {
        return 'b_client_smartseo_sitemap';
    }
}

Отдельная таблица для хранения настроек выбрана потому что:

  • не ломаем структуру таблиц модуля SmartSEO
  • не зависим от миграций SmartSEO
  • легко удалить модуль и полностью откатить кастомизацию
  • можно безопасно обновлять исходный модуль SmartSEO

Как добавлена настройка в штатную форму SmartSEO

Настройка на страницу редактирования sitemap была добавлена при помощи JS-иньекции.

Bootstrap реализован обработчик события OnBeforeProlog, который проверяет:

  • что открыта страница /bitrix/admin/aspro.smartseo_smartseo.php
  • что текущий route равен sitemap_detail/detail

После этого модуль:

  • подключает `smartseo-detail.js`
  • передает в `window.ClientSmartseoConfig` два флага:

    • enabled
    • available
$APPLICATION->AddHeadScript('/local/modules/client.smartseo/assets/smartseo-detail.js');
$APPLICATION->AddHeadString(
    '',
    true
);

В smartseo-detail.js находим штатную форму form_sitemap, вставляем строку с checkbox и блокирует ее, если в Aspro Max не включена региональность с использованием поддоменов.

В итоге это дает:

  • остается штатная форма редактирования sitemap для SmartSEO
  • не занимаемся дублированием HTML-кода админки, для реализации собственного функционала
  • сохранена возможность обновления модуля SmartSEO
  • функционал отключается удалением модуля

Как модуль понимает, что пора обрабатывать sitemap

Для отслеживания обновления sitemap SmartSEO требуется встроиться в "жизненный цикл" генерации sitemap для умного фильтра. Для этого будем использовать shutdown processing. Идея такая:

  1. SmartSEO отрабатывает как обычно
  2. модуль запоминает route и входящие данные
  3. после завершения основного кода выполняется register_shutdown_function
  4. на shutdown запускаем свою пост-обработку и генерируем карты

Отслеживаем маршруты:

  • sitemap_detail/update
  • sitemap/generate
  • sitemap/delete
  • sitemap_detail/delete

В зависимости от route выполняются три сценария:

  • processUpdate()
  • processGenerate()
  • processDelete()

Это позволяет:

  • не вмешиваться в код SmartSEO
  • не копировать его контроллеры
  • встраиваться уже после того, как стандартный XML-sitemap точно создан

Сценарий сохранения настроек

Когда пользователь открывает страницу редактирования sitemap и ставит флаг Генерировать карту для поддоменов, checkbox отправляется как:

На shutdown маршрут sitemap_detail/update разбирается в processUpdate():

$data = static::$requestSnapshot['post']['SITEMAP'] ?? null;
$sitemapId = RegionalSitemapManager::resolveSitemapId($data);

RegionalSitemapManager::saveSetting(
    $sitemapId,
    !empty($data['GENERATE_SUBDOMAIN']) && $data['GENERATE_SUBDOMAIN'] === 'Y' ? 'Y' : 'N'
);

Тут есть важный нюанс, для только что созданной sitemap - ID может еще не быть в форме, поэтому модуль умеет восстанавливать `SITEMAP_ID` по набору полей:

  • SITE_ID
  • DOMAIN
  • SITEMAP_FILE
  • NAME

Это избавляет от неприятной проблемы - на первой генерации флаг не сохранился, потому что объект еще не имел ID.

Как определяется, доступна ли поддоменная логика?

Если в проекте не используется региональность на поддоменах, тогда не имеет смысла показывать наши настройки пользователю. Поэтому модуль проверяет состояние использования поддоменов в Aspro Max через Bitrix\Main\Config\Option

return Option::get('aspro.max', 'USE_REGIONALITY', 'N', $siteId) === 'Y'
    && Option::get('aspro.max', 'REGIONALITY_TYPE', 'ONE_DOMAIN', $siteId) === 'SUBDOMAIN';

То есть настройка активируется только если:

  • включено использование региональности
  • тип региональности выбран именно SUBDOMAIN - на поддоменах

Нельзя просто добавить checkbox и молча делать вид, что он всегда работает. Хорошая кастомизация обязана быть честной.

Как формируется список регионов

Источником данных о регионах служит инфоблок aspro_max_regions. Модуль читает:

  • PROPERTY_MAIN_DOMAIN
  • PROPERTY_DEFAULT

Если регион отмечен как default, а MAIN_DOMAIN пустой, берется SERVER_NAME текущего сайта. Схема простая:

$dbRes = \CIBlockElement::GetList(
    ['SORT' => 'ASC', 'NAME' => 'ASC'],
    [
        'ACTIVE' => 'Y',
        'LID' => $siteId,
        'IBLOCK_CODE' => 'aspro_max_regions',
    ],
    false,
    false,
    [
        'ID',
        'NAME',
        'IBLOCK_ID',
        'PROPERTY_MAIN_DOMAIN',
        'PROPERTY_DEFAULT',
    ]
);

Это позволяет использовать ту же региональную модель, которая уже есть в Aspro Max, не изобретая второй источник данных.

Как работает генерация региональных sitemap

Когда SmartSEO завершает штатную генерацию XML, модуль вызывает:

Дальше выполняем набор действий:

  1. Загружается запись sitemap из SmartseoSitemapTable
  2. Определяется, включена ли региональность для сайта
  3. Проверяется, включен ли флаг GENERATE_SUBDOMAIN
  4. Удаляются старые региональные артефакты для текущего и предыдущего имени файла
  5. Если опция активна, создаются региональные копии XML
  6. Создается proxy PHP-файл
  7. В .htaccess добавляется rewrite-правило
  8. Если sitemap включена в индексную карту, обновляются региональные копии индексного sitemap

Копирование XML и замена хостов

SmartSEO уже создал sitemap с корректным набором URL фильтра. Нам остается создать по одной копии файла на каждый регион и заменить в <loc> хост.

Для этого:

  • читает исходный XML через file_get_contents
  • проходит по всем регионам
  • сохраняет копию в aspro_regions/sitemap

Замена хостов выполняется при помощи регулярных выражений в <loc>:

return preg_replace_callback(
    '~<loc>(.*?)</loc>~is',
    function ($matches) use ($host) {
        $loc = html_entity_decode(trim($matches[1]), ENT_QUOTES | ENT_XML1, 'UTF-8');
        $loc = static::replaceUrlHost($loc, $host);

        return '<loc>' . htmlspecialchars($loc, ENT_XML1 | ENT_QUOTES, 'UTF-8') . '</loc>';
    },
    $content
);

Отказались от парсинга XML через SimpleXML или DOM по следующим причинам:

  • структура sitemap очень простая
  • не нужно менять дерево документа, только loc
  • для больших файлов текстовая обработка дешевле и быстрее

При этом важно, что мы не делаем грубый str_replace() по всему документу. Мы меняем только значения внутри <loc>, это безопаснее.

Где лежат региональные sitemap

Все региональные копии сохраняются в директорию:

Именование файлов строится так:

Например:

sitemap-aspro-smartseo_msk.example.ru.xml
sitemap-aspro-smartseo_spb.example.ru.xml

Зачем нужны proxy PHP-файлы

Сами XML-копии по регионам лежат в служебной директории. Но поисковый робот должен приходить на понятный URL sitemap и получать именно ту версию файла, которая соответствует текущему хосту. Для этого модуль генерирует proxy-файл в корне сайта, например:

Proxy работает так:

  1. берет HTTP_HOST
  2. ищет файл /aspro_regions/sitemap/<basename>_<host>.xml
  3. если находит, отдает его
  4. если не находит, отдает дефолтный XML SmartSEO
  5. если нет ничего, возвращает 404

Это очень важно, потому что:

  • один и тот же URL может обслуживать разные поддомены
  • логика выбора файла остается на сервере
  • робот не должен знать о внутренней структуре хранения

Плюс proxy отдает Content-Type, Content-Length, Last-Modified, ETag, то есть ведет себя как обычный статичный XML.

$arHost = explode(':', $_SERVER['HTTP_HOST']);
$_SERVER['HTTP_HOST'] = $arHost[0];
$hostname = $_SERVER['HTTP_HOST'];

$echoTextFile = static function ($file) {
    if (!file_exists($file) || !is_readable($file)) {
        return false;
    }

    $timestamp = filemtime($file);
    $tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT';
    $etag = md5($file . $timestamp);

    header('Content-Type: application/xml');
    header('Content-Length: ' . filesize($file));
    header("Last-Modified: $tsstring");
    header("ETag: \"{$etag}\"");

    readfile($file);

    return true;
};

$sitemapHost = $_SERVER['DOCUMENT_ROOT'] . '/aspro_regions/sitemap/sitemap-aspro-smartseo_' . $hostname . '.xml';
$sitemapDefault = $_SERVER['DOCUMENT_ROOT'] . '/aspro-sitemap/sitemap-aspro-smartseo.xml';

if (!$echoTextFile($sitemapHost) && !$echoTextFile($sitemapDefault)) {
    header('HTTP/1.0 404 Not Found');
}

Для чего использовать rewrite

Основная sitemap.xml или sitemap_index.xml может ссылаться не на root proxy-файл, а, например, на путь вида:

Если прокси существует только как /sitemap-aspro-smartseo.php, робот на поддомене просто не попадет в нужную региональную карту. Поэтому модуль дописывает правило в `.htaccess`, которое умеет направлять в proxy оба варианта пути:

  • исходный путь из SmartSEO
  • root-алиас файла

При обновлении:

  • старый блок удаляется
  • новый вставляется сразу после первого RewriteEngine On

Это решение дает два преимущества:

  • модуль управляет только своим небольшим фрагментом .htaccess
  • при повторной генерации не копятся дубли правил

Для Bitrix это особенно важно, потому что .htaccess в реальных проектах почти всегда уже перегружен историческими правилами.

Как синхронизируется индексная sitemap

Если sitemap для умного фильтра входит в индексный sitemap, то мало создать ее региональные копии. Нужно еще, чтобы региональная версия индексного файла ссылалась на правильные поддоменные карты. Для этого модуль:

  • создает копии индексного sitemap по регионам
  • меняет хосты внутри <loc>
  • удаляет из региональных index-файлов те SmartSEO sitemap, для которых опция поддоменной генерации выключена

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

Как обрабатывается удаление и переименование sitemap

Любая подобная интеграция быстро превращается в источник мусора, если не продумать cleanup. Для этого мы добавили очистку артефактов в двух случаях:

  • при удалении sitemap
  • при смене имени файла sitemap
Реализовали метод cleanupRegionalArtifacts() который удаляет:
  • proxy-файл
  • rewrite-блок из .htaccess
  • региональные XML-копии по шаблону

А если у записи изменился SITEMAP_LAST_FILE, модуль чистит и старые артефакты, чтобы не оставались устаревшие файлы и правила.

Что в итоге получил проект

После внедрения модуль дал проекту:

  • управляемую генерацию региональных sitemap для Smart Filter
  • выдачу корректных XML на каждом поддомене
  • сохранение стандартной логики работы SmartSEO
  • отсутствие вмешательства в код модуля SmartSEO
  • удобное администрирование через штатную форму

С точки зрения SEO это значит, что поисковые роботы видят региональные ссылки именно там, где ожидают их увидеть: в sitemap соответствующего поддомена. С точки зрения разработки это значит, что решение переживает обновления и не превращается в мину замедленного действия внутри bitrix/modules.

Статья была полезна? Поблагодарите автора.

Оглавление
    Самые читаемые
    #1С Битрикс, #Bitrix CMS, #.htaccess, #настройка редиректов
    4 авг 2019
    #bitrix:news, #сортировка, #фильтрация, #bitrix:catalog, #catalog.section, #news.list
    16 дек 2020
    #Хлебные крошки, #1С Битрикс, #Bitrix CMS, #bitrix:breadcrumbs, #component_epilog, #кэширование
    1 окт 2018
    #bitrix, #свойства элементов, #обработчик событий, #OnBeforeIBlockElementUpdate, #OnIBlockElementSetPropertyValues
    21 июл 2020
    #Bitrix CMS, #breadcrumb, #bitrix:breadcrumbs, #хлебные крошки, #настройка
    13 фев 2019
    #ресайз изображений, #1С Битрикс, #Bitrix CMS
    3 мар 2019
    #bitrix, #robots.txt, #sitemap.xml, #поддомены, #мультисайтовость
    16 окт 2018
    #bitrix, #bitrix:catalog.section, #скидки, #товары со скидкой, #страница скидок, #страница со скидками
    4 окт 2018
    #bitrix, #пользовательские свойства, #тип свойств, #привязка к элементам
    27 ноя 2019