Take this example.

I am loading node 1 which has a filter enabled on it that will node_load(2) and prepare some of the content to embed within the body of node 1. To do this I call node_view() on node 2. node_view() calls node_is_page() to see if you are viewing the main node (in this case node 1) on the page, in order to decide whether to add contextual links. node_is_page() calls menu_get_object() to get the page node nid which in turn will load the node as a page argument. But if
node_view() is called *during* the load of the page node (i.e. during a cached input filter), this means node_load() gets called again on the same node.

Right now to stop this there are two pieces of code in the filter. One checks for the recursion and exits before calling node_view but also the code now just uses field_attach_prepare_view, entity_prepare_view and field_attach_view to get what it needs. However ignoring the filter and this use case you should be able to call node_view($nid) and have it work regardless of the active URL.

This was added in d7. In D6 node_view() has an extra boolean param "links".

Comments

disasm’s picture

Assigned: Unassigned » disasm
disasm’s picture

Note: I tested this in Drupal 8.x not 7.x

I was not able to reproduce the recursion issue. The issue summary was a little vague, so it's possible, I'm not even doing what the original reporter was.

Here are my steps:

  • Install the latest Drupal 8.x using the standard profile.
  • Create a new node with title "node 1" and body empty
  • Create a new node with title "node 2" and body "node 2 content"
  • Enable php module
  • Edit node1 with the following contents:
<?php
$node2 = node_load(2);
echo drupal_render(node_view($node2));
?>
  • Go to 'node/1'. The page displays contents of node 2 inside node 1
  • disasm’s picture

    Status: Active » Postponed (maintainer needs more info)

    I just ran the same steps on D7. It worked as expected, no errors.

    I'm changing status to postponed until we get more info from the original reporter.

    stewsnooze’s picture

    Status: Postponed (maintainer needs more info) » Active

    Hi,

    The bug was around the filter system failing. I am not sure your code in #2 would reproduce it. Here is what I had at the time. I had a filter that looked for {node:xx} where x is the nid. The filter would then load the title and a field from node xx and replace the value with that detail.

    I was thinking about this when I saw the d.o upgrade to d7 and the project module does something similar to show related issues. This would have worked fine in 6.

    disasm’s picture

    I really need some sample code and detailed steps to reproduce to be able to understand what you are trying to do. Please see my comment #2 for an example of what steps to reproduce should look like.

    xjm’s picture

    Status: Active » Postponed (maintainer needs more info)

    Setting status back for more detailed steps to reproduce this.

    nm-dev’s picture

    Similar problem here.

    Trying to write a filter to embed nodes I get an infinite Loop after saving content.
    The node's content contains a tag [task]%nid[/task] wich needs to be replaced by the renderend node output.

    Strange thing: After calling any other page everything works fine and the rendered content appears as expected.

    Here is my custom filter code:

    function section_content_filter_info() {
      $filters['filter_content_tasks'] = array(
        'title' => t('Content - Tasks Filter'),
        'description' => t('Every [task](node_id)[/task] pattern is beeing replaced by its content.'),
        'process callback' => '_section_content_filter_tasks_process',
      );
      return $filters;
    }
    
    function _section_content_filter_tasks_process($text, $filter, $format) {
      $regex = '#\[task\]([0-9]+)\[\/task\]#s';
      preg_match($regex, $text, $matches);
      if (!empty($matches) && count($matches) > 1) {
        $nid = $matches[1];
        $node = node_load($nid);
    
        if ($node != FALSE && node_access('view', $node) && $node->status) {
          $node_view = node_view($node); //infinite loop here
          $node_output = drupal_render($node_view);
          $text = preg_replace($regex, $node_output, $text);
        }
      }
      return $text;
    }
    

    A non-existent viewname or other viewname than 'full' solves this issue for me.

    $node_view = node_view($node, 'teaser', NULL);
    
    hawkeye.twolf’s picture

    @nm-dev: In your filter's info declaration, add 'cache' => FALSE. This fixed it for me (after much consternation!). E.g.,

    function section_content_filter_info() {
      $filters['filter_content_tasks'] = array(
        'title' => t('Content - Tasks Filter'),
        'description' => t('Every [task](node_id)[/task] pattern is beeing replaced by its content.'),
        'process callback' => '_section_content_filter_tasks_process',
    
        'cache' => FALSE,
    
      );
      return $filters;
    }
    
    neRok’s picture

    Title: Calling node_view whilst loading a node can cause an infinite loop. » Calling node_view within a filter can cause an infinite loop
    Component: node.module » filter.module
    Issue summary: View changes

    I can confirm the problem in the original post and #7. You must create a text filter that will load/view a node as part of its process (as seen in #7 code example).

    I received the error Fatal error: Maximum function nesting level of '100' reached, aborting! in \includes\database\database.inc on line 248

    I believe the workflow causing the error is this (not investigated, just a hunch):
    1: You view node/1, which has a link in its body to node/2.
    2: The filter acting on node/1 body loads node/2.
    3: Whilst drupal is loading node/2, node/2's body needs text filters applied, which in turn may load node/3.
    4: And the cycle continues...


    EDIT: Thought I would post my work-around. I just reverted to a manual database query. In my case, I am replacing [[node:nid]] with a link to the node that is prefixed with the taxonomy term (in this case called category), so the output is <a class="inter-wiki-link" href="/aliased/path/to/node">Category: Node Title</a>
    function my_module_filter_process($text, $filter) {
    
      if (!preg_match_all('|\[\[node:(\d+)]]|', $text, $matches, PREG_SET_ORDER)) {
        return $text;
      }
    
      $nids = array();
      foreach ($matches as $match) {
        $nids[] = $match[1];
      }
    
      $query = db_select('field_data_field_category','f')
        ->fields('n',array('nid','title'))
        ->fields('t',array('tid','name'))
        ->condition('f.entity_id',$nids,'IN');
      $query->join('taxonomy_term_data','t','f.field_category_target_id = t.tid');
      $query->join('node','n','f.entity_id = n.nid');
    
      $results = $query->execute()->fetchAllAssoc('nid');
      
      foreach ($matches as $match) {
        $link = l("{$results[$match[1]]->name}: {$results[$match[1]]->title}", "node/{$match[1]}", array('attributes' => array('class' => 'inter-wiki-link')));
        $text = str_replace($match[0], $link, $text);
      }
      
      return $text;
    
    }
    
    acbramley’s picture

    I've just encountered this very issue, the problem is I can't really change my filter to use db queries as that would involve a lot of refactoring, any one else have a fix for this?

    acbramley’s picture

    The patch at https://www.drupal.org/node/2470503#comment-9952629 fixed my issues, hope this helps someone!

    Status: Postponed (maintainer needs more info) » Closed (outdated)

    Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.