RSS для Яндекс.новостей
Мы решили подключить наш сайт к Яндекс.новостям. Яндексу нужна RSS особого вида, та, что livestreet отдаёт из коробки ему не подходит.
За основу был взят ActionRSS, который есть в ливстрите с самого начала. Вообще-то я в php ни в зуб ногой, на работе пишу на c++, и ливстрит увидел в первый раз в жизни, так что работа эта заняла у меня не меньше 4 часов. В том числе потому что документацию к движку я тогда найти не смог.
Вот такие задачи следовало решить:
А такие задачи решить было желательно, но не обязательно:
Проблему фильтрации договорились решить следующим образом — в RSS попадают только посты с главной, помеченные определенным тегом. Чтобы он не мозолил глаз огромным шрифтом в облаке тегов, я отключил его показ в облаке. Это, конечно, костыль, и рано или поздно я эту радость заменю чем-нибудь поприличнее — например, отдельным булевым полем в базе и галочкой «Пустить на Яндекс» у администратора. Или хотя бы выделю в плагин.
Очень не хотелось писать парсер, который бы вылавливал медиа-элементы из новости и добавлял их в RSS как элементы <enclosure>. Тем более, что вообще-то не всякую картинку из статьи стоит добавлять к новости. Зато у нас шаблон simple, который позволяет к каждому посту добавить картинку-preview. Вот её мы и решили запихивать в RSS. На всякий случай я сделал эту функциональность отключаемой.
RSS-лента будет располагаться по адресу /yandex_rss. Полученная в результате RSS-лента была подключена к Яндексу без малейших нареканий.
А вот получившийся код.
/classes/actions/YandexRss.class.php
/templates/skin/ваш темплейт/actions/ActionYandexRss/index.tpl
эти строчки нужно добавить в /config/config.local.php
а это костыль в /classes/blocks/BlockTags.class.php
За основу был взят ActionRSS, который есть в ливстрите с самого начала. Вообще-то я в php ни в зуб ногой, на работе пишу на c++, и ливстрит увидел в первый раз в жизни, так что работа эта заняла у меня не меньше 4 часов. В том числе потому что документацию к движку я тогда найти не смог.
Вот такие задачи следовало решить:
- добавить пространство имён yandex в RSS
- сменить описание (<description>) канала на что-то более информативное, чем «Новости по-ростовски / RSS Channel»
- добавить логотип сайта размером «не более 100 пикселей по максимальной стороне».
- добавить в каждую новость элемент <yandex:full-text>, содержащий текст новости без единого HTML-тега.
- заменить элементы <category>, описывающие набор тегов, на один элемент <category>, описывающий рубрику (в нашем случае — блог публикации)
- выпилить все ненужные Яндексу элементы из RSS
- сделать систему фильтрации новостей для Яндекса. У нас сайт гражданской журналистики, который помимо новостей содержит анонсы всяких культурных штук, крики души пользователей, непроверенные сообщения — в общем, всякие штуки, за которые на Яндекс-новостях могут забанить
А такие задачи решить было желательно, но не обязательно:
- добавить картинки и прочие media-элементы из новости в виде элементов <enclosure>
- добавить ссылки по теме новости в виде элемента <yandex:related>
- добавить элемент <author> с именем-фамилией автора сообщения
Проблему фильтрации договорились решить следующим образом — в RSS попадают только посты с главной, помеченные определенным тегом. Чтобы он не мозолил глаз огромным шрифтом в облаке тегов, я отключил его показ в облаке. Это, конечно, костыль, и рано или поздно я эту радость заменю чем-нибудь поприличнее — например, отдельным булевым полем в базе и галочкой «Пустить на Яндекс» у администратора. Или хотя бы выделю в плагин.
Очень не хотелось писать парсер, который бы вылавливал медиа-элементы из новости и добавлял их в RSS как элементы <enclosure>. Тем более, что вообще-то не всякую картинку из статьи стоит добавлять к новости. Зато у нас шаблон simple, который позволяет к каждому посту добавить картинку-preview. Вот её мы и решили запихивать в RSS. На всякий случай я сделал эту функциональность отключаемой.
RSS-лента будет располагаться по адресу /yandex_rss. Полученная в результате RSS-лента была подключена к Яндексу без малейших нареканий.
А вот получившийся код.
/classes/actions/YandexRss.class.php
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
/**
* Делает RSS для Яндекса
* Автор класса vsh, базируется на классе vovazol(http://livestreet.ru/profile/vovazol/)
*
*/
class ActionYandexRss extends Action {
public function Init() {
$this->SetDefaultEvent('index');
Router::SetIsShowStats(false);
}
/**
* Указывает браузеру правильный content type в случае вывода RSS-ленты
*/
protected function InitRss() {
header('Content-Type: application/rss+xml; charset=utf-8');
}
protected function RegisterEvent() {
$this->AddEvent('index','RssYandex');
}
protected function RssYandex() {
$aResult=$this->Topic_GetTopicsGood(1,Config::Get('module.topic.per_page')*2,false);
$aTopics=$aResult['collection'];
$aChannel['title']=Config::Get('view.name');
$aChannel['link']=Config::Get('path.root.web');
$aChannel['description']=htmlspecialchars(Config::Get('yandex_rss.description'));
$aChannel['language']='ru';
$aChannel['managingEditor']=Config::Get('general.rss_editor_mail');
$aChannel['generator']=Config::Get('view.name');
$aChannel['image']=Config::Get('yandex_rss.image');
$bPrintPreview=Config::Get('yandex_rss.print_preview');
$sAllowTag=Config::Get('yandex_rss.allow_tag');
$topics=array();
foreach ($aTopics as $oTopic){
if (in_array($sAllowTag, $oTopic->getTagsArray()))
{
$item['title']=$oTopic->getTitle();
$item['guid']=$oTopic->getUrl();
$item['link']=$oTopic->getUrl();
$item['pubDate']=$oTopic->getDateAdd();
$item['author']=$oTopic->getUser()->getLogin();
$item['yandexFullText']=$this->getYandexFullTopicText($oTopic);
$oBlog=$oTopic->getBlog();
$item['category']=htmlspecialchars($oBlog->getTitle());
if($bPrintPreview)
{
$item['preview'] = $this->getPreviewUrl($oTopic);
}
$topics[]=$item;
}
}
$this->InitRss();
$this->Viewer_Assign('aChannel',$aChannel);
$this->Viewer_Assign('aItems',$topics);
$this->SetTemplateAction('index');
}
/**
* выдирает адрес preview в зависимости от типа топика
* если preview нет, возвращает ''
*
*/
protected function getPreviewUrl($oTopic)
{
if ($oTopic->getType()=='photoset')
{
$oMainPhoto=$oTopic->getPhotosetMainPhoto();
return $oMainPhoto->getWebPath('220crop');
}
else if ($oTopic->getPreviewImage())
{
return $oTopic->getPreviewImageWebPath('220crop');
}
else
{
return '';
}
}
/**
* Формирует текст топика для индексации RSS роботом яндекса
*
*/
protected function getYandexFullTopicText($oTopic) {
$sText=$oTopic->getText();
return htmlspecialchars(strip_tags($sText));
}
}
?>
/templates/skin/ваш темплейт/actions/ActionYandexRss/index.tpl
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:yandex="http://news.yandex.ru" xmlns:media="http://search.yahoo.com/mrss/">
<channel>
<title>{$aChannel.title}</title>
<link>{$aChannel.link}</link>
<description>{$aChannel.description}</description>
<image>
<url>{$aChannel.image}</url>
<title>{$aChannel.title}</title>
<link>{$aChannel.link}</link>
</image>
{foreach from=$aItems item=oItem}
<item>
<title>{$oItem.title|escape:'html'}</title>
<link>{$oItem.link}</link>
<pubDate>{date_format date=$oItem.pubDate format="r"}</pubDate>
<category>{$oItem.category}</category>
<yandex:full-text>{$oItem.yandexFullText}</yandex:full-text>
{if $oItem.preview}
<enclosure url="{$oItem.preview}"/>
{/if}
</item>
{/foreach}
</channel>
</rss>
эти строчки нужно добавить в /config/config.local.php
/**
* Настройка rss для Яндекса
*/
$config['router']['page']['yandex_rss'] = 'ActionYandexRss';
$config['yandex_rss']['description'] ='Очень клёвый новостной сайт';
$config['yandex_rss']['image']='http://путь.к/yandex-logo.png';
$config['yandex_rss']['print_preview']=true; //печатать preview или нет
$config['yandex_rss']['allow_tag']='foobar'; //тег, по которому отбираются топики с главной страницы, регистр важен.
а это костыль в /classes/blocks/BlockTags.class.php
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
/**
* Обрабатывает блок облака тегов
*
*/
class BlockTags extends Block {
public function Exec() {
/**
* Получаем список тегов
*/
$aTags=$this->oEngine->Topic_GetOpenTopicTags(70);
/* фильруем тег для яндекс-новостей */
function FilterYandexTag($oTag)
{
$sAllowTag=Config::Get('yandex_rss.allow_tag');
return $oTag->getText() != $sAllowTag;
}
$aTags=array_filter($aTags, "FilterYandexTag");
/**
* Расчитываем логарифмическое облако тегов
*/
if ($aTags) {
$iMinSize=1; // минимальный размер шрифта
$iMaxSize=10; // максимальный размер шрифта
$iSizeRange=$iMaxSize-$iMinSize;
$iMin=10000;
$iMax=0;
foreach ($aTags as $oTag) {
if ($iMax<$oTag->getCount()) {
$iMax=$oTag->getCount();
}
if ($iMin>$oTag->getCount()) {
$iMin=$oTag->getCount();
}
}
$iMinCount=log($iMin+1);
$iMaxCount=log($iMax+1);
$iCountRange=$iMaxCount-$iMinCount;
if ($iCountRange==0) {
$iCountRange=1;
}
foreach ($aTags as $oTag) {
$iTagSize=$iMinSize+(log($oTag->getCount()+1)-$iMinCount)*($iSizeRange/$iCountRange);
$oTag->setSize(round($iTagSize)); // результирующий размер шрифта для тега
}
/**
* Устанавливаем шаблон вывода
*/
$this->Viewer_Assign("aTags",$aTags);
}
}
}
?>
16 комментариев
Буквально на днях делал тоже самое для своего проекта, чтобы стало человечнее в частности аватарка пользователя в фиде и «о себе» из профиля в дискрипшн фида, тоже самое для коллективного блога — сделал проще картинка собирается в одну строку (на самом деле не так, но чтоб стало понятнее) и если у пользователя нет аватара то ничего не выводится (в шаблоне фида $aChannel.image пустая сторка)
Конечно, для того, чтобы попасть в яндекс.новости, мы сделали не только rss-ленту, а списывались с сотрудниками яндекса, те одобряли сайт, потом я посылала письмо и факс со своими данными в компанию Яндекс на имя его гендира… Но это другая история.
по москве и питеру попасть в топ последние 2-3 года уже не реально.
Пожалуйста, подскажите, как оно должно выглядеть?
Подскажите, пож, с чем может быть связано и как поправить? Версия 0.4.2
Подскажите, пож., как поправить!
Заранее благодарю.