I have the following situation:
My customer wants, that content creators/editors stay anonymous to the public. While it is no problem to hide the information in HTML, I can't seem to figure out how to alter or hide the dc:creator tag in RSS, without modifying Drupal's core code.

Comments

yan’s picture

I'm having the same problem. No ideas? Another thing I'd like to do is add the content type to the rss feed (title or description) in a feed made with views.

bboldi’s picture

My solution:

Create a module (for example mymodule) and implement a nodeapi hook. Nodeapi gives you ability to modify RSS feeds ($op=='rss item'). Example:

function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL)
{
	switch($op)
	{
		case 'rss item':
		
			if($node->type=='mytype')
			{
				$node->title = 'Help! They are modifying me!'.$node->title;
				$node->teaser = 'Help! They are modifying me!'.$node->teaser;
			}		
		
		break;
	}
}

hope it helps.
----------------------------------------
Boldizsár Bednárik ing.
http://www.bboldi.com

yan’s picture

Nice workaround bboldi, it works for me. One more question though: Is it possible to apply your method to a specific RSS feed? This way the modification is applied for the node type in every RSS feed. It'd be perfect to have the change just in one feed, in case the node appears in various feeds.

yan’s picture

To answer my own question: I achieve this by adding an if-statement that checks the feed URL:

function rss_theme_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL)
{
    switch($op)
    {
        case 'rss item':

          // Array that contains feed URLs to include
          $feed_urls = array('feed/url/1', 'feed/url/2');

          // Changes for all defined URLs
          if (in_array($_REQUEST['q'], $feed_urls)){

            // Change title
            $node->title = '<my_modification>'.$node->title;

          }

        break;
    }
}

It works, I'm not sure if it's written nicely, though.

locdao’s picture

thanks bboldi

it works well for me for changing the teaser since we use a different cck field for our teasers.

kmsherald’s picture

Hello,

I have a content type called 'article' and I included the title in my teaser, so now on the rss feed the title is displaying twice. I'm trying to remove the title from the teaser so that it doesn't show in the rss description, so I created a module based on your above code, but for some reason the teaser is not updating. I can update the title fine, but the teaser still displays the contents from my mytheme_article_teaser function. Here is my code to redefine my article teaser without the node title:

function rsstheme_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL)
{
    switch($op)
    {
        case 'rss item':
            if($node->type=='article') {
            	
            	$rssteaser = '';
            	$rssteaser = '<div class="article_teaser">';
				if ($node->iid){
					$image = node_load($node->iid);
					$rssteaser .= l(image_display($image, 'thumbnail'), "node/$node->nid", array(), NULL, NULL, FALSE, TRUE);
				}	
				$rssteaser .= '<p>'.t('%short_summary', array('%short_summary' => $node->short_summary)).'</p>';	
				$rssteaser .= '</div>';
				
                $node->teaser = $rssteaser;
            }              
        break;
    }
}

Any ideas?

hunthunthunt’s picture

Great snippet - works a treat.

shadowdknight’s picture

Thanks for the solution,
can you give a sample how to replace PubDate with cck date field?

Thanks

xjm’s picture

Thanks for the suggestion. Tracking this thread in case there are any other ideas.

adamcarsonb’s picture

Can you give me an example of how you implemented the above module? I'm trying to pull in some extra CCK fields into my RSS feed, but according to http://drupal.org/node/118833 it's not possible out of the box with Views / CCK / Contemplate.

I need my RSS feed items to look more like this:

<item>
 <title>iPhone Finally Released!</title>
 <link>http://mysite.thecreativetrust.com/iphone</link>
 <mainImage>http://www.example.com/image.jpg</mainImage> //custom item
 <hoverText>This is custom hover text</hoverText>  //custom item
 <description></description>
 <pubDate>Fri, 29 Jun 2007 13:00:00 -0500</pubDate>
 <dc:creator>admin</dc:creator>
 <guid isPermaLink="false">4 at http://mysite.thecreativetrust.com</guid>
</item>

Is something like this even possible, I've spent all day on it and hit a dead end every time....

The greatest strength is knowing your greatest weakness.

