How to add XML elements to your WordPress RSS feed

A while back, I shared a little way of customising the individual title of each item in your WordPress feed. That was based on filtering the existing title, and prepending the requisite content, which in that example was the post type (Gallery, Video, etc.).

I’m now using a variant of that same technique in The Stage’s new RSS feeds. News, Features, and Columns and their respective subcategories are all implemented using WordPress’s built-in categories system. The relevant category (News, Arts 2.0, Obituaries, etc.) precedes the relevant article’s headline. It’s not an ideal solution: if you grab a category feed, e.g., the RSS feed for Shenton’s View, every article will still contain the category name, even though it’s implicit from the context in which you’re requesting the feed.

Recently I’ve had an additional need, though: to add additional XML elements to an RSS feed in a way that gives additional flexibility to custom clients, but doesn’t break any feed readers.

It turns out this is pretty easy, but it took a bit of ferreting around the WordPress code to work out how to do. The WordPress documentation is apallingly bad: there are online references for every function, action and filter, but working out which ones you need in what circumstance are generally best found out by perusing the source code direct.

Anyway, adding additional attributes is relatively straightforward.

1. Work out which attributes to add, and the namespace to use

All the attributes in WordPress’s default RSS feeds that aren’t part of the RSS 2.0 namespace belong to other specific namespaces, which are all specified in the opening <rss> element:

<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/"
>

I’m going to assume that the above means something to you – if it doesn’t, then maybe meddling with the RSS feed creation isn’t for you. Each of the cited URLs should, in theory at least, provide you with a route for finding which XML elements should be considered valid for the specified namespace – for example, you can see from http://purl.org/rss/1.0/modules/syndication/ that the following elements can be used:

<sy:updatePeriod>
<sy:updateFrequency>
<sy:updateBase>

There aren’t many elements defined by the referenced documents that the default feed doesn’t already use, so the chances are that any new elements you’ll want to add will be new to the document. In order to ensure that your RSS feed continues to validate, it’s wise to specify a namespace for your new elements.

In this example, I’ll be adding elements defined by the Yahoo! Media Search RSS module – namely, I’m going to use the <media:thumbnail> element to add a reference to the post’s thumbnail, where one exists.

Note that this is not the same as adding the thumbnail so that it shows up within the body of the RSS feed so that it is viewed in an RSS feed reader (to do that, you’d add a filter to the_content_feed(), modifying the HTML to include the relevant <img> element). Instead, I’m adding an XML element that points direct to the thumbnail, which can be picked up by a third party feed consumer that knows what it’s looking for. When coded correctly, standard feed readers will simply ignore this additional element.

The format for this additional element is (according to the spec):

<media:thumbnail url="[source_url]" width="[w]" height="[h]" />

where the width and height are optional attributes, but source_url is required.

2. Add your code to functions.php

// add the namespace to the RSS opening element
function add_media_namespace() {
  echo "xmlns:media="http://search.yahoo.com/mrss/"n";
}

// add the requisite tag where a thumbnail exists
function add_media_thumbnail() {
  global $post;
  if( has_post_thumbnail( $post->ID )) {
    $thumb_ID = get_post_thumbnail_id( $post->ID );
    $details = wp_get_attachment_image_src($thumb_ID, 'thumbnail');
    if( is_array($details) ) {
      echo '<media:thumbnail url="' . $details[0]
        . '" width="' . $details[1] 
        . '" height="' . $details[2] . '" />';
    }
  }
}

// add the two functions above into the relevant WP hooks
add_action( 'rss2_ns', 'add_media_namespace' );
add_action( 'rss2_item', 'add_media_thumbnail' );

What’s going on here?

The construction of the RSS 2.0 feeds takes place within wp-includes/feed-rss2.php. A number of actions are called during each feed’s construction. If you attach your function to  the relevant action, any output you echo will get inserted at the appropriate position.

The full list of such actions is:

  • rss2_ns – called within the construction of the <rss> opening element. You should output any additional namespaces here. I’d recommend also outputting at least one character of whitespace at the end as well – so if another plugin or other function also adds a namespace, there’ll always be whitespace separating each declaration. Any functions hooked to this action will also be called during the generation of any comments feeds; if you only want to add namespaces to the comments feed, you can use rss2_comments_ns.
  • rss2_head – called once, at the ‘top’ of the RSS feed, before it starts looping through every item in the feed. You would hook your function to this action if you had additional feed-level elements you wanted to add.
  • rss2_item – called once per item.

Warnings and gotchas

If you’re careful, you can add additional fields with ease. However, the actions you can hook your functions to don’t do any form of validation: if you end up including malformed XML fragments into your feeds, you’re likely to break code for anybody (or any computer) that’s consuming your RSS feed. So if you are using user-created data, make sure attributes are properly escaped, text entries are wrapped up in CDATA declarations where necessary, etc. As you update your WordPress installation, ensure that your updated feeds are correctly validated at the W3C Validator or similar.

Published by

Scott Matthewman

Formerly Online Editor and Digital Project Manager for The Stage, creator of the award-winning The Gay Vote politics blog, now a full-time software developer specialising in Ruby, Objective-C and Swift, as well as a part-time critic for Musical Theatre Review, The Reviews Hub and others.

One thought on “How to add XML elements to your WordPress RSS feed”