Problem: once render($content) is called, show($content['element'] will affect the array, but subsequent calls to render($content) will render the cached copy of $content, which was generated prior to the show($content['element']) call.

Steps to reproduce:

     
      // We hide the comments and links now so that we can render them later.
      hide($content['comments']);
      print render($content);

      // show comments
      show($content['comments']);

      //attempt to print content again but $content will be printed without comments.
      print render($content);
      //comments are printed
      print render($content['comments']);
      

If we never render $content, the hide/show functions work.

      hide($content['comments']);
      hide($content['links']);
      show($content['comments']);
      print render($content);

Also if you copy $content to foo, and then call print render($foo), the comments will be printed

     
      // We hide the comments and links now so that we can render them later.
      hide($content['comments']);
      print render($content);

      // show comments
      show($content['comments']);

      //copy $content to $foo
      $foo = $content
      //attempt to print content again but $content will be printed without comments.
      print render($content);
     
      //comments are printed along with 
      print render($food)

      //comments are printed
      print render($content['comments']);
      

Expected Behavior: once show(&$element) is called, print render($content) prints the entire content, including the array element we set to show.

Actual Behavior: show(&$element) updates the array, but print render ($content) prints a cached version of the array.

CommentFileSizeAuthor
#4 Screen shot 2010-10-03 at 10.48.06 AM.png23.91 KBkanani

Comments

kanani’s picture

Title: after render($content) is called, subsequent calls to show(&$element) do not affected subsequent calls to print render($content) » same behavior for hide(&$element) as well

Turns out its the same behavior for hide(&$element) as well. Once render($content) is called, any subsequent calls to render(&$content) will return the cached render, regardless of any calls to show/hide.

This is perfectly valid for $content since you should theoretically not be printing it twice, but for other variables you may want to do that. At a minimum the API should note this.

damien tournoud’s picture

Category: bug » support

There is no such thing as the "cached copy of $content", except for the render cache, but I strongly doubt that you are running into it.

This is the expected behavior:

// We hide the comments so that we can render them later.
hide($content['comments']);

// Render the content without the 'comments' element.
print render($content);

// Show comments.
show($content['comments']);

// This will return nothing, because $content has already been rendered.
print render($content);

// This will print the comments, as they have not been rendered yet.
print render($content['comments']);

// This will return nothing, because comments have been rendered now.
print render($content['comments']);

// Show comments.
show($content['comments']);

// This will print the comments, because of the previous show().
print render($content['comments']);
damien tournoud’s picture

Title: same behavior for hide(&$element) as well » After render($content) is called, subsequent calls to show(&$element) do not affected subsequent calls to print render($content)
kanani’s picture

StatusFileSize
new23.91 KB

I annotated the expected behaviour code from #2 and dropped it into node.tpl.php.

  <pre> // We hide the comments so that we can render them later. 
  <?php hide($content['comments']); ?>
  
   </pre>

<pre> // Render the content without the 'comments' element.
<?php print render($content); ?>

  </pre>

<pre> // Show comments.  
<?php show($content['comments']); ?>

</pre>

<pre> // This will return nothing, because $content has already been rendered.   
<?php print render($content); ?>
</pre>

<pre> // This will print the comments, as they have not been rendered yet.   
<?php print render($content['comments']); ?>
</pre>

<pre> // This will return nothing, because comments have been rendered now.   
<?php print render($content['comments']); ?>
    
    </pre>

Actual behavior is different. The second call to render($content) returns the content. (See http://api.drupal.org/api/function/render/7 which says that call to render(&$element) always returns the top level element)
Also the very last call to print render($content['comments']); returns the comments, even though they were previously rendered.

 // We hide the comments so that we can render them later. 
    
   
 // Render the content without the 'comments' element.
BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY


Add new comment

  
 // Show comments.  

 // This will return nothing, because $content has already been rendered.   
BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY BODY

Add new comment
 // This will print the comments, as they have not been rendered yet.   
          
Comments


    Sat, 10/02/2010 - 17:41 — admin

COMMENTS COMMENTS COMMENTS      
COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS
    

// This will return nothing, because comments have been rendered now.   

          
Comments


    Sat, 10/02/2010 - 17:41 — admin
        
COMMENTS COMMENTS COMMENTS
      
COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS COMMENTS


  delete
edit
reply

Add new comment
jhodgdon’s picture

Status: Active » Fixed

I wasn't quite convinced by kanani's test, so I altered it a bit...

What I found:

If you have $content containing $content['comments']...
- If you call print render($content), you get the whole thing. After that, if you call hide($content['comments']) and then print render($content) again, you still get the whole thing -- the hide() has no effect.
- If you call hide($content['comments']) first, before the first render, then subsequent calls to show($content['comments']) do not affect the output of print render($content) at all.

Which is what kanani reported.

It is actually the expected behavior if you look at the doc for drupal_render() -- it is going to set the #printed status flag at the top level the first time through, so it will never look deeper after that first call.

However, that is not what is documented in render(), show(), and hide(). I think this is just a doc problem, and should be fixed on the other doc issue that kanani reported
#930000: show(), hide(), and render() documentation is misleading

For reference, here's the code I added to the top of my node.tpl.php to test this. Remove the first print render($content) line to test that if you hide initially, subsequent shows do nothing; leave it in to test that if it's shown initially, subsequent hides do nothing.

print "<br />content without adulturation<br />";
print render($content);

hide($content['comments']);
print "<br />content with comments hidden<br />";
print render($content);

show($content['comments']);
print "<br />content with comments shown<br />";
print render($content);

print "<br />comments only<br />";
print render($content['comments']);

print "<br />content again<br />";
print render($content);

print "<br />now return to your regular programming<br />";

So I think I'll mark this as "fixed" as a support request, and leave the doc issue open. Feel free to disagree :)

kanani’s picture

I think

"So I think I'll mark this as "fixed" as a support request, and leave the doc issue open." 

is right on. And we should thank RockSoup for first surfacing this issue at his session at the Vancouver PNW Summit 2010

Status: Fixed » Closed (fixed)

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