YII СЕО оптимизация сайта





При построении любого сайта в какой-то момент разработчик сталкивается с требованиями поисковой оптимизации. Традиционно она включает в себя построение правильной адресной структуры, исключение из индексации служебных страниц и неинтересных для поискового робота фрагментов, добавление метаинформации для записей. Более расширенный вариант подразумевает специфическое распределение ссылочного веса и борьбу с дубликатами адресов.

Заголовок окна и метатеги


По правилам хорошего тона каждая наша запись должна сопровождаться корректным заголовком окна, описанием и ключевыми словами. То есть приблизительно так:


<head>
<
title>Разведение кроликов | Блог о кроликах</title>
<
meta name="description" content="Статья о кроликах" />
<
meta name="keywords" content="кролики, разведение, питание" />
</
head>



В представлениях мы можем добавлять метатеги как явно, так и как скрипты и стили с помощью компонента clientScript.

Достаточно вписать вручную только формирование заголовка. Для этого в классе CController уже имеется свойство pageTitle, так что мы без проблем можем использовать его в шаблоне:


<head>
<
title><?php echo CHtml::encode($this->pageTitle); ?> | <?php echo Yii::app()->name; ?></title>
</
head>



А присваивать этот заголовок и добавлять новые теги можем уже в конкретных представлениях:


<?php
$this->pageTitle = $model->pagetitle;
Yii::app()->clientScript->registerMetaTag($model->description, 'description');
Yii::app()->clientScript->registerMetaTag($model->keywords, 'keywords');
?>

<
h1><?php echo CHtml::encode($model->title); ?></h1>



Для хранения значений нужно не забыть добавить соответствующие поля в таблицу и модель наших статей. Если отдельные значения записывать не хочется, то можно генерировать их автоматически:


<?php
$this->pageTitle = $model->title;
Yii::app()->clientScript->registerMetaTag(strip_tags(mb_substr($model->text, 0, 200, 'utf-8')) . '...', 'description');
Yii::app()->clientScript->registerMetaTag(implode(', ', CHtml::listData($model->tags, 'id', 'name')), 'keywords');
?>



Хотя это не очень хорошо с точки зрения поисковой оптимизации.

Если конструкция с Yii::app()->clientScript кажется слишком громоздкой, то можно пойти по стопам свойства pageTitle и ввести новые поля description и keywords в базовый контроллер:


class Controller extends CController
{
public $menu = array();
public $breadcrumbs = array();

public $description = '';
public $keywords = '';
}



Теперь в представлениях достаточно присваивать значения этим полям:


<?php
$this->pageTitle = $model->pagetitle;
$this->description = $model->description;
$this->keywords = $model->keywords;
?>

<
h1><?php echo CHtml::encode($model->title); ?></h1>



А присвоенные значения уже выводить в шаблоне через clientScript или вручную:


<head>
<
title><?php echo CHtml::encode($this->pageTitle); ?> | <?php echo Yii::app()->name; ?></title>
<
meta name="description" content="<?php echo CHtml::encode($this->description); ?>" />
<
meta name="keywords" content="<?php echo CHtml::encode($this->keywords); ?>" />
</
head>



Теперь для всех страниц и новостей можно будет прописывать метатеги.

Дубли значений метатегов


Какие значения <title> будет у первых четырёх страниц при паджинации блога про кроликов? Приблизительно такие:
Разведение кроликов
Разведение кроликов
Разведение кроликов
Разведение кроликов

Все разделы с перелистыванием страниц будут нести одинаковые имена.

Если вы решили закрыть все кроме первой страницы директивой Disallow в файле robots.txt, то переживать не стоит.

Аналогично с описаниями description категории. В панели вебмастеров Google вы встретите негодование поисковой системы по этому поводу. Из-за повторов заголовка в индексе будет находиться всего одна страница.

Самое лучшее решение в случае необходимости индексации всех страниц заключается в написании уникального заголовка для каждой. Это нам врядли под силу, поэтому проще сделать автоматическое добавление номера страницы:
Разведение кроликов
Разведение кроликов - Страница 2
Разведение кроликов - Страница 3
Разведение кроликов - Страница 4

Для этого достаточно получить номер и добавить его к значениям соответствующих полей:


<?php
$page = (int)Yii::app()->request->getQuery('page', 1);

$this->pageTitle = $model->pagetitle . ($page > 1 ? ' - Страница ' . $page : '');
$this->description = $model->description . ($page > 1 ? ' - Страница ' . $page : '');
$this->keywords = $model->keywords;
?>



Удобнее переместить всю логику в помощник:


class PageHelper
{
static public function pageString($param = 'page')
{
$page = (int)Yii::app()->request->getQuery($param, 1);
return $page > 1 ? ' - Страница ' . $page : '';
}
}



и использовать его:


<?php
$this->pageTitle = $model->pagetitle . PageHelper::pageString('page');
$this->description = $model->description . PageHelper::pageString('page');
$this->keywords = $model->keywords;
?>



Теперь на сайте не будет дублирующихся заголовков.

Это не так уж хорошо решает проблемы ранжирования, но немного помогает.

Установка rel=nofollow для ссылок из блоков кода


Представим, что у нас есть какой-либо блок текста или облако меток со ссылками. Порой для исключения их из индексации и из распределения ссылочного веса страниц этот блок нужно поместить в <noindex> и всем ссылкам добавить атрибут rel="nofollow".

Для выполнения этой работы в представлении лучше всего подходит виджет. Напишем его:


class DNofollowWidget extends СWidget
{
public function init() {
ob_start();
ob_implicit_flush(false);
}

public function run() {
$html = ob_get_clean();
$html = preg_replace('#<a(\s([^>]+))?\srel="[^"]*"#is', '<a$1', $html);
$html = str_replace('<a ', '<a rel="nofollow" ', $html);
echo $html;
}
}



