10 способов изменить RSS ленту в WordPress
RSS-лента сайта (фид сайта) дает возможность пользователям следить за появлением новых материалов на вашем блоге. Для этого пользователи подписываются на ваш блог через какой-либо обработчик RSS и получают новые материалы с вашего блога в своей RSS-ленте. Иногда для удобства или по другим причинам, нужно изменить вывод постов в фиде. Например, добавить в ленту записи произвольных типов, добавить картинки к постам и т.д.
В этой статье я приведу примеры, демонстрирующие как изменять вывод фидов в WordPress. Все нижеприведенные хуки следует размещать в файл темы functions.php или создавать из них отдельный плагин. Код плагина будет выглядеть так:
<?php /* Plugin Name: Мой вывод RSS-ленты сайта Description: Изменяет вывод постов в RSS-ленте. */ // Здесь код ...
-
Про фиды читайте: Все о фидах в WordPress
- Также про получение фидов читайте в описании функции fetch_feed()
Включение произвольных типов записей в 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' ); } );
—
Хуки, использованные в примерах:
-
pre_get_posts - позволяет внедрится в запрос, до фактического запроса к базе данных и изменить его параметры;
-
the_excerpt_rss - фильтрует контент короткого описания передаваемого в фид;
-
the_content_feed - фильтрует контент поста после того, как он получен из базы данных и обработан фильтром the_content;
-
posts_where - изменяет WHERE часть SQL запроса;
- post_limits - изменяет LIMIT часть SQL запроса перед тем, как получить посты из базы данных.