flycam’s picture

I'm trying to do the same thing, the only way I could think of was making a list view and reformatting it with php to rss, then print and exit() before the layout is output. It didn't work, though. Now I'm digging inside the views module code for something usable, and found a function called _views_build_query(), which returns an array with the query, a count query and all of the arguments. Ran it through db_query() or db_query_range() and then parsed the result myself.
Note: this approach returns only the fields specified in the view. Below I use print_r() instead of writing XML.

You could duplicate the views-rss module and implement this mehtod, or use it wherever you can execute php.

$view = views_get_view('view_name');
$viewQuery = _views_build_query($view);
$viewResult = db_query_range( $viewQuery['query'], $viewQuery['args'], 0, 12);
while($item = db_fetch_array($viewResult)){
   print_r($view);
}
jyork’s picture

I found information on this at http://groups.drupal.org/node/9044.

Jeremy

pravda23’s picture

Problem with our events guide feed: it's listing the publishing date on the line below the event title, giving the impression that the publishing date is the date of the event.

we're looking for a way to customise the view and remove the publishing date from the feed entirely. any help on this? view the feed here: http://new.overtone.co.za/cape_town_event_rss

ar-jan’s picture

How would one adapt the code examples to hide a specific item from the RSS feed, like the dc: creator tag as originally asked in this thread?
I hope someone can clarify how to do this in Drupal 6.

michaelj’s picture

Try http://drupal.org/project/contemplate (great module allows theme rss and much more, but still display creator and pubDate ), so in views/modules/node/views_plugin_row_node_rss.inc -> comment line "array('key' => 'pubDate', 'value' => gmdate('r', $item->created)), array('key' => 'dc:creator', 'value' => $item->name)"- I know, very not elegant solution

ar-jan’s picture

though I forgot to post it here...

Maybe at some point someone will come up with a better solution...

abowers’s picture

Based on bboldi's code above, I used $node->name = ''; to remove the username (dc:creator) from the RSS items. So, I created a custom module with the following code in the .module file:

<?php
function mymodule_rss_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL)
{
    switch($op)
    {
        case 'rss item':
       
            if($node->type=='resource')
            {
                     $node->name = '';
            }       
       
        break;
    }
}

This will not remove the dc:creator tag entirely, but it shows as empty in the xml. I believe that doing the same thing with $node->created would meet the need of removing the timestamp from the feed, though, I would guess that having some sort of timestamp for a feed is a good idea. I'm not sure what you would set it to, whether it is a date or a string or whatever.

dzepol’s picture

This approach worked for me with 6.19. In my case, I did not want to remove author but rather replace it with the contents of a CCK field. Seems to work fine, I haven't found any problem.

<?php
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL)
{
    switch($op)
    {
        case 'rss item':
      
            if($node->type=='article')
            {
                     $node->name = $node->field_article_byline[0]['value'];
            }      
      
        break;
    }
}

?>
Bilalx’s picture

On Drupal 6:

Put "views-view-row-rss.tpl.php" in your theme directory and replace

print $item_elements;

with

$item_elements = ereg_replace('<pubDate>.*</pubDate>', '', $item_elements);  // removes pubdate
$item_elements = ereg_replace('<dc:creator>.*</dc:creator>', '', $item_elements);  // removes author
$item_elements = ereg_replace('<category .*</category>', '', $item_elements);  // removes terms			

$item_elements = preg_replace("!^\s+(\D)!m", "\\1", $item_elements);  // removes some blank lines

print $item_elements; 

You can use the same approach to insert other items

markconroy’s picture

ereg is deprecated in PHP 5.3+

But you can achieve the above using preg, like so:

$item_elements = preg_replace('<pubDate>.*</pubDate>', '', $item_elements);  // removes pubdate
$item_elements = preg_replace('<dc:creator>.*</dc:creator>', '', $item_elements);  // removes author
$item_elements = preg_replace('<category .*</category>', '', $item_elements);  // removes terms
$item_elements = preg_replace("!^\s+(\D)!m", "\\1", $item_elements);  // removes some blank lines
print $item_elements;

I've a short blog post about this here..

