WordPress как на ладони
wordpress jino

10 способов изменить RSS ленту в WordPress

RSS-лента сайта (фид сайта) дает возможность пользователям следить за появлением новых материалов на вашем блоге. Для этого пользователи подписываются на ваш блог через какой-либо обработчик RSS и получают новые материалы с вашего блога в своей RSS-ленте. Иногда для удобства или по другим причинам, нужно изменить вывод постов в фиде. Например, добавить в ленту записи произвольных типов, добавить  картинки к постам и т.д.

В этой статье я приведу примеры, демонстрирующие как изменять вывод фидов в WordPress. Все нижеприведенные хуки следует размещать в файл темы functions.php или создавать из них отдельный плагин. Код плагина будет выглядеть так:

<?php
/*
Plugin Name: Мой вывод RSS-ленты сайта
Description: Изменяет вывод постов в RSS-ленте.
*/

// Здесь код ...

Про фиды читайте здесь: все виды фидов в WordPress

Включение произвольных типов записей в RSS-ленту

Допустим, при помощи register_post_type(), мы создали новый тип записи book и хотели бы, чтобы записи этого типа, на ровне с постами (post), попадали в RSS-ленту. Сделать это можно так:

add_filter('pre_get_posts', 'add_new_post_types_to_feed');
function add_new_post_types_to_feed( $query ) {
	// Выходим если это запрос не фидов
	if( ! $query->is_feed || ! $query->is_main_query() )
		return;

	$query->set( 'post_type', array('post', 'book') );  
}

Если, нужно включить еще и постоянные страницы (page), то добавьте "page" в массив: array('post', 'book', 'page').

Добавление миниатюры поста в RSS-ленту

Подключимся к хуку the_excerpt_rss, который срабатывает для короткого описания поста в фиде и добавим в него миниатюру поста:

add_filter( 'the_excerpt_rss', 'add_thumbnail_to_feed' );
add_filter( 'the_content_feed', 'add_thumbnail_to_feed' ); // обычно этот хук не используется, но тоже может быть...
function add_thumbnail_to_feed( $content ){
	$img = get_the_post_thumbnail( null, array(100, 80), array( 'align' => 'left', 'style' => 'margin-right:15px;' ) );
	$content =  $img . $content;

	return $content;
}

Для получения миниатюры используется функция get_the_post_thumbnail(), во втором аргументе которой указан размер получаемой картинки (100х80), а в третьем - атрибут тега <img> - align="left". Некоторые обработчики RSS-лент вырезают встроенные CSS правила (style=''), поэтому лучше использовать align="left", когда нужно расположить картинку слева.

Указанный размер (100x80), не реальный, это не копия оригинала картинки с нужными нам размерами: подбирается наиболее подходящая по размеру картинка и визуально уменьшается под указанные размеры. Иногда лучше создать специальный формат картинок-миниатюр для RSS-лент. Для этого вам нужно будет зарегистрировать новый формат миниатюр для вашей темы, так:

if ( function_exists( 'add_image_size' ) ) {
	// Формат миниатюр для фидов
	add_image_size( 'feed', 100, 80 );
}

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

После добавки такого кода в functions.php или плагин, миниатюру можно получить с указанием размера feed:

$img = get_the_post_thumbnail( null, 'feed', array( 'align' => 'left' ) );

Если нужно изменить выводимый контент, а не короткое описание, то используйте хук the_content_rss.

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

Исключение из фида постов с меткой

Если нужно, чтобы в RSS-ленту не попадали посты имеющие, допустим, метку ID которой равен 451, то используйте такой код:

add_filter( 'pre_get_posts', 'exclude_posts_from_feed_by_tag_id' );
function exclude_posts_from_feed_by_tag_id( $query ) {
	if( ! $query->is_feed || ! $query->is_main_query() )
		return;

	$query->set( 'tag__not_in', array(451) );
}

Если нужно исключить посты имеющие любую из указанных меток, то укажите ID всех меток в массиве:

array(29, 31, 124)

Исключение рубрик из RSS-ленты

