I need to alter the link (URL) that is produced in the taxonomy/term/xxx/feed. I am going around in circles looking for where to do this in Views. Since hook_nodeapi is not getting called as far as I can see, how can I get hold of this field so that I can add a custom query string to it?

Comments

merlinofchaos’s picture

To which link are you referring? Feeds have many links, including links to the feed and links from the feed.

nancydru’s picture

The node URL which the end-user will click to come back to our site to read the whole article. I can correctly alter this in blog/xxx/feed, but it's not working for taxonomy/term/xxx/feed, which is being produced by the Views version of taxonomy/term.

merlinofchaos’s picture

Hmm. That's weird because for normal RSS feeds, assuming you haven't modified the style in use on the feed, should use the standard method of producing RSS. See includes/modules/node/views_plugin_style_node_rss.inc (and the preprocess, where most of the work is done, is in modules/node.views.inc). There's nothing too out of the ordinary there. I can't think why nodeapi might not be getting called.

Might want to check caching? Anonymous caching covers RSS.

nancydru’s picture

Actually I stand corrected on that, it does appear that nodeapi is called, and even that build_mode is set to RSS, however, the modified $node->link field is being ignored. Yes, I see that I am changing it. And during my testing here, I am user/1.

I am doing this in hook_nodeapi(..., 'view',...):

  $node->link = url("node/$node->nid", array(
    'absolute' => TRUE,
    'query' => "cm_mmc=RSS-_-forrester-$term->cg_role_id-blogs-$term->role_id-blog_$account->profile_analyst_id",
    ));

As I mentioned, this is fine with blog/xxx/feed.

johnpitcairn’s picture

The problem, as far as I see it, is in views_plugin_row_node_rss.inc.

The $item object is created immediately after the hook_nodeapi "alter" op is invoked, and the $item->link and $item->title properties are added then.

Then hook_nodeapi "rss item" op is invoked, and array elements returned from that will be added to $item->elements.

So there's no way for hook_nodeapi "rss item" to alter the title or link. And in hook_nodeapi "alter", I don't think we can tell if the node is being built for RSS, ie messing with things there will have unfortunate side-effects.

I propose a small modification of views_plugin_row_node_rss.inc: move the addition of the $item->title and $item->link elements to AFTER hook_nodeapi "rss item" is invoked. I don't think that would affect anything else.

Patch against 6.x-2.10 attached.

nicks’s picture

As I just pointed out on this issue: http://drupal.org/node/174359 this change will only allow you to set the title, and not the link, as the link is not built from a property of the $node object. It may be possible to achieve a workaround by changing that, or by overriding the views-view-row-rss.tpl.php template, but it may require some hacking around. I suspect that finding a solution that can be patched into the views module itself will be difficult.

johnpitcairn’s picture

Yeah, sorry - I was mostly interested in changing the title.

Since we're patching the views plugin, I wonder if adding a custom hook would be a decent solution for you? Something like (untested):

  $item->title = $node->title;
  $item->link = module_invoke_all('views_view_row_rss_link', $row, $node);

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

Then implement that hook in your own module to generate and return the link.

dawehner’s picture

Thats the same code from drupal core. The item is also there.

    // Load the specified node:
    $item = node_load($nid);
    $item->build_mode = NODE_BUILD_RSS;
    $item->link = url("node/$nid", array('absolute' => TRUE));

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

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

      // Allow modules to change $node->content before the node is rendered.
      node_invoke_nodeapi($item, 'view', $teaser, FALSE);
johnpitcairn’s picture

Yes, but this is the Views issues queue. The issue is how to modify the link in an RSS feed item generated by a Views feed display - not how to do so in core's RSS feeds.

dawehner’s picture

Sure sure.

The reason why i posted it, was that we shouldn't change the code from the existing one in drupal.

strangeways’s picture

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

/**
 * 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;
    }
  }
}
johnpitcairn’s picture

Nice, no need to patch the views plugin. I was overlooking the availability of $node->build_mode in the "alter" op.

dawehner’s picture

So this is fixed?

yan’s picture

Thanks for the snippet in #11 & #12, strangeways. It works, but only when I remove the break; from the preprocessor function or put it inside the if-statement above it. i.e. like 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;
      }
    }
  }
}
nancydru’s picture

@dereine: My customer will not allow such a convoluted solution. The most they will accept is needing the case 'rss item': in hook_nodeapi(). And with at least 6 feeds so far, I'm certainly disinclined to clone the preprocess code that many times. We really need something cleaner.

nancydru’s picture

$vars['row'] contains Array ( [0] => Array ( [key] => comments [value] => http://drupal6b/noel_yuhanna/10-05-17-sybase_acquisition_sap_great_move#comments ) [1] => Array ( [key] => category [value] => Application Development [attributes] => Array ( [domain] => http://drupal6b/application_development ) ) [2] => Array ( [key] => category [value] => Database [attributes] => Array ( [domain] => http://drupal6b/category/database ) ) [3] => Array ( [key] => category [value] => ERP [attributes] => Array ( [domain] => http://drupal6b/category/erp ) ) [4] => Array ( [key] => category [value] => SAP [attributes] => Array ( [domain] => http://drupal6b/category/sap ) ) [5] => Array ( [key] => category [value] => Sybase [attributes] => Array ( [domain] => http://drupal6b/category/sybase ) ) [6] => Array ( [key] => pubDate [value] => Mon, 17 May 2010 17:00:18 +0000 ) [7] => Array ( [key] => dc:creator [value] => Noel Yuhanna [namespace] => Array ( [xmlns:dc] => http://purl.org/dc/elements/1.1/ ) ) [8] => Array ( [key] => guid [value] => 4368 at http://drupal6b [attributes] => Array ( [isPermaLink] => false ) ) )

Note, no isset($element['link'])

nancydru’s picture

Ah, it helps to spell "rss item" correctly. This seems to be working now. I'm just not going to tell the customer how it got fixed. Now I have to make sure no other feeds are broken.

nancydru’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

zerolab’s picture

Version: 6.x-2.10 » 6.x-2.16
Status: Closed (fixed) » Active
StatusFileSize
new782 bytes

@dawehner, @strangeways

first off thank you for the alternate solution. However, in some cases doing the preprocess is too much (deh, clients!). Sorry for reopening this, but the 3.3 code solves this in a simple manner ( see line 156 ) and allows a simple change in hook_nodeapi as seen here

I am attaching a patch against 2.16 that moves the $item->link = url() bit before the node hooks are called and instead relies on $item->link = $node->link and could be considered a partial backport from Views 3.3

mustanggb’s picture

Issue summary: View changes
Status: Active » Closed (outdated)