============

Drupal Core Maintainer for "Out of the Box" Initiative.

jaypan’s picture

You are not wrapping your regex in delimiters, so I believe that code will throw errors.

Contact me to contract me for D7 -> D10/11 migrations.

vood002’s picture

I've been trying to apply some of these changes to an RSS feed on my Drupal 6 site. Specifically, I'm using the node comment module--and I'm attempting to make a RSS feed for comments. The feed builds fine, but since comments are now nodes the link in the rss feed takes you to the comment node, rather than the parent node.

I've been trying to use nodeapi to override and change some of the rss settings with this function:

 <?php

function my_module_nodeapi(&$node, $op)
{
    switch($op)
    {
        case 'rss item':
            if($node->type == 'comment')
            {
                $node->title .= ' Test ';
                //$node->teaser .= 'Test' . $node->teaser;
                $node->path = "/test/me";
                $node->body .= '<pre>'. check_plain(print_r($node,1)) .'</pre>';
            }       
        break;
    }
}

?> 

This code will modify the Body on the node of any rss item, and as you can see I have the body modified to print out the full node object. In this printout the Title and Path will be changed to my custom setting, however in the rss feed the title and path do not change.

Does anyone have any idea what might be going wrong here? It doesn't make sense to me...i figure I'm just doing something wrong.

thanks-

vood002’s picture

If anyone searches for rss, node_comments module, feed, path etc. here's my status on creating this rss feed.

For some reason, I can't get the following code to work...although it seems like it should.

<?php

/**
* Change the path and title of an RSS item in the Comments RSS Feed
*/
function [my_module]_nodeapi(&$node, $op)
{
    switch($op)
    {
        case 'rss item':
            if($node->type == 'comment')
            {
 		global $base_url;
                $node->title .= ' by  ' . check_plain($node->name);
 		$node->path= $base_url . "/" . drupal_get_path_alias('node/'.$node->comment_target_nid);            
            }       
        break;
    }
}

?>

For some reason my views rss feed isn't being modified by this hook. At least not consistently. I'm still working on it.

In the meantime I just added a javascript redirect to my node-comment.tpl.php file


 <?php if($page): ?>
 	<?php 
 		global $base_url;
 		$url = $base_url . "/" . drupal_get_path_alias('node/'.$node->comment_target_nid); 
 	?>
	<script type="text/javascript">
		<!--
			window.location = "<?php echo $url; ?>";
		//-->
	</script>
 <?php endif; ?>

This is working for now.

johnpitcairn’s picture

I've been trying to remove taxonomy terms and modify the title in my module's hook_nodeapi "rss item" operation, but this has no effect.

It looks like views is assembling link and title BEFORE the hook_nodeapi "rss item" operation. From views_plugin_row_node_rss.inc:

    // Allow modules to modify the fully-built node.
    node_invoke_nodeapi($node, 'alter', $teaser, FALSE);

    $item = new stdClass();
    $item->title = $node->title;
    $item->link = url("node/$row->nid", array('absolute' => TRUE));

    // Allow modules to add additional item fields and/or modify $item
    $extra = node_invoke_nodeapi($node, 'rss item');
    $item->elements = array_merge($extra,
      array(
        array('key' => 'pubDate', 'value' => gmdate('r', $node->created)),
        array(
          'key' => 'dc:creator',
          'value' => $node->name,
          'namespace' => array('xmlns:dc' => 'http://purl.org/dc/elements/1.1/'),
        ),
        array(
          'key' => 'guid',
          'value' => $node->nid . ' at ' . $base_url,
          'attributes' => array('isPermaLink' => 'false')
        ),
      )
    );

So any alteration of those presumably needs to be done in the "alter" operation. But in that case it's unclear how we might determine if the node is about to be included in an rss feed, or if this is some other node view that we don't want to mess with. Ouch.

I can't really see any good reason why views should be making this distinction. Title and link could be added to $item after the "rss item" operation, since $item isn't passed in there anyway, so nothing else gets a chance to modify them.

We can modify or add stuff in $item->elements (ie $item_elements in the view template file) by returning an appropriate array from hook_nodeapi "rss feed", ie:

