Customizing WordPress RSS Feed with Code: The Easy Way

Is RSS dead? That was the question that I was asking myself when I decided to write this post. Veteran users of the internet are probably familiar with Google Reader. The golden days of RSS were those days that everyone was aggregating their beloved website feeds using apps such as Google Reader and had everything in one place. Many still believe that Google’s most successful attempt to run a social network was Google Reader, although it went offline in 2013. But with the  shutting down of feed aggregators such as GReader, is RSS dead? Not exactly. RSS is still alive; however, it is being used less than before. You may still find apps and websites that allow you to aggregate RSS feeds in one place and have your beloved blogs in your pocket, but they are more useful than you might think.

Honestly, the reason that I was encouraged to write this post is that one of our clients wanted to modify the RSS feed of their website to be able to connect it to an app that was pulling their events data from one of the custom post types created on their WordPress website. But, instead of the event date, it was pulling the post publish date. He asked this question at the support desk and I thought it was a really interesting question. After searching around a little bit, I decided to share what I knew about customizing the WordPress RSS feed in this article. Let’s take a closer look.

What is a feed and what types of feed does WordPress support?

Based on what Wikipedia says: A web feed (or news feed) is a data format used for providing users with frequently updated content in raw format. Simply put, it allows users to see a website’s updated content without visuals. Common web feed formats are ATOM, RSS and JSON. RSS and ATOM are presented in XML format.

RSS or Really Simple Syndication is a web feed that allows users and applications to access updates to websites in XML format. Subscribing to RSS feeds can allow a user to keep track of many different websites in a single news aggregator app or website and removes the need for users to manually check them. 

WordPress supports both ATOM and RSS and RDF feeds by default. Using this doc, you can get the default WordPress feeds link like this:

For RSS 2.0 feed:

<?php bloginfo('rss2_url'); ?>

And for ATOM feed:

<?php bloginfo('atom_url'); ?>
customizing WordPress RSS feed
Example of a RSS 2.0 feed, default web feed of WordPress

What are the use cases for RSS feeds?

Most of the time, RSS feeds are used in news aggregators such as Feedly or Inoreader. They simply allow you to compile all the websites you love in one place. This is particularly useful if you are a geek, author, stock trader or bibliophile. More than that, if you want to show another website feed somewhere on your website, you can simply use a feed reader widget on it.

Earlier I mentioned that one of our clients wanted to show their Event post type feed in an app. They created the Event post type using the bundled plugin Jet Engine and the Jupiter X theme to easily add their meta field, but they needed the date field to show instead of the publish date of the post. This is probably a popular topic out there for those who want to showcase events on their Mailchimp RSS campaigns (to be able to send event dates through the newsletters once the event is published)! 

There are many more use cases than what I’ve written about here for sure, but it’s enough to show the importance of RSS feed customization methods.

How to modify feed content using WordPress actions and filters

I’m going to show you how you can modify feed content using WordPress actions and filters. But wait a minute… if it’s possible, why not just use third party plugins to modify the feed content? Customizing the WordPress RSS feed using a plugin is quite simple—just search for RSS in the WordPress plugin repository to find a good RSS editor plugin. However, you may find it time consuming to find a plugin that is capable of doing what you want, learning how to use it and then customizing it to fit your needs. It would be simpler to dig into the code yourself and start customizing the WordPress RSS feed the way you want. Fortunately, WordPress has good documentation explaining Feed Customization. You can find it here.

By default, if you add /feed/ or /rss/ to the end of your website URL, you can see the feed entry in XML format. You can use a more specific URL to filter the content on the feed. For example, if you add the “post_type” parameter to the end of your RSS feed address, you will limit the posts to your custom post type. Below you can see some examples of how WordPress targets RSS feeds:

http://www.example.com/?cat=-123&feed=rss2     //exclude category with ID 123 from the RSS feed
http://www.example.com/category/cat1+cat2/feed //show the RSS feed of cat1 and cat2 posts
http://www.example.com/tag/tag1+tag2/feed         //show the RSS feed of posts having tag1 and tag2
http://www.example.com/category/cat1,cat2/feed  //show the RSS feed of cat1 or cat2 posts
http://example.com/author/authorname/feed/         //show the RSS feed of posts that have written by authorname
http://example.com/?s=searchterm&feed=rss2     //show the RSS feed of searchterm
http://www.example.com/feed/?post_type=event   //show the RSS feed of post type "event"

You can also use a combination of the parameters above to provide a specific feed output. However, in the following example I’m going to show you a way to build a specific feed to fit your needs.

By default, the RSS feed only shows the posts categorized under the “post” type. If you want to include other posts from different post types on the feed, you need to add this to your child theme’s functions.php file. The example below will add the “event” post type to the default RSS feed output.

function myfeed_request( $qv ) {
      if ( isset( $qv['feed'] ) && !isset( $qv['post_type'] ) ) {
            $qv['post_type'] = array( 'post', 'event' );
     }
     return $qv;
}
add_filter( 'request', 'myfeed_request' );

One important part of coding for RSS is that you need to hard refresh the browser after each update–otherwise you won’t be able to see your change. I fell into this trap for an hour or more and, after making sure the code was working fine, tried incognito mode and realized I couldn’t see my changes because of the browser caching. Hit CTRL+F5 or CMD+SHIFT+R to hard refresh your feed’s page and see the changes. 

As an example, I created an “event” post type using Jet Engine (a bundled plugin with the Jupiter X theme) and added an “event-date” meta field into it. The event-date receives the data in text, but the field will display a date-time picker like the one below. 

customizing WordPress RSS feed
Adding an event with a proper event date

After publishing this post, I can’t see it among my default RSS feeds. However, if I add the above code to my child theme’s functions.php file, the RSS feed will display this post as well.

customizing WordPress RSS feed
Custom post type “event” showing up in the default RSS feed.

In the above feed, I can see that the pubDate field is set to the date that I published the post, and not the event-date time that I chose in the meta fields:

<pubDate>Thu, 11 Nov 2021 18:04:34 +0000</pubDate>

If I want to add a new field to each item and not touch the <pubDate> field, I would use this code:

function add_custom_fields_to_rss() {
    if(get_post_type() == 'event' && $my_meta_value = get_post_meta(get_the_ID(), 'event-date', true)) {
        ?>
        <event-date><?php echo $my_meta_value ?></event-date>
        <?php
    }
}

add_action('rss2_item', 'add_custom_fields_to_rss');

This will add  <event-date>DATETIME</event-date> to each item, if its post type is “event”.

customizing WordPress RSS feed
Add a new field to each item in the RSS feed

But if I want to modify the <pubDate> field directly, I can use this code:

add_filter( 'get_post_time', 'return_event_date_rss_2_feed_func', 10, 3 ); 

function return_event_date_rss_2_feed_func( $time, $d, $gmt )
{
    if( did_action( 'rss2_head' ) )
    {
    	 if(get_post_type() == 'event' && $my_meta_value = get_post_meta(get_the_ID(), 'event-date', true)) {
    	 	 $time = $my_meta_value;
    	 }
      
    }
       
    return $time;
}

The result would look like this:

Modifying the <pubDate> value in the RSS feed for custom post type “event”

If you want to do the same for the ATOM feed, you need to add this as well:

add_filter( 'get_post_time',          'return_event_date_atom_feed_func', 10, 3 ); 
add_filter( 'get_post_modified_time', 'return_event_date_atom_feed_func', 10, 3 ); 

function return_event_date_atom_feed_func( $time, $d, $gmt )
{
    if( did_action( 'atom_head' ) )
         if(get_post_type() == 'event' && $my_meta_value = get_post_meta(get_the_ID(), 'event-date', true)) {
    	 	 $time = $my_meta_value;
    	 }
    return $time;
}

You can modify the post content, post title or post excerpts with regular WordPress actions. You just need to check if you are modifying them through the RSS or not or use the filters that are specifically designed for RSS feeds.

Adding the featured image to RSS feed items is possible with this code:

function add_image_to_rss($content) {
	global $post;
	if(has_post_thumbnail($post->ID)) {
		$content = '<p>' . get_the_post_thumbnail($post->ID) .
		'</p>' . get_the_content();
	}
	return $content;
}
add_filter('the_excerpt_rss', 'add_image_to_rss');
add_filter('the_content_feed', 'add_image_to_rss');
Inserting the featured image to the RSS feed

I highly recommend that you follow this article to get to know which actions you can use to modify your website’s RSS feed. 

So far, we understand that there are actions and filters we can use to customize the feed output. However, sometimes we need to do more than this. I personally like the idea of having an exclusive feed populated from my own feed template. The good thing about this is that WordPress allows you to have custom feeds even with a custom template. Let’s see an example of this approach. I will add a new feed to my website and will use my own template to render the RSS content. This feed will have a separate URL and would be useful when I want to use it as an app or widget that is exclusively developed and requires specific data. First I will use the default RSS feed template copied from wp-includes/feed-rss2.php, which is the default RSS template of WordPress, and then modify the template as I wish. Then I’ll copy every single line of it into the function customRSSFunc().

add_action('init', 'customRSS');
function customRSS(){
    add_feed('custom-event', 'customRSSFunc');
}

