Theming an RSS feed in Drupal

2011 October 20
by Karen

I still do a bit of work with Drupal as part of my job at OCLC. Mostly that involves making tweaks to the Developer Network website which runs on Drupal. In the last couple weeks I’ve wanted to create a custom RSS feed that would let me move bits of content from the site into other webpages OCLC offers. The problem is that the standard Drupal RSS feeds aren’t exactly what I want. The content I’m creating an RSS feed for uses CCK heavily and has lots of fields that I want to expose in the RSS feed. The standard Drupal settings will let me control which of these fields show or not by going to RSS. The problem is that this controls whether or not these fields show in the description element of the feed. It doesn’t allow you to map them to other elements, which is what I wanted to do. Luckily I found a nice blog post by someone who wanted to do something similar. The upshot is that I’m theming the RSS feed so that I have two new fields dc:creator (which I’ve remapped from the username of the user who create the node to another field for my content) and media:content which I’m using for the images that I need to incorporate into the other system.

After reading and trying to incorporate the code shown in the fore-mentioned blog post, I encountered two issues.

  1. dc:creator already exists as a field and I need to put different data in it
  2. the image associated with my node is very large, too large in fact for the application that is going to consume the RSS feed. So I needed to send a smaller version of it

Solving the first problem is a bit challenging because the standard dc:creator element is output via an array variable $item->elements. This array is generated via the Node API part of Drupal and if you want to override its behaviors then Drupal expects you to write a module. The result is that if you just want to deal with theming not writing a module you have two options:

  1. Manipulate $item->elements array when it comes to the view which means using a preprocess function
  2. Perform a ereg_replace on the $item_elements variable (which is a string) that is generated from the $item->elements array. This can be done by creating a customized in the views-view-row-rss.tpl.php file something that I had to do already to customize the RSS feed. Basically what this does is is find a particular pattern in the string and replaces it with whatever you want. If you replace it with nothing, then it eliminates that pattern from the string.
    $item_elements = ereg_replace(‘<dc:creator>.*</dc:creator>’, ”, $item_elements);  // removes author

Solving the second problem involved leveraging the ImageCache module and its functions. Some of my readers may have heard of or used ImageCache before. But for those of you who aren’t familiar with the module, its basic purpose is to allow a site maintainer to upload a single copy of an image and then create presets for other versions of that image. This comes in really handy if you want a very large image on a Node display page but smaller versions on a page that lists a bunch of nodes. Imagecache is really easy to use and you can access different presets via the GUI parts of Drupal. In addition though ImageCache has functions that allow you to access the presets you built via themes. The theme function allows you to apply a particular preset to an image an output said image with the appropriate HTML. In my case I didn’t need to output the image but rather the path to a particular preset of an image so I could build a media:content element in my feed. This required a slightly different function – imagecache_create_path .

My final code looked like this

New preprocess function for my template.php file

function devnet_preprocess_views_view_row_rss(&$vars) {
$view = &$vars['view'];
$options = &$vars['options'];
$item = &$vars['row'];

// Use the [id] of the returned results to determine the nid in [results]
$result = &$vars['view']->result;
$id = &$vars['id'];
$node = node_load( $result[$id-1]->nid );

$vars['title'] = check_plain($item->title);
$vars['link'] = check_url($item->link);
$vars['description'] = check_plain($item->description);
//$vars['description'] = check_plain($node->teaser);
$vars['node'] = $node;
$vars['item_elements'] = empty($item->elements) ? ''

New views-view-row-rss.tpl.php file

<item>
 <title><?php print $title; ?></title>
 <link><?php print $link; ?></link>
 <description>
 <![CDATA[
 <?php print $node->body; ?>
 ]]>
 </description>
 <?php
 $creator = '';
 if ($node->field_contact_name[0]['value']):   
 $creator = $node->field_contact_name[0]['value'];
 endif;
 if ($node->field_contact_name[0]['value'] and $node->field_institutions_organizations[0]['value']):
 $creator = $creator . ', ';   
 endif;
 if ($node->field_institutions_organizations[0]['value']):
 $creator = $creator . $node->field_institutions_organizations[0]['value'];
 endif;

 if ($node->field_application_screenshot[0]['fid']) :
 $screenshot = field_file_load($node->field_application_screenshot[0]['fid']);
 $screenshot_filepath = $screenshot['filepath'];
 $screenshot_url = $GLOBALS['base_url'] . '/' . imagecache_create_path('application_gallery_export', $screenshot_filepath);
 endif;
 $item_elements = ereg_replace('<dc:creator>.*</dc:creator>', '', $item_elements);  // removes author
 ?>
 <dc:creator><?php print $creator?></dc:creator>
 <media:content url="<?php print $screenshot_url;?>" medium="image"/>
 <?php print $item_elements;?>
 </item>

The whole project took me a couple hours but it has allowed me to move my Drupal data around and incorporate it into other systems much more effectively. Additionally, you can see from this project why I often say that feeds are the poor man’s APIs. Using this feed I can share data real-time between systems and I didn’t need to build a fancy API from scratch. All I needed to do was understand the extensibility of RSS and Drupal. If you want you can check out the feed on the Developer Network site.

 

No comments yet

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS