В Битриксе есть проблема отображения 404 страницы, если на сайте используются компоненты, такие как catalog/news.list и пр. (отображающие какую-либо информацию из инфоблока). Проблема заключается в том, что при запросе какого-либо несуществующего раздела/элемента — производится отображение либо надписи, что раздел/элемент не найден, либо показывается начальная страница каталога. Как же быть?
Есть решение:
В init.php добавляем
AddEventHandler("main", "OnEpilog", "ShowError404");
function ShowError404() {
if (CHTTP::GetLastStatus()=='404 Not Found') {
global $APPLICATION;
$APPLICATION->RestartBuffer();
require $_SERVER['DOCUMENT_ROOT'].SITE_TEMPLATE_PATH.'/header.php';
require $_SERVER['DOCUMENT_ROOT'] . '/404.php';
require $_SERVER['DOCUMENT_ROOT'].SITE_TEMPLATE_PATH.'/footer.php';
}
}
Обработчик вызывается в самом конце создания страницы, чтобы точно быть уверенными, что все компоненты вызвались. CHTTP::GetLastStatus() устанавливается в компонентах Битрикса, т.е. как раз тот случай, который не обыгрывается стандартным решением от Битрикса. Далее мы сбрасываем буфер, тем самым очищаем всё, что успело попасть в него до этого. Заключительным шагом мы подключаем напрямую хедер, файл 404 ошибки и футер.
Сама 404 страница может выглядеть как угодно. Например, на неё можно добавить sitemap:
Тут любой ваш текст
<?
$APPLICATION->IncludeComponent("bitrix:main.map", ".default", array(
"CACHE_TYPE" => "A",
"CACHE_TIME" => "36000000",
"SET_TITLE" => "Y",
"LEVEL" => "3",
"COL_NUM" => "2",
"SHOW_DESCRIPTION" => "Y"
),
false
);
?>
Другим решением является явный костыль, но всё же его можно взять на заметку.
Идея в следующем: проверить присутствует ли элемент/раздел в инфоблоке товаров с символьным кодом взятым из URL адреса. Если присутствует — показывать страницу товара/раздела, если нет — показывать 404 ошибку:
//получим последний непустой элемент разбивки url по разделителю "/":
$sections = explode('/', $APPLICATION->GetCurPage());
$sections = array_filter(
$sections,
function($el){ return !empty($el);}
);
$last_el = end($sections);
$show_404 = true;
$arFilter = Array("IBLOCK_ID"=>50, "ACTIVE"=>"Y", "CODE"=>$last_el);
$arSelect = Array("ID", "NAME");
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
if($ob = $res->GetNext())
{
$show_404 = false;
}
$res = CIBlockSection::GetList(Array(), $arFilter, false, $arSelect);
if($ob = $res->GetNext())
{
$show_404 = false;
}
if ($show_404) echo '404';
if(($show_404)&&(!CSite::InDir("/404.php")))
{
LocalRedirect("/404.php");
}