В стандартной поставке Битрикс есть только один вариант человекопонятных URL — номерные, т.е. мы можем сделать достаточно легко, чтобы ссылка на товар каталога выглядела не так
/catalog/detail.php?ELEMENT_ID=111 , а более приятным образом. Например, вот так /catalog/detail/111/ или как-то еще — все это зависит от нашей фантазии.
Но мы не можем сделать, чтобы ссылка имела вместо цифрового идентификатора 111 , какой-либо символьный, например ice-cream.
Но ведь ссылки вида /catalog/ice-cream/ выглядят явно лучше, чем /catalog/detail/111/ .
Я этой статье я попробую дать решение этой проблемы.
Итак, как же сделать так, чтобы ссылки стали совсем уж дружественными к человеку?
Первая задача — направить ссылки вида /catalog/ice-cream/ на страницу /catalog/detail.php
Для этого придется обратиться к интерфейсу «Настройка правил обработки адресов» ( /bitrix/admin/urlrewrite_list.php?lang=ru ).
Создаем новое правило:
Условие: #^/catalog/([a-zA-Z0-9-]+)/#
Файл: /catalog/detail.php
Правило: ELEM=$1
Можно проверить — это правило будет направлять все подобные ссылки на страницу /catalog/detail.php , но там у нас стоит компонент bitrix:catalog.element, который умеет искать
элементы только по их ID. А мы же предлагаем какой-то символьный код.
Решения таким образом может быть два: либо мы как-то конвертируем код в численный идентификатор, либо переделываем компонент, чтобы он находил элементы по символьному коду.
В каждом из этих случаев нам нужна таблица сопоставления значений символьный код — ID элемента. По моему мнению, проще всего добавить строковое свойство в инфоблок товары.
Назовем его SEF (Search Engine Friendly). И напишем в элемент, который имеет ID 111 в это свойство ice-cream.
Следующая задача — нужно таки преобразовать символьный код в ID код элемента. Проще всего это делать сразу для всех элементов в файле /bitrix/templates/init.php
Примерно так:
RegisterModuleDependences(«main», «OnBeforeProlog», «main», «CMyBot», «StartBuffer», «100»);
class CmyBot
{
function StartBuffer()
{
if (defined(«ADMIN_SECTION») && ADMIN_SECTION===true) return;
define(«MYBOT_IS_ACTIVE», true);
ob_start();
if ($_SERVER[«REAL_FILE_PATH»]==»/catalog/detail.php» && $_REQUEST[«ELEM»]!=»»)
{
$arFilter = Array(«IBLOCK_ID»=>$IBLOCK_ID, «ACTIVE_DATE»=>»Y», «ACTIVE»=>»Y», «PROPERTY_SEF»=>$_REQUEST[«ELEM»]);
$res = CIBlockElement::GetList(Array(), $arFilter, false);
while($ob = $res->GetNextElement())
{
$arFields = $ob->GetFields();
$_REQUEST[«ELEMENT_ID»] = $arFields[«ID»];
}
}
}
function EndBuffer()
{
if(defined(«MYBOT_IS_ACTIVE»))
{
$content = ob_get_contents();
ob_end_clean();
echo $content;
}
}
}
И последняя задача — было бы очень здорово, если бы все ссылки вида /catalog/detail.php?ELEMENT_ID=число автоматически преобразовывались в красивый вид.
Решается это примерно так:
RegisterModuleDependences(«main», «OnAfterEpilog», «main», «CMyBot», «EndBuffer», «100»);
function EndBuffer()
{
if(defined(«MYBOT_IS_ACTIVE»))
{
$content = ob_get_contents();
ob_end_clean();
preg_match_all(«/\/catalog\/detail.php\?.*ELEMENT_ID=([0-9]+)/i», $content, &$matches);
if (count($matches[0]) > 0)
{
$arFilter = Array(«IBLOCK_ID»=>$IBLOCK_ID, «ID»=>$matches[1][$i], «ACTIVE_DATE»=>»Y», «ACTIVE»=>»Y»);
$res = CIBlockElement::GetList(Array(), $arFilter, false);
while($ob = $res->GetNextElement())
{
$arProps = $ob->GetProperties();
}
$arSef[$i] = «/catalog/».$arProps[«SEF»][«VALUE»].»/»;
}
$content = str_replace($matches[0], $arSef, $content);
}
echo $content;
}
Надеюсь, кому-нибудь мои изыскания помогут решить подобную задачу.
В битриксе уже давно есть возможность делать чпу на символьных кодах. При этом не нужно ничего дописывать руками, только настройки инфоблока + настройки компонента.
Вы можете описать поподробнее ваш вариант реализации?
Посмотрите внимательно, я ведь даю полную обработку ЧПУ, т.е. и на входе ссылки подменяются, а на выходе обрабатываются.
Возможно я не до конца понял реализации этого метода, но, повторюсь, комплексный компонент каталога (новостей) умеет сам обрабатывать чпу ссылки на кодах.
К тому же у Вашего метода есть один существенный недостаток — лишние запросы к базе на каждом хите в каталоге. Закешировать бы все это дело:)
Смысл метода в том, что его можно применять для любой структурированной информации. А вы говорите про комплексный компонент новостей. :)
Кеширование html никто не отменял кстати. Оно абсолютно также будет работать как и для любой другой страницы.
Если есть желание продолжать дискуссию, давайте по e-mail пообщаемся, мне действительно интересно что можно сделать по этому методу и нельзя сделать комплексными новостями)) Пишите, обменяемся опытом.
А про кеширование — тут в StartBuffer() и EndBuffer() надо бы PHPCache прикрутить, чтобы GetList на каждом хите не отрабатывал.
жесть…
а чем, простите, #ELEMENT_CODE# в ЧПУ вас не устраивает?
Выше написал почему. Недостаточная гибкость такого решения.