eurobyte.ru - мощные сервера с Дата-центрами в Нидерландах и Москве. От 159 ₽/мес.

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

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

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

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

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

Включение произвольных типов записей в 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" в массив: [ '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, [100, 80], [ 'align' => 'left', 'style' => 'margin-right:15px;' ] );
	$content =  $img . $content;

	return $content;
}

Для получения миниатюры используется функция get_the_post_thumbnail(), во втором аргументе которой указан размер получаемой картинки (100х80), а в третьем - атрибут тега - 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', [ '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', [ 451 ] );
}

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

[ 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, [ 'fields' => 'ids' ] );

	// если есть метки, получаем связанные
	if( $tag_ids ){
		$out = '';
		$args = array(
			'posts_per_page' => 3,
			'tag__in'        => $tag_ids,
			'post__not_in'   => [ $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', function( $n ){ return "LIMIT $n"; } );
}

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

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

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

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

	if( $query->is_feed && $query->is_main_query() && ! $GLOBALS['wp_query']->is_comment_feed ){
		$query->set( 'date_query', [
			'before' => '12 hour ago', // получить посты опубликованные 12 часов назад
		]);
	}
}

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

Все ссылки фидов перестанут работать, будут возвращать 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 запроса перед тем, как получить посты из базы данных.
22 комментария
Вопросы - 2 Все
    Войти