Мы включаем буферизацию, получаем переданный HTML-код, удаляем атрибут rel у ссылок и подставляем rel="nofollow".

Теперь достаточно окружить любое меню данным виджетом:


<noindex>
<?
php $this->beginWidget('NofollowWidget'); ?>
<?
php $this->beginWidget('zii.widgets.CMenu', array(
'items'=>Tag::model()->getMenuList(),
); ?>
<?
php $this->endWidget(); ?>
</
noindex>



и облако меток или вспомогательное меню не будет больше распылять ссылочный вес.

Определение текущего маршрута


Порой в представлении или шаблоне бывает нужно узнать, из какого действия и какого контроллера это представление вызвали.

В WordPress для определения текущего положения имеются функции is_front_page(), is_category и некоторые другие. Это удобно использовать, например, чтобы не использовать ссылку с логотипа на главной странице.

Для этих целей в Yii удачно подходит параметр route контроллера. Он содержит текущий маршрут, состоящий из имени модуля, контроллера и действия. Если модулей в системе нет, то он содержит только контроллер и действие. Это свойство можно использовать для условных конструкций в представлениях.

Предположим, что у нас есть какой-либо текст в сайдбаре, и мы хотим закрыть его от индексирования для всех страниц, кроме главной.

Для этого в шаблоне мы можем обрамить данный блок конструкцией <noindex> (или её валидным вариантом <!--noindex-->) для всех маршрутов, кроме SiteController::actionIndex:


<?php if ($this->route != 'site/index'): ?><!--noindex--><? endif; ?>
<
p>Приветствуем Вас!</p>
<?
php if ($this->route != 'site/index'): ?><!--/noindex--><? endif; ?>



Аналогично с условным вызовом рассмотренного ранее виджета можно открыть ссылки во вспомогательном меню только на главной странице:


<?php if ($this->route != 'site/index') $this->beginWidget('DNofollowWidget'); ?>

<?
php $this->beginWidget('zii.widgets.CMenu', array(
'items'=>Category::model()->getMenuList(),
); ?>

<?
php if ($this->route != 'site/index') $this->endWidget(); ?>



Можно, например, вообще закрыть какое-либо меню на странице записи блога (то есть по маршруту blog/post/view) для избежания утечки ссылочного веса.

Аналогично можно использовать другие свойства контроллера:


$this->id;
$this->action->id;
$this->module->id;



Что равносильно прямому вызову соответствующих геттеров:


$this->getId();
$this->getAction()->getId();
$this->getModule()->getId();



С их помощью можно легко определить имя текущего контроллера, действия и модуля.

Находясь в виджете переменная $this ссылается на сам виджет, а не на контроллер. Нужно сначала получить контроллер, а уже потом обращаться к нему:


Yii::app()->controller->id;
Yii::app()->controller->action->id;
Yii::app()->controller->module->id;



Указание rel=nofollow для активного пункта меню


При построении любого меню с помощью виджета CMenu возникает ситуация, что активный элемент остаётся активной ссылкой и по-прежнему ссылается на текущую страницу. Получается бесконечная циклическая ссылка со страницы, ведущая на саму себя.

Переопределим и немного дополним метод CMenu::normalizeItems в нашем новом классе:


Yii::import('zii.widgets.CMenu');

class Menu extends CMenu
{
protected function normalizeItems($items,$route,&$active)
{
foreach($items as $i=>$item)
{
if(isset($item['visible']) && !$item['visible'])
{
unset($items[$i]);
continue;
}
if(!isset($item['label']))
$item['label']='';
if($this->encodeLabel)
$items[$i]['label']=CHtml::encode($item['label']);
$hasActiveChild=false;
if(isset($item['items']))
{
$items[$i]['items']=$this->normalizeItems($item['items'],$route,$hasActiveChild);
if(empty($items[$i]['items']) && $this->hideEmptyItems)
{
unset($items[$i]['items']);
if(!isset($item['url']))
{
unset($items[$i]);
continue;
}
}
}
if(!isset($item['active']))
{
if($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item,$route))
$active=$items[$i]['active']=true;
else
$items[$i]['active']=false;
}
elseif($item['active'])
$active=true;
if(isset($items[$i]['active']) && $items[$i]['active'])
$items[$i]['linkOptions']['rel']='nofollow';

}
return array_values($items);
}
}



Мы взяли код из исходного метода и дописали пару строк:


if(!isset($items[$i]['active']) && $items[$i]['active'])
$items[$i]['linkOptions']['rel']='nofollow';



в которых активным ссылкам добавляется соответствующий атрибут.

Теперь вместо zii.widgets.CMenu можно использовать свой класс Menu:


<?php $this->beginWidget('Menu', array(
'items'=>Category::model()->getMenuList(),
); ?>



и активная ссылка будет автоматически снабжена атрибутом rel="nofollow".

Noindex для «хвоста» хлебных крошек


При использовании «хлебных крошек» с включённым выводом текущего заголовка у нас на странице будет дублирование текста. Например, так:


<div class="breadcrumbs">
<
a href="/">Главная</a> / <a href="/blog">Блог</a> / <span>Размножение кроликов в дикой природе</span>
</
div>
<
h1>Размножение кроликов в дикой природе</h1>



Одна и та же фраза (заголовок) написана два раза рядом, что не очень хорошо.

Для борьбы с таким контентным «спамом» можно заменить шаблон последнего элемента:


<?php $this->widget
                    
                
                    1194  
                
                                
                    0  
                
                

Comments

    Ничего не найдено.