function mynodule_rss_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
   case 'rss item':
      // do stuff, then
      return array(
        array(
          'key' => 'dc:creator',
          'value' => 'foo',
          'namespace' => array('xmlns:dc' => 'http://purl.org/dc/elements/1.1/'),
        ),
      );
    }
    break;
  }
}

would set all author names to "foo". But that doesn't help us with title or link.

But I still can't see where the node's taxonomy terms are getting added to the $item->elements array.

Hmm. I'll poke around a bit more then file a request for clarification in the views issue queue.

nicks’s picture

Thanks for your investigation John - it was very useful.

Your suggestion for changing the contents of $item->elements doesn't actually work, as the changes you make are added to the xml, rather than replacing the field you are trying to change. I tried this for the creator using your code, and ended up with two "" tags for each entry.

You can however set the creator field by setting $node->name.

Also, note that even if the 'rss items' nodeapi hook was called before the $item object was configured, you would not be able to set the link in hook_nodeapi. This is because the link is being constructed using:

$item->link = url("node/$row->nid", array('absolute' => TRUE));

For my purposes I was hoping to set the RSS link to an external site, and it doesn't look like that is going to be possible without some pretty heavy hacking..!

strangeways’s picture

Here's some code to alter an RSS item's title, creator, and link via a custom module.

(I just posted this in the related issue at http://drupal.org/node/773400#comment-3047550 but thought it might be useful to copy here.)

/**
 * Implementation of hook_nodeapi().
 */
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'alter':
      // Alter nodes for RSS feeds.
      if ($node->build_mode == NODE_BUILD_RSS) {
        // This is where you can set your custom title and creator.
        if ($node->type == 'my_content_type') {
          $node->title = $my_custom_title;
          $node->name = $my_custom_creator;
        }
      }
    }
    break;

    case 'rss item':
      if ($node->type == 'my_content_type') {
        // This will get added to the RSS item's extra elements array, which can then be
        // accessed in the views preprocessor function below.
        return array('link' => $my_custom_link);
      }
      break;
  }
}

/**
 * Preprocessor for views RSS feed items.
 */
function mymodule_preprocess_views_view_row_rss(&$vars) {
  // If your view is generating multiple RSS feeds, you may have to change 'feed_1' to
  // match the correct display.
  if ($vars['view']->name == 'my_view_name' && $vars['view']->current_display == 'feed_1') {
    // This will use the link from the item's elements as the item's link.
    $vars['link'] = $vars['row']->elements['link'];

    // Remove the duplicate <link> entry from the item_elements. It probably wouldn't cause
    // any issues to leave it in; you'd just have two identical <link> tags for each item.
    $vars['item_elements'] = str_replace(" <link>{$vars['link']}</link>\n", '', $vars['item_elements']);
  }
}

Don't forget to clear your cache so that the preprocessor function gets recognized.

strangeways’s picture

Oops, array_merge expects an array of arrays, so in hook_nodeapi() use this line instead:

        return array(array('link' => $my_custom_link));

And the preprocessor can be replaced with this:

/**
 * Preprocessor for views RSS feed items.
 */
function mymodule_preprocess_views_view_row_rss(&$vars) {
  // If your view is generating multiple RSS feeds, you may have to change 'feed_1' to
  // match the correct display.
  if ($vars['view']->name == 'my_view_name' && $vars['view']->current_display == 'feed_1') {
    // This will use the link from the item's elements as the item's link.
    foreach ($vars['row']->elements as $element) {
      if (isset($element['link'])) {
        $vars['link'] = $element['link'];
      }
      break;
    }
  }
}
kalidasan’s picture

Hi,

I have tried below code. But no luck. Why print_r($vars) its not working?

function mymodule_preprocess_views_view_row_rss(&$vars) { 
  print_r($vars); 
}

I have also cleared cache.

jaypan’s picture

Use this:

function mymodule_preprocess_views_view_row_rss(&$vars) {
  die('<pre>' . print_r($vars, TRUE) . '</pre>');
}

Contact me to contract me for D7 -> D10/11 migrations.