Способы включения подразделов инфоблоков в пути для ЧПУ не раз обсуждались и эти способы были разными. В этой статье я хочу описать ещё один способ.
Суть моего решения состоит в том, чтобы до подключения компонента заменять $_SERVER["REQUEST_URI"] на понятный для компонента путь, а затем вresult_modifier.php возвращать в $_SERVER["REQUEST_URI"] путь понятный для пользователя, т.е. со всеми подразделами.
Опишу по пунктам, что необходимо сделать, чтобы на сайте заработали правила ЧПУ вида:
#НАЗВАНИЕ_РАЗДЕЛА#/#НАЗВАНИЕ_ПОДРАЗДЕЛОВ#/#НАЗВАНИЕ_ЭЛЕМЕНТА#/
UPD. В последней версии продукта вышла возможность реализовать подобный функционал стандартно, используя в шаблонах ссылок #SECTION_CODE_PATH# [spoiler]
Настройки.
1. В настройках инфоблока указываем:
2. В настройках компонента "Каталог" указываем:
Конечно же "test" в обоих случаях необходимо заменить на путь к Вашему разделу.
Код.
1. В файл "/bitrix/php_interface/init.php" вставляем:
2. Перед кодом вызова компонента "Каталог" вставляем:
3. В шаблоне компонента "Каталог" создаём(если не создан) файл result_modifier.php (например, в папке "/bitrix/components/bitrix/catalog/templates/.default/" ) с содержимым:
Чтобы пересчитать все символьные коды элементов и разделов определённого инфоблока, в "Настройки - Инструменты - Командная PHP-строка" достаточно выполнить код:
где $IBLOCK_ID - ID требуемого инфоблока. Стоит учитывать, что если в инфоблоке достаточно много элементов и разделов, то метод может не успеть выполнится до истечения лимита. В этом случае Вам понадобится самостоятельно писать пошаговый скрипт.
В обработчиках изменения/добавления разделов и элементов инфоблока, скорее всего, Вам необходимо будет указать условия выполнения кода для конкретного инфоблока.
Также, обратите внимание на то, что в файле "/bitrix/php_interface/init.php" вызывается метод CSubsections::InitParser(), который инициализирует обработчик события "OnEndBufferContent". Этот обработчик заменяет все "urlencode'нные" ядром символы "/" обратно. Это не совсем правильно, но избавляет от создания многочисленных файловresult_modifier.php для всех компонентов, выводящих ссылки на разделы и элементы, а это все простые компоненты, входящие в состав комплексного компонента "Каталог", компоненты модуля "Поиск" и т.д.
Суть моего решения состоит в том, чтобы до подключения компонента заменять $_SERVER["REQUEST_URI"] на понятный для компонента путь, а затем в
Опишу по пунктам, что необходимо сделать, чтобы на сайте заработали правила ЧПУ вида:
#НАЗВАНИЕ_РАЗДЕЛА#/#НАЗВАНИЕ_ПОДРАЗДЕЛОВ#/#НАЗВАНИЕ_ЭЛЕМЕНТА#/
UPD. В последней версии продукта вышла возможность реализовать подобный функционал стандартно, используя в шаблонах ссылок #SECTION_CODE_PATH# [spoiler]
Настройки.
1. В настройках инфоблока указываем:
URL страницы информационного блока: #SITE_DIR#test/ URL страницы раздела: #SITE_DIR#test/#SECTION_CODE#/ URL страницы детального просмотра: #SITE_DIR#test/#ELEMENT_CODE#/ |
Включить поддержку ЧПУ: Да Каталог ЧПУ (относительно корня сайта): /test/ Раздел: #SECTION_ID#/ Детальная информация: #SECTION_ID#/#ELEMENT_ID#/ |
Код.
1. В файл "/bitrix/php_interface/init.php" вставляем:
<? class CSubsections { function Init() { global $APPLICATION; $sef_folder = (isset($_SERVER["REAL_FILE_PATH"]) && $_SERVER["REAL_FILE_PATH"] != "" ? str_replace("index.php", "", $_SERVER["REAL_FILE_PATH"]) : $APPLICATION->GetCurDir(false) ); $uri = $GLOBALS["BACK_REQUEST_URI"] = $APPLICATION->GetCurDir(false); $uri = str_replace($sef_folder, "", $uri); $uri = trim($uri, "/"); $tmp_uri = ""; if($uri && CModule::IncludeModule("iblock")) { $rs = CIBlockElement::GetList( array(), array("=CODE" => $uri), false, array("nTopCount" => 1), array("ID", "IBLOCK_ID", "IBLOCK_SECTION_ID", "NAME") ); if($ar = $rs->Fetch()) { $tmp_uri = $sef_folder.intval($ar["IBLOCK_SECTION_ID"])."/".$ar["ID"]."/"; } else { $rs = CIBlockSection::GetList( array(), array("=CODE" => $uri), false, array("ID") ); if($ar = $rs->Fetch()) { $tmp_uri = $sef_folder.$ar["ID"]."/"; } } } if($tmp_uri) { $_SERVER["REQUEST_URI"] = $REQUEST_URI = $tmp_uri; $APPLICATION->sDocPath2 = $tmp_uri."index.php"; CSubsections::InitParser(); } elseif($sef_folder == $APPLICATION->GetCurDir(false)) { CSubsections::InitParser(); } } function Back($arResult) { global $APPLICATION; $arResult["URL_TEMPLATES"]["section"] = "#SECTION_CODE#/"; $arResult["URL_TEMPLATES"]["element"] = "#ELEMENT_CODE#/"; $_SERVER["REQUEST_URI"] = $REQUEST_URI = $GLOBALS["BACK_REQUEST_URI"]; $APPLICATION->sDocPath2 = $GLOBALS["BACK_REQUEST_URI"]."index.php"; unset($GLOBALS["BACK_REQUEST_URI"]); } function Parse($html) { $html = str_ireplace("%"."2f", "/", $html); } function InitParser() { if(!defined("CSUBSECTIONS_INIT_HANDLER")) { define("CSUBSECTIONS_INIT_HANDLER", true); AddEventHandler("main", "OnEndBufferContent", array("CSubsections", "Parse"), 10000); } } function GetCode($iblock_id, $section_id, $element_name="") { $arPath = array(); if(CModule::IncludeModule("iblock")) { if($element_name) { $element_name = CUtil::translit($element_name, LANGUAGE_ID); $element_name = $element_name? "/".$element_name: ""; } if($rs = CIBlockSection::GetNavChain($iblock_id, $section_id)) { while($ar = $rs->Fetch()) { $arPath[] = CUtil::translit($ar["NAME"], LANGUAGE_ID); } } } return trim(implode("/", $arPath).$element_name, "/"); } function ElementAddHandler($arFields) { //if($GLOBALS["IBLOCK_ID"] == $IBLOCK_ID) //{ $oElement = new CIBlockElement(); $oElement->Update($arFields["ID"], array("CODE" => "recalculate")); //} } function ElementUpdateHandler($arFields) { //if($GLOBALS["IBLOCK_ID"] == $IBLOCK_ID) //{ if($rs = CIBlockElement::GetByID($arFields["ID"])) { if($ar = $rs->Fetch()) { $arFields["CODE"] = CSubsections::GetCode( $ar["IBLOCK_ID"], $ar["IBLOCK_SECTION_ID"], $ar["NAME"] ); } } //} } function SectionAddHandler($arFields) { //if($GLOBALS["IBLOCK_ID"] == $IBLOCK_ID) //{ $oSection = new CIBlockSection(); $oSection->Update($arFields["ID"], array("CODE" => "recalculate")); //} } function SectionUpdateHandler($arFields) { //if($GLOBALS["IBLOCK_ID"] == $IBLOCK_ID) //{ $arFields["CODE"] = CSubsections::GetCode( $arFields["IBLOCK_ID"], $arFields["ID"] ); //} } function Recalculate($iblock_id) { if(CModule::IncludeModule("iblock")) { $oSection = new CIBlockSection(); if($rs = CIBlockSection::GetList(array(), array("IBLOCK_ID" => $iblock_id), false, array("ID"))) { while($ar = $rs->Fetch()) { $oSection->Update($ar['ID'], array("CODE" => "recalculate")); } } $oElement = new CIBlockElement(); if($rs = CIBlockElement::GetList(array(), array("IBLOCK_ID" => $iblock_id), false, false, array("ID"))) { while($ar = $rs->Fetch()) { $oElement->Update($ar['ID'], array("CODE" => "recalculate")); } } } } } AddEventHandler("iblock", "OnAfterIBlockElementAdd", array("CSubsections", "ElementAddHandler")); AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", array("CSubsections", "ElementUpdateHandler")); AddEventHandler("iblock", "OnAfterIBlockSectionAdd", array("CSubsections", "SectionAddHandler")); AddEventHandler("iblock", "OnBeforeIBlockSectionUpdate", array("CSubsections", "SectionUpdateHandler")); CSubsections::InitParser(); ?> |
<?CSubsections::Init();?> |
<?CSubsections::Back(&$arResult);?> |
Чтобы пересчитать все символьные коды элементов и разделов определённого инфоблока, в "Настройки - Инструменты - Командная PHP-строка" достаточно выполнить код:
CSubsections::Recalculate($IBLOCK_ID); |
В обработчиках изменения/добавления разделов и элементов инфоблока, скорее всего, Вам необходимо будет указать условия выполнения кода для конкретного инфоблока.
Также, обратите внимание на то, что в файле "/bitrix/php_interface/init.php" вызывается метод CSubsections::InitParser(), который инициализирует обработчик события "OnEndBufferContent". Этот обработчик заменяет все "urlencode'нные" ядром символы "/" обратно. Это не совсем правильно, но избавляет от создания многочисленных файлов