Control Title link and "read more" in RSS Feed of views

Events happening in the community are now at Drupal community events on www.drupal.org.
aurelien-bordeaux's picture

Hi.
I have this need: use drupal as a rss remixer. That means I want to suscribe to feed1, feed2, feed3 and give "tag A" as a tag for feed 1 and 2.

Then I make a view that is the taxonomy term view for "tag A".
I want the RSS feed of this view to redirect title links and "read more" links directly to the original article, and not to my site.
But I can't, since the RSS style in views is not changeable.
I tried with "Contemplate module", but it will only allow me to change the teaser and body of the rss feed.

Is there a way around not to manipulate template directly? If not, i would love to have a step by step method to do so, since I am not familiar with this.

Thanks!!!

Aurélien

Comments

Aurélien: We did something

TKS's picture

Aurélien:

We did something similar with the core RSS feed -- it involved writing a module to override the function with with a themable one, and then making the desired changes in template.php.

See http://drupal.org/node/200434#comment-1069310 for details. The same approach could work for views-generated RSS feeds.

Sounds great

aurelien-bordeaux's picture

Knowing that there is a solution made my day! Knowing how to deal with those functions would make my week end!!

This post shows exactly the same problem, but I don't know how to implemant this solution.
Can you tell me in which files I should put those functions?

The first two chunks of code

TKS's picture

The first two chunks of code in that post are what make up the themefeed module:
- the first should be saved as themefeed.module
- the second should be saved as themefeed.info
- both should go in a folder at .../sites/all/modules/themefeed

The third chunk of code is what you then put in the template.php file of your theme, and that is where you make changes to get whatever alterations you're seeking.

And remember, this is for the CORE RSS feeds, not those generated by Views. But in going back into our template.php file, I see we have an override for Views RSS items as well:

// ==================== Override of Views' RSS Function ====================