Чтобы исключить ненужные рубрики из фида, пусть это будут рубрики с ID 6 и 4, используйте такой код:

add_filter( 'pre_get_posts', 'exclude_cats_from_feed' );
function exclude_cats_from_feed( $query ){
	if( ! $query->is_feed || ! $query->is_main_query() )
		return;

	$query->set( 'cat', '-6,-4' ); 
}

Исключение дерева рубрики из RSS-ленты

Если нужно исключить посты из рубрики и всех её подрубрик, мы можем использовать предыдущий пример и указать ID рубрики и всех подрубрик вручную. Однако это не удобно ведь, если мы добавим в эту рубрику новую подрубрику, нам придется добавлять ID этой продрубрики в код, иначе посты из нее попадут в ленту, а нам этого не надо.

Чтобы исключить посты из рубрики и автоматически из всех её подрубрик, используйте следующий код, где нужно указать только ID родительской рубрики, а ID всех подрубрик будут получены автоматически:

add_filter( 'pre_get_posts', 'exclude_cat_tree_from_feed' );
function exclude_cat_tree_from_feed( $query ){
	if( ! $query->is_feed || ! $query->is_main_query() )
		return;

	// ID категории, дерево которой нужно исключить
	$cat = 4;

	$subcats = get_categories( "child_of=$cat" );

	$subcat_string = '';
	foreach( $subcats as $subcat) {
		$subcat_string .= '-' . $subcat->cat_ID . ',';
	}
	$subcat_string .= "-$cat";

	$query->set( 'cat', $subcat_string ); 
}

Исключение из фида постов имеющих произвольно поле

Предположим, нам нужно исключить из RSS-ленты случайные посты: не зависящие от метки, рубрики или другой таксономии. Тогда, мы может добавлять к таким постам, произвольное поле exclude_from_feed с любым значением (пусть 1) и использовать код, который исключит из RSS-ленты все посты имеющие произвольное поле exclude_from_feed:

add_filter( 'posts_where', 'exclude_special_posts_from_feed' );
function exclude_special_posts_from_feed($where){
	// Выходим если это не фид.
	if( ! is_feed() || ! is_main_query() )
		return $where;

	global $wpdb;

	$where .= " AND $wpdb->posts.ID NOT IN ( 
						SELECT distinct(post_id) from $wpdb->postmeta 
						where $wpdb->postmeta.meta_key = 'exclude_from_feed'
						) ";

	return $where;
}

Тут, в отличии от предыдущих примеров, мы использовали хук-фильтр posts_where, который срабатывает каждый раз при запросе.

Вывод в ленте постов только из указанных рубрик

В случаях, когда нужно вывести в фиде посты только из одной рубрики можно использовать такой код:

add_filter( 'pre_get_posts', 'my_categories_for_feed' );
function my_categories_for_feed( $query ){
	if( ! $query->is_feed || ! $query->is_main_query() )
		return;

	$query->set( 'category_name', 'life' ); 
}

Для вывода постов из нескольких рубрик, укажите их названия (слаги) через запятую:

$query->set( 'category_name', 'life,love' );

Также можно указать ID рубрик, через запятую:

$query->set( 'cat', '2,6,17,38' );

Добавляем ссылку на источник в конец каждого поста в RSS-ленте

Может быть куча причин, по которым нужно добавить какую-либо строку в конец каждого поста в RSS-ленте. Допустим, вы хотите сохранить копирайты вашего сайта, для постов в фиде, добавив в конец каждого поста строку: "Источник: Название сайта (ссылка на сайт)":

add_filter( 'the_excerpt_rss', 'add_text_to_the_feed_end' );
function add_text_to_the_feed_end( $content ){
	$content .= '
	<p>
		Источник: <a href="'. get_bloginfo('url') .'">'. get_bloginfo('name') .'</a>.
	</p>
	';

	return $content;
}

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

Связанные по меткам записи в конце каждого поста в RSS-ленте

Развивая мысль добавочного контента к постам в RSS-ленте, можно например, в конец каждого поста добавить ссылки на записи с одинаковой меткой. То есть, скажем, у поста есть метка "жизнь" в ленте в конец этого поста будут добавлены другие посты с меткой "жизнь":