function customRSSFunc(){

/**
 * RSS2 Feed Template for displaying RSS2 Posts feed.
 *
 * @package WordPress
 */

header( 'Content-Type: ' . feed_content_type( 'rss2' ) . '; charset=' . get_option( 'blog_charset' ), true );
$more = 1;

echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>';

/**
 * Fires between the xml and rss tags in a feed.
 *
 * @since 4.0.0
 *
 * @param string $context Type of feed. Possible values include 'rss2', 'rss2-comments',
 *                        'rdf', 'atom', and 'atom-comments'.
 */
do_action( 'rss_tag_pre', 'rss2' );
?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	<?php
	/**
	 * Fires at the end of the RSS root to add namespaces.
	 *
	 * @since 2.0.0
	 */
	do_action( 'rss2_ns' );
	?>
>

<channel>
	<title><?php wp_title_rss(); ?></title>
	<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
	<link><?php bloginfo_rss( 'url' ); ?></link>
	<description><?php bloginfo_rss( 'description' ); ?></description>
	<lastBuildDate><?php echo get_feed_build_date( 'r' ); ?></lastBuildDate>
	<language><?php bloginfo_rss( 'language' ); ?></language>
	<sy:updatePeriod>
	<?php
		$duration = 'hourly';

		/**
		 * Filters how often to update the RSS feed.
		 *
		 * @since 2.1.0
		 *
		 * @param string $duration The update period. Accepts 'hourly', 'daily', 'weekly', 'monthly',
		 *                         'yearly'. Default 'hourly'.
		 */
		echo apply_filters( 'rss_update_period', $duration );
	?>
	</sy:updatePeriod>
	<sy:updateFrequency>
	<?php
		$frequency = '1';

		/**
		 * Filters the RSS update frequency.
		 *
		 * @since 2.1.0
		 *
		 * @param string $frequency An integer passed as a string representing the frequency
		 *                          of RSS updates within the update period. Default '1'.
		 */
		echo apply_filters( 'rss_update_frequency', $frequency );
	?>
	</sy:updateFrequency>
	<?php
	/**
	 * Fires at the end of the RSS2 Feed Header.
	 *
	 * @since 2.0.0
	 */
	do_action( 'rss2_head' );

	while ( have_posts() ) :
		the_post();
		?>
	<item>
		<title><?php the_title_rss(); ?></title>
		<link><?php the_permalink_rss(); ?></link>
		<?php if ( get_comments_number() || comments_open() ) : ?>
			<comments><?php comments_link_feed(); ?></comments>
		<?php endif; ?>

		<dc:creator><![CDATA[<?php the_author(); ?>]]></dc:creator>
		<pubDate><?php echo  get_post_meta(get_the_ID(), 'test_meta_field', true); // mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
		<?php the_category_rss( 'rss2' ); ?>
		<guid isPermaLink="false"><?php the_guid(); ?></guid>

		<?php if ( get_option( 'rss_use_excerpt' ) ) : ?>
			<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
		<?php else : ?>
			<description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
			<?php $content = get_the_content_feed( 'rss2' ); ?>
			<?php if ( strlen( $content ) > 0 ) : ?>
				<content:encoded><![CDATA[<?php echo $content; ?>]]></content:encoded>
			<?php else : ?>
				<content:encoded><![CDATA[<?php the_excerpt_rss(); ?>]]></content:encoded>
			<?php endif; ?>
		<?php endif; ?>

		<?php if ( get_comments_number() || comments_open() ) : ?>
			<wfw:commentRss><?php echo esc_url( get_post_comments_feed_link( null, 'rss2' ) ); ?></wfw:commentRss>
			<slash:comments><?php echo get_comments_number(); ?></slash:comments>
		<?php endif; ?>

		<?php rss_enclosure(); ?>

		<?php
		/**
		 * Fires at the end of each RSS2 feed item.
		 *
		 * @since 2.0.0
		 */
		do_action( 'rss2_item' );
		?>
	</item>
	<?php endwhile; ?>
</channel>
</rss>



<?php 
}

This code requires you to save your permalinks in Settings -> Permalinks once, otherwise you will see a 404 error if you open the feed URL. 

Custom field, outputs the feed template.

The good thing about this approach is that you won’t have any limitations on modifying the RSS output. That’s why I like it the most. Now I can modify the template in customRSSFunc() or move it to a template file on my child theme and call it via template_parts() function to organize the code.

That’s it, guys–customizing the WordPress RSS feed using code is not that complicated! Let me know your thoughts about it and ask your questions below if you have any. 

Recommended Posts

No comment yet, add your voice below!


Add a Comment

Your email address will not be published. Required fields are marked *