/**
* plugin that actually displays an RSS feed
*/
function phptemplate_views_rss_feed($view, $nodes, $type) {
  if ($type == 'block') {
    return;
  }
  global $base_url;


  $channel = array(
    // a check_plain isn't required on these because format_rss_channel
    // already does this.
    'title'       => views_get_title($view, 'page'),
    'link'        => url($view->feed_url ? $view->feed_url : $view->real_url, NULL, NULL, true),

    'description' => $view->description,
  );

  $item_length = variable_get('feed_item_length', 'teaser');
  $namespaces = array('xmlns:dc="
http://purl.org/dc/elements/1.1/"');

  // Except for the original being a while and this being a foreach, this is
  // completely cut & pasted from node.module.
  foreach ($nodes as $node) {

    // Load the specified node:
    $item = node_load($node->nid);
    // Set date based on pub_date field, not node creation date
    // Need the + 18000 to get this value to EST for some reason
    $item->pubdate = ($item->field_pub_date[0][value] + 18000);
    $item->rss_link = url('node/'. $item->nid, NULL, NULL, 1);
    if ($item_length != 'title') {
      $teaser = ($item_length == 'teaser') ? TRUE : FALSE;


      // Filter and prepare node teaser
      if (node_hook($item, 'view')) {
        node_invoke($item, 'view', $teaser, FALSE);
      }
      else {
        $item = node_prepare($item, $teaser);

      }

      // Allow modules to change $node->teaser before viewing.
      node_invoke_nodeapi($item, 'view', $teaser, FALSE);
    }

    // Allow modules to add additional item fields

    $extra = node_invoke_nodeapi($item, 'rss item');
    $extra = array_merge($extra, array(array('key' => 'pubDate', 'value' =>  date (r, $item->pubdate)), array('key' => 'dc:creator', 'value' => $item->name), array('key' => 'guid', 'value' => $item->nid . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false'))));

    foreach ($extra as $element) {
      if ($element['namespace']) {
        $namespaces = array_merge($namespaces, $element['namespace']);
      }
    }
   
    // Prepare the item description

    switch ($item_length) {
      case 'fulltext':
        $item_text = $item->body;
        break;
      case 'teaser':
        $item_text = $item->teaser;
        if ($item->readmore) {
          $item_text .= '<p>'. l(t('read more'), 'node/'. $item->nid, NULL, NULL, NULL, TRUE) .'</p>';
        }
        break;
      case 'title':
        $item_text = '';

        break;
    }

    $items .= format_rss_item($item->title, $item->rss_link, $item_text, $extra);
  }

  $channel_defaults = array(
    'version'     => '2.0',
    'title'       => variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', ''),

    'link'        => $base_url,
    'description' => variable_get('site_mission', ''),
    'language'    => $GLOBALS['locale'],
  );
  $channel = array_merge($channel_defaults, $channel);


  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  $output .= "<rss version=\"". $channel["version"] . "\" xml:base=\"". $base_url ."\" ". implode(' ', $namespaces) .">\n";

  $output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language']);
  $output .= "</rss>\n";

  drupal_set_header('Content-Type: text/xml; charset=utf-8');

  print $output;
  module_invoke_all('exit');
  exit;
}

The Views_RSS Module has a function called theme_views_rss_feed which means that all you have to do is put the appropriate overrride into your template.php file. (In the example above, we just needed to use a CCK date field in the feed as opposed to the node's creation date.)

Good luck!

Thank you.. but I need more help!

aurelien-bordeaux's picture

Thank you for the patience of your explanation.
I tried but didn't succeed.
My feed node type is "feed"
My feed item type is "story".

Are there any parameters that I am suppose to switch in the code you gave me?

one more question: Is the "Override of Views' RSS Function" suppose to replace the "Override of ThemeFeed Module's theme_rss_item" Function?
Shall I just place this function at the end of the template.php? (which I did).

I am sorry for those dummies question, but as you understood, I don't speak php...

Aurélien: First off, be

TKS's picture

Aurélien:

First off, be warned: I don't know much PHP either! But basically, you're on the right track -- you should be able to just put an "Override of Views' RSS function" in your template.php file. I don't think you need any of the ThemeFeed stuff at all.

The trick is figuring out exactly what you need to change in your override. The function in the views_rss.module itself is what you should start with -- it looks like this:

   
/**
* plugin that actually displays an RSS feed
*/
function theme_views_rss_feed($view, $nodes, $type) {
  if ($type == 'block') {
    return;
  }
  global $base_url;

  $channel = array(
    // a check_plain isn't required on these because format_rss_channel
    // already does this.
    'title'       => views_get_title($view, 'page'),
    'link'        => url($view->feed_url ? $view->feed_url : $view->real_url, NULL, NULL, true),
    'description' => $view->description,
  );

  $item_length = variable_get('feed_item_length', 'teaser');
  $namespaces = array('xmlns:dc="http://purl.org/dc/elements/1.1/"');

  // Except for the original being a while and this being a foreach, this is
  // completely cut & pasted from node.module.
  foreach ($nodes as $node) {
    // Load the specified node:
    $item = node_load($node->nid);
    $link = url("node/$node->nid", NULL, NULL, 1);

    if ($item_length != 'title') {
      $teaser = ($item_length == 'teaser') ? TRUE : FALSE;

      // Filter and prepare node teaser
      if (node_hook($item, 'view')) {
        node_invoke($item, 'view', $teaser, FALSE);
      }
      else {
        $item = node_prepare($item, $teaser);
      }

      // Allow modules to change $node->teaser before viewing.
      node_invoke_nodeapi($item, 'view', $teaser, FALSE);
    }

    // Allow modules to add additional item fields
    $extra = node_invoke_nodeapi($item, 'rss item');
    $extra = array_merge($extra, array(array('key' => 'pubDate', 'value' =>  date('r', $item->created)), array('key' => 'dc:creator', 'value' => $item->name), array('key' => 'guid', 'value' => $item->nid . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false'))));
    foreach ($extra as $element) {
      if ($element['namespace']) {
        $namespaces = array_merge($namespaces, $element['namespace']);
      }
    }
   
    // Prepare the item description
    switch ($item_length) {
      case 'fulltext':
        $item_text = $item->body;
        break;
      case 'teaser':
        $item_text = $item->teaser;
        if ($item->readmore) {
          $item_text .= '<p>'. l(t('read more'), 'node/'. $item->nid, NULL, NULL, NULL, TRUE) .'</p>';
        }
        break;
      case 'title':
        $item_text = '';
        break;
    }

    $items .= format_rss_item($item->title, $link, $item_text, $extra);
  }

  $channel_defaults = array(
    'version'     => '2.0',
    'title'       => variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', ''),
    'link'        => $base_url,
    'description' => variable_get('site_mission', ''),
    'language'    => $GLOBALS['locale'],
  );
  $channel = array_merge($channel_defaults, $channel);

  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  $output .= "<rss version=\"". $channel["version"] . "\" xml:base=\"". $base_url ."\" ". implode(' ', $namespaces) .">\n";
  $output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language']);
  $output .= "</rss>\n";

  drupal_set_header('Content-Type: text/xml; charset=utf-8');
  print $output;
  module_invoke_all('exit');
  exit;
}

As I said before, our override was focused on changing the publication date. To alter the link in your RSS feeds, I think you'd want your override to look like this:

// ==================== Override of Views' RSS Function ====================
/**
* plugin that actually displays an RSS feed
* note the name change from theme_views_rss_feed to phptemplate_views_rss_feed
*/
function phptemplate_views_rss_feed($view, $nodes, $type) {
  if ($type == 'block') {
    return;
  }
  global $base_url;

  $channel = array(
    // a check_plain isn't required on these because format_rss_channel
    // already does this.
    'title'       => views_get_title($view, 'page'),
    'link'        => url($view->feed_url ? $view->feed_url : $view->real_url, NULL, NULL, true),
    'description' => $view->description,
  );

  $item_length = variable_get('feed_item_length', 'teaser');
  $namespaces = array('xmlns:dc="http://purl.org/dc/elements/1.1/"');

  // Except for the original being a while and this being a foreach, this is
  // completely cut & pasted from node.module.
  foreach ($nodes as $node) {
    // Load the specified node:
    $item = node_load($node->nid);

    // Here's where we're changing the link from
    // $link = url("node/$node->nid", NULL, NULL, 1);
    // to:
    $link=$item->links['feedapi_original']['href'];
  
    if ($item_length != 'title') {
      $teaser = ($item_length == 'teaser') ? TRUE : FALSE;

      // Filter and prepare node teaser
      if (node_hook($item, 'view')) {
        node_invoke($item, 'view', $teaser, FALSE);
      }
      else {
        $item = node_prepare($item, $teaser);
      }

      // Allow modules to change $node->teaser before viewing.
      node_invoke_nodeapi($item, 'view', $teaser, FALSE);
    }

    // Allow modules to add additional item fields
    $extra = node_invoke_nodeapi($item, 'rss item');
    $extra = array_merge($extra, array(array('key' => 'pubDate', 'value' =>  date('r', $item->created)), array('key' => 'dc:creator', 'value' => $item->name), array('key' => 'guid', 'value' => $item->nid . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false'))));
    foreach ($extra as $element) {
      if ($element['namespace']) {
        $namespaces = array_merge($namespaces, $element['namespace']);
      }
    }
   
    // Prepare the item description
    switch ($item_length) {
      case 'fulltext':
        $item_text = $item->body;
        break;
      case 'teaser':
        $item_text = $item->teaser;
        if ($item->readmore) {
          $item_text .= '<p>'. l(t('read more'), 'node/'. $item->nid, NULL, NULL, NULL, TRUE) .'</p>';
        }
        break;
      case 'title':
        $item_text = '';
        break;
    }

    $items .= format_rss_item($item->title, $link, $item_text, $extra);
  }

  $channel_defaults = array(
    'version'     => '2.0',
    'title'       => variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', ''),
    'link'        => $base_url,
    'description' => variable_get('site_mission', ''),
    'language'    => $GLOBALS['locale'],
  );
  $channel = array_merge($channel_defaults, $channel);

  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  $output .= "<rss version=\"". $channel["version"] . "\" xml:base=\"". $base_url ."\" ". implode(' ', $namespaces) .">\n";
  $output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language']);
  $output .= "</rss>\n";

  drupal_set_header('Content-Type: text/xml; charset=utf-8');
  print $output;
  module_invoke_all('exit');
  exit;
}

And that should do it! Or, it could give you a big, ugly error message -- in which case, we'll need a more skilled Drupaler to weigh in here. But I hope that helps -- even if the exact code for changing the URL isn't just right, this is the way to override themable functions in general.

Good luck

Oups. I went for the small

aurelien-bordeaux's picture

Oups. I went for the small tiny error message... (not the bug ugly one!).

"Parse error: syntax error, unexpected T_IS_IDENTICAL in /home/inteaur8/public_html/annuaire9/themes/garland/template.php on line 104"

But I think I have enough material to figure out what's missing and don't want to bother you too much...

I'll work on it ( it might take some time) and post back when I find (or not) a solution.

one more question: where is the views_rss.module in drupal 6?
I found it in back-ups I did in drupal 5 but not 6...
Am I missing something important?

AHH...

TKS's picture

If you're on Drupal 6, then none of the above code is likely to work as-is for you. (Sorry, if you mentioned that you were running 6, I didn't see that.) The basic concepts about theme-overrides still hold true, but all the examples I gave are from Drupal 5.

I'm afraid I don't know where in Views for Drupal 6 one finds the RSS-creating function. But if you can find it -- and assuming it's still themable -- then you should be able to fashion a fix for yourself.

Oh my.. ! :)

aurelien-bordeaux's picture

I am sorry for taking that for granted... and taking your time .. :(
I'll ask and post around till I find something, and will get back to this post when the problem is solved.

Thanks for your help anyway. That encouraged me exploring some files and directories in Drupal system!
It looks like travelling in a country where I don't speak the language!!

No more error

aurelien-bordeaux's picture

the error was caused by a "br" in the code.
So no more error message.

I placed the second part of code in the template.php file, but didn't get the function to work.

Seems to me that there is something related with the views_rss.module file that I can't find....

On drupal 6...

aurelien-bordeaux's picture

Exploring more inside drupal 6 views module...

On the feed display, we can see a theme information.
It seems that the style plugin has to be modified to get the appropriate results.

So I guess that there is something to do in this file : views_plugin_style_rss.inc

and probably in this one : views-view-rss.tpl

But I have no idea what are the appropriate changes...

On drupal 6...

aurelien-bordeaux's picture

Exploring more inside drupal 6 views module...

On the feed display, we can see a theme information.
It seems that the style plugin has to be modified to get the appropriate results.

So I guess that there is something to do in this file : views_plugin_style_rss.inc

and probably in this one : views-view-rss.tpl

But I have no idea what are the appropriate changes...

posting here a well

sullyvon's picture

I'd recommend that you use the "Fields" Row Style in your view instead of the "Node" Row Style. Then you can add the Node Title, Node Teaser, and Item Link to your Fields.

Now, I just need to remove the bogus more link.

It seems I've come to a

PeterZ's picture

It seems I've come to a similar point as you.

It also appears in the Views code (6.x) that there are handlers for core aggregator (views/modules/aggregator) but nothing for feedAPI.

I also played with views_plugin_row_node_rss.inc in views/modules/node, but to no avail.

Seems that others would also have this problem, but after a fair amount of web searching, I haven't found much information at all...

I also looked at the Links Package module to see whether that could help work around, but I didn't see anything easy or scaleable.

Did you have any success with this?

Not very drupalesque, but to

PeterZ's picture

Not very drupalesque, but to get the titles of all RSS feeds to point to a different URL, I went into:

Sites/all/modules/views/modules/node/views_plugin_row_node_rss.inc

Found this line:

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

And replaced it with this:

$item->link = $node->field_fi_original_url[0][value];

In my case, field_fi_original_url[0][value] is the field storing the "original URL". You'll have to use whatever field is doing this in your content type.

Keep in mind that every time you update the views module, you'll have to make this change again. So, in the very, very, very small number of cases where you make changes to core code or modules, make sure you keep a very good list and description of these changes so that you can reapply them after making upgrades. Many would argue never to do this as it does complicate maintenance and upgrade handling.

I'd recommend that you use

sullyvon's picture

I'd recommend that you use the "Fields" Row Style in your view instead of the "Node" Row Style. Then you can add the Node Title, Node Teaser, and Item Link to your Fields.

Now, I just need to remove the bogus more link.

For some reason, for my RSS

nixdrupal's picture

For some reason, for my RSS feed view, only the "Node" Row Style is available in the drop down. Agreed if we can use the "Fields" Row Style, that should make things a bit easier. Otherwise the only way seems to be to change the views rss tpl file.

subscribe

mstobbs's picture

subscribe

Views RSS Module

mstobbs's picture

On a related note, the Views RSS module adds a RSS Feed - Fields option to the Styles attribute of a Feeds View.

http://drupal.org/project/views_rss

RSS & Aggregation

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: