Создавая на днях два сайта (один новостного профиля, другой — онлайн тендеры) на MODx Evo столкнулся со следующей проблемой: товары (или новости) создаются не в виде отдельных страниц (что естественно, т.к. их может быть многие тысячи), а в виде одной страницы с параметром. Например, /news?newsid=876 или /tender?tender=873.
Стал вопрос об отдельной реализации ЧПУ для таких страниц (с подачи назойливого SEO-шника), но штатные средства MODx такой возможности не предоставляют. Пришлось написать своё решение, которое и описано ниже — авось пригодится братьям по MODx-у.
Итак, идея проста: заменить при генерации вывода страницы все ссылки вида ?newsid=xxx на транслитерацию заголовка статьи + ID (если будут одинаковые заголовки), обработать запросы к таким страницам (обработка плагином + .htaccess). Htaccess при таком подходе будет генерироваться плагином. Сразу отмечу, что страхи того, что при большом размере данного файла замедлится работа сайта не обоснованны. По крайней мере при достигнутом размере в 500Кб скорость не изменилась. Единственный возможный небольшой «тормоз» — при первом просмотре страницы с вновь созданными новостями — поскольку идет генерация ссылок и htaccess.
Для хранения данных о том, какие линки мы уже сгенерировали (чтобы не создавать htaccess при каждом просмотре даже для старых ссылок) будет использована таблица в БД. Приступим.
Готовим почву
Создаем таблицу uri по схеме:
CREATE TABLE IF NOT EXISTS `uri` ( `id` int(11) NOT NULL, `docid` int(11) NOT NULL, `link` varchar(255) NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=cp1251;
Далее, необходимо подготовить сам стандартный MODx-овый .htaccess (если у вас свой, модифицированный htaccess — принцип аналогичный, главное не забыть включить все параметры преобразования). Перемещаем блок
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
в самый конец файла с тем, чтобы вновь добавляемые строки всегда были в конце. Строка "RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]" будет дописываться после добавленных строк автоматически.
Если вы используете особые файлы (у меня — это скрипт генерации превьюшек thumb.php), то их необходимо добавить в исключения: меняем свтроку "RewriteRule ^(manager|assets|js|css|images|img)/.*$ — [L]" на «RewriteRule ^(manager|assets|js|css|images|img|php|js|css)/.*$ — [L]» и после нее пишем:
RewriteRule thumb.php$ — [L]
Стоит ли говорить, что должны быть установлены права на запись в .htaccess, если оные у него отсутствуют.
Плагин
Создаем плагин SEOAddr. Вешаем на него системные события OnWebPagePrerender и OnPageNotFound.
В коде плагина присутствует функция транслитерации кириллического заголовка в латиницу — советую оставить ее нетронутой, поскольку в иных реализациях есть проблема при транслите UTF в латиницу.
Параметры плагина:
$postpar = ‘newsid’; — собственно динамический параметр, т.е. /viewpage?newsid=232
$table = ‘oco_news_original’; — таблица, где хранится динамический контент (в моем случае — новости)
$table_title = ‘title’; — поле вышеуказанной таблицы, в котором находится заголовок статьи
$initpage = ‘news’; — страница, которая выводит новость, для /viewpage?newsid=232 это viewpage
$view_pageId = 184; — ID этой же страницы
$error404_pageId = 130; — ID страницы 404.
Таким образом, мы ищем ссылки указанного формата в генерируемой странице и заменяем их на сгенерированный алиас. К примеру, заголовок «В Испании обнаружена потерянная могила Сервантеса» транслируется в v_ispanii_obnaruzhena_poteryannaya_mogila_servantesa_191, а соответствующие ссылки /news?newsid=191 превратятся в /v_ispanii_obnaruzhena_poteryannaya_mogila_servantesa_191.
Осталось записать результат (если он еще там не присутствует) в таблицу БД «uri», дабы не делать транслит и модификацию .htaccess еще раз и подправить сам .htaccess.
Результаты
Благодаря параметрам плагина он достаточно гибок. Для подтверждения этого сделал ровно все действия, указанные в этой статье, на одном старом (рабочем) сайте — всё прошло гладко, напильник не пригодился. Тем не менее, держите напильник и руки на готове — возможно, что-то нужно будет подправить, исходя из реалий вашего сайта. Качество кода прошу не критиковать, а вот принцип — пожалуйста, предлагайте свои идеи.
$postpar = 'newsid'; $table = 'oco_news_original'; $table_title = 'title'; $initpage = 'news'; $view_pageId = 184; $error404_pageId = 130; function GetInTranslit($string) { $replace=array( "'"=>"", "`"=>"", "а"=>"a","А"=>"a", "б"=>"b","Б"=>"b", "в"=>"v","В"=>"v", "г"=>"g","Г"=>"g", "д"=>"d","Д"=>"d", "е"=>"e","Е"=>"e", "ж"=>"zh","Ж"=>"zh", "з"=>"z","З"=>"z", "и"=>"i","И"=>"i", "й"=>"y","Й"=>"y", "к"=>"k","К"=>"k", "л"=>"l","Л"=>"l", "м"=>"m","М"=>"m", "н"=>"n","Н"=>"n", "о"=>"o","О"=>"o", "п"=>"p","П"=>"p", "р"=>"r","Р"=>"r", "с"=>"s","С"=>"s", "т"=>"t","Т"=>"t", "у"=>"u","У"=>"u", "ф"=>"f","Ф"=>"f", "х"=>"h","Х"=>"h", "ц"=>"c","Ц"=>"c", "ч"=>"ch","Ч"=>"ch", "ш"=>"sh","Ш"=>"sh", "щ"=>"sch","Щ"=>"sch", "ъ"=>"","Ъ"=>"", "ы"=>"y","Ы"=>"y", "ь"=>"","Ь"=>"", "э"=>"e","Э"=>"e", "ю"=>"yu","Ю"=>"yu", "я"=>"ya","Я"=>"ya", "і"=>"i","І"=>"i", "ї"=>"yi","Ї"=>"yi", "є"=>"e","Є"=>"e" ); return $str=iconv("UTF-8","UTF-8//IGNORE",strtr($string,$replace)); } $e = &$modx->Event; switch($e->name) { case 'OnPageNotFound': $link = str_replace('/', '', $_SERVER['REQUEST_URI']); $res = $modx->db->query("SELECT * FROM `uri` WHERE `link`='".$link."' LIMIT 1"); if ( $row = $modx->db->getRow($res) ) { $lnk = '/'.$initpage.'?'.$postpar.'='.$row['docid']; $modx->sendForward( $view_pageId ); } else { $lnk = $modx->makeUrl( $error404_pageId ); $modx->sendRedirect($lnk,0,'REDIRECT_HEADER','HTTP/1.1 301 Moved Permanently'); } break; case 'OnWebPagePrerender': $doc = $modx->documentOutput; preg_match_all("/\?".$postpar."=(.*?)(\"|')/", $doc, $res); $add = ''; foreach ( $res[1] as $val ) { $val = str_replace('"', '', $val); $res = $modx->db->query("select * from `".$table."` WHERE `id`='".(int)$val."' LIMIT 1"); if ( $row = $modx->db->getRow($res) ) { $link = GetInTranslit($row[ $table_title ]); $link = str_replace(' ', '_', $link); $link = str_replace('=', '_', $link); $link = str_replace('?', '_', $link); $link = str_replace('"', '_', $link); $link = str_replace("'", '_', $link); $link = str_replace("*", '_', $link); $link = str_replace("#", '_', $link); $link = $link.'_'.(int)$val; $res = $modx->db->query("SELECT * FROM `uri` WHERE `link`='".$link."' LIMIT 1"); if ( $row = $modx->db->getRow($res) ) {} else { $modx->db->query("INSERT INTO `uri` (`docid`,`link`) VALUES ('".(int)$val."','".$link."')"); $current = file_get_contents('.htaccess'); $current = str_replace('RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]', '', $current)."\n"; $current .= 'RewriteRule '.$link.' /'.$initpage.'?'.$postpar.'='.(int)$val.' [L,QSA]'."\n"; $current .= 'RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]'."\n"; file_put_contents('.htaccess', $current); } $doc = str_replace('href="/'.$initpage.'?'.$postpar.'='.(int)$val.'"', 'href="/'.$link.'"', $doc); } } $modx->documentOutput = $doc; break; }
GitHub — зло 🙂
ссылка на оригинал статьи http://habrahabr.ru/post/261613/
Добавить комментарий