add_filter( 'the_excerpt_rss', 'related_tag_posts_to_feed_end' );
add_filter( 'the_content_feed', 'related_tag_posts_to_feed_end' );
function related_tag_posts_to_feed_end( $content ){ 
	global $post;

	// во второй раз отдаем кэш
	$cache_key = __FUNCTION__ . $post->ID;
	if( $cache = wp_cache_get( $cache_key ) )
		return $content . $cache;

	// получаем метки
	$tag_ids = wp_get_post_tags( $post->ID, array( 'fields' => 'ids' ) );

	// если есть метки, получаем связанные
	if( $tag_ids ){
		$out = '';
		$args = array( 
			'posts_per_page' => 3, 
			'tag__in' => $tag_ids,
			'post__not_in' => array($post->ID)
		);
		$posts = get_posts( $args );
		if( $posts ){
			foreach( $posts as $p ){
				$out .= '<li>'. get_permalink($p->ID) . " </li>";
			}
			$out = make_clickable( $out );
			$content .= '<p>Читайте также: <ul>'. $out .'</ul></p>';
		}
	}

	// кэшируем
	wp_cache_set( $cache_key, $out );

	return $content;
}

Регулируем количество записей выводимых в RSS-ленте

Обычно количество записей отображаемых в RSS-ленте можно установить в настройках: Параметры > Чтение > В RSS-лентах отображать последние. Однако, если вам нужно изменить количество записей через плагин или в любых других случаях, когда не подходит стандартное изменение в настройках, то используйте такой код:

add_filter( 'pre_get_posts', 'how_many_posts_display_in_feed' );
function how_many_posts_display_in_feed($query) {
	if( ! $query->is_feed || ! $query->is_main_query() )
		return;

	// этот вариант не работает
	// $query->set( 'posts_per_page', 11 );

	// Сколько записей показывать
	$n = 7;
	add_filter( 'post_limits', create_function('', "return 'LIMIT $n';") );
}

Тут, мы использовали фильтр post_limits, который позволяет внедрится в SQL запрос и изменить количество получаемых строк запроса (LIMIT 7), в нашем случае, количество записей.

Задержка перед публикацией записи в RSS фид

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

## Задержка перед публикацией записи в RSS фид
add_filter('posts_where', 'publish_later_on_feed');
function publish_later_on_feed( $where ){
	global $wpdb;

	if( is_feed() ){
		$now = gmdate('Y-m-d H:i:s'); // MYSQL формат текущего времени

		$wait = '10'; // сколько ждать?

		// http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_timestampdiff
		$device = 'MINUTE'; // MINUTE, HOUR, DAY, WEEK, MONTH, YEAR

		// SQL-синтаксис
		$where .= " AND TIMESTAMPDIFF( $device, $wpdb->posts.post_date_gmt, '$now') > $wait ";
	}

	return $where;
}

Этот пример не тестировал. Если кто проверил, черкните в комментах все ли работает.

Удаление всех фидов из правил преезаписи, кроме фида на главной станице

Все ссылки фидов перестанут работать, будут возвращать 404 ошибку, кроме фида на главной странице:

## удаляет все правила перезаписи фидов, кроме фида на главной странице.
is_admin() && add_filter( 'rewrite_rules_array', 'delete_all_feed_rewrites_rules' );
function delete_all_feed_rewrites_rules( $rules ){

	foreach( $rules as $rule => $val ){
		if(
			strpos($rule, 'feed/(')
			|| ( strpos($rule, '/(feed') && 0 !== strpos($rule, 'feed/(feed') )
		)
			unset( $rules[ $rule ] );
	}

	return $rules;
}

После установки кода, нужно сбросить правила перезаписи в настройках ЧПУ...

Вместе с этим кодом, также нужно удалить ссылки на фиды из wp_head, возможно для главной страницы такие ссылки нужно оставить:

add_action( 'wp', function(){
	if( is_front_page() ) return;

	remove_action( 'wp_head', 'feed_links_extra', 3 );
	remove_action( 'wp_head', 'feed_links', 2 );
	remove_action( 'wp_head', 'rsd_link' );

});

Хуки, использованные в примерах:

  1. pre_get_posts - позволяет внедрится в запрос, до фактического запроса к базе данных и изменить его параметры;

  2. the_excerpt_rss - фильтрует контент короткого описания передаваемого в фид;

  3. the_content_feed - фильтрует контент поста после того, как он получен из базы данных и обработан фильтром the_content;

  4. posts_where - изменяет WHERE часть SQL запроса;

  5. post_limits - изменяет LIMIT часть SQL запроса перед тем, как получить посты из базы данных.
10 способов изменить RSS ленту в WordPress 19 комментариев
Вопросы 2 Все
  • Otshelnik-Fm185 cайт: otshelnik-fm.ru

    А я сделал так:
    Понадобилось мне одну страницу отдавать в фид (на ней новости). Создаю отдельную страницу Custom Feed в админке, а в шаблон пишу нужный мне цикл вывода записей (обновленные записи, новые записи). Оформляю всё это в стандарте rss2 (опустил вывод самого цикла - тут только принцип)

    header("Content-Type: application/rss+xml; charset=UTF-8");
    echo '<?xml version="1.0"?>';
    <rss version="2.0">
    <channel>
    	<title>Приют Отшельника</title>
    	<link>мой сайт</link>
    	<description></description>
    	<language>ru</language>
    	<pubDate>дата формирования</pubDate>
    	<lastBuildDate></lastBuildDate>
    		<item>
    			<title></title>
    			<link></link>
    			<description></description>
    			<pubDate></pubDate>
    			<guid></guid>
    		</item>
    </channel>
    </rss>

    Публикую страницу и скармливаю страницу в сервис автопостинга в твиттер.

    Ответить3.8 года назад #
  • adward5 cайт: cimetrica.ru

    я использую RSS для того, чтобы отправлять новые посты в vk.com, fb.com, ok.ru и в твиттер. И при этом мне актуально, чтобы вместе с постом в RSS транслировалась ещё и миниатюра в full - размере (соцсети сами подгонят под свои размеры).

    в functiond.php включаю вот такой код:

    function featuredtoRSS($content) {
    	global $post;
    	if ( has_post_thumbnail( $post->ID ) ){
    		$content = '' . get_the_post_thumbnail( $post->ID, 'full' ) . '' . $content;
    	}
    	return $content;
    }
    add_filter('the_excerpt_rss', 'featuredtoRSS');
    add_filter('the_content_feed', 'featuredtoRSS');

    Однако же столкнулся вот с такой проблемкой.

    Если в пост встроен фотоальбом - то естественно, то изображения тоже транслируются (и это есть хорошо), но транслируются именно миниатюры (что не есть гуд). Вот явный пример: пост вконтакте. (Оригинал поста)

    Отсюда вопрос, на который я не смог найти ответ:

    Если в пост встроен фотоальбом, то в случае с RSS? как транслировать не миниатюры этого альбома, а full-размер картинок?

    Спасибо.

    1
    Ответить3.8 года назад #
    • Kama4696

      Думаю, тут можно обрабатывать текст через preg_replace, где проверять если картинка это анкор ссылки, то заменять УРЛ картинки УРЛом ссылки... Подробнее не подскажу.

      Ответить3.8 года назад #
  • igor cайт: viktorijatravel.lv

    А нет плагина которые делает всё это?
    Ведь если я придут обновление темы, то все эти хуки слетят.

    Ответить3.6 года назад #
    • Kama4696

      Плагины для редактирования выдачи RSS ленты есть. Названия к сожалению не подскажу. Поищите в сети.

      Ответить3.6 года назад #
  • Manfred cайт: privatcat.com

    Привет,
    отличная подборка спасибо. Столкнулся с одной проблемой при добавлении функции : Добавляем ссылку на источник в конец каждого поста в RSS-ленте

    Сайт слёг с ошибкой

    Fatal error: Cannot redeclare add_text_to_the_feed_end() (previously declared in /home/vhosts/

    что то там не так Kama

    Ответить3.5 года назад #
    • Kama4696

      Функция add_text_to_the_feed_end() два раза определяется. У меня в статье она два раза используется. Сейчас поправлю.

      Ответить3.5 года назад #
  • Алексей

    У меня почему то выводится пару слов в rss и все... Как это исправить? Вообще в PHP немного шарю, но где искать я не знаю.... http://ws-life.ru/feed

    Ответить3 года назад #
    • Алексей

      Что, никто не поможет??? Для меня это серьезная проблема...

      Ответить3 года назад #
    • Kama4696

      Возможно какой-то плагин меняет вывод RSS, попробуйте поотключать плагины, отключите при проверке плагин кэширвоания у вас hyper cache стоит. Вспомните что вы делали с RSS, может коды какие-то вставляли. Вам нужно, чтобы стандартный RSS выводился, что нужно? Чтобы вам помочь нужно хоть на что-то опирется, а из вашего вопроса не понятно ничего, ясно только что RSS кривой, причин десятки могут быть...

      Ответить3 года назад #
      • Алексей

        Я в rss вообще не шарю. Так в общих чертах. Мне нужно, чтобы был анонс статей и все. На счет плагинов не знаю. У меня и до плагинов в rss плохо дело было. Плагины отключать пробовал, не помогает. С кодом ничего не делал, в functions.php искал зацепки - нет. На счет плагина кеширования, он что может как то влиять???

        Ответить3 года назад #
        • Kama4696

          Плагин кэширования может влиять на проверку мгновенных изменений. Допустим вы удалил плагин из-за которого проблемы, проверили, а проблема осталась потому что кэш... И вывод - этот плагин невиновен, хотя он виновен... Только так может влиять плагин кэширования. Кроме того, RSS кэшируется в самом WordPress, поэтом после каждого изменения желательно как-то убедиться что RSS отдается свежий.

          Вам нужно найти проблему. ПО умолчанию в WordPress все нормально с RSS - это факт! Отсюда: попробуйте временно сменить тему, на любую, и проверьте вывод RSS. Если опять также, то виноват плагин. Отключайте плагины по одному. Если ничего не помогает, но загляните в папку wp-contents/mu-plugins (её может не быть), там тоже могут располагаться плагины.

          В последнюю очередь, зайдите в phpMyAdmin и сделайте поиск в таблице wp_options по полю option_name ищите %rss%:

          SELECT *  FROM `wp_options` WHERE `option_name` LIKE '%rss%'

          Возможно у вас RSS лежит в кэше базы данных. Такое бывает, в каких случаях точно я не знаю, но помню встречался с таким...

          В общем, найдите проблемное место, потом пишите, я помогу решить её, если сами не сможете. За вас проблему никто искать не будет, ну или почти никто, для этого нужны доступы и свободное время и желание помоч, ну или оплата за работу...

          Удачи в поисках!

          Ответить3 года назад #
          • Алексей

            В общем пробежался глазками по всему шаблону, нашел!

            function new_excerpt_length($length) { return 60; }
            	add_filter('excerpt_length', 'new_excerpt_length');

            Вместо 60, стояла 5. Какой я не внимательный оказывается.... Печальбеда sorry

            Ответить3 года назад #
  • Александр

    Огромное спасибо за способ: "Включение произвольных типов записей в RSS-ленту" Ну оочень помогли! smile

  • aliprofi @

    А как изменить адрес фида, но без редиректа, чтобы скрыть от парсеров и спамеров, но открыть для кросспостинга?

  • Доброго времени суток!
    Подскажите пожалуйста есть ли способ вставки в РСС не картинки, а видео?

  • Валерий

    Похоже, что "Исключение из фида постов с меткой" не работает. Я вводил ID поста, добавлял к записи поста тег с аналогичным именем, но пост никуда из RSS не исчезал sad

    1
    Ответить6 дней назад #

Здравствуйте, !

Ваш комментарий
Предпросмотр