В Битриксе есть проблема отображения 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"); }