Get the contents of a block instead of displaying it?

Permalink 1 user found helpful
I've been trying to find a way of returning the contents of a block (fully rendered) instead of having it instantly pushed out to the browser (using $b->display()).

It seems that there is no way to do this? I tried using output buffering to surround the call to $b->display() but it seems to still cause the output to be displayed in the browser.

I'm currently using the fact that my block is a content block and I can access the content via $b->getInstance()->getContent(), however this obviously only works for the content block type and I would prefer something generic that works for any block type.

Is there any other/better way of getting the content of a block in to a variable (I want to modify the content on the fly... in this particular case, using strip_tags() on it)?

View Replies: View Best Answer
griebel replied on at Permalink Reply
griebel
Use this code to call the area, instead of a specific block

$fetchNews = new Area('News');
$specialPage = Page::getByID($id, "ACTIVE"); 
$fetchNews->display($specialPage);


You can then modify or display the output.

Another solution is to modify the block template, copy the default template to /block/content/templates/mytemplate.php, you can then edit your custom template and assign it to the block, using Concrete5s interface.
esand replied on at Permalink Reply
That code still just *displays* the contents. To give you a slightly better idea of what I'm trying to do, this is what I have right now:

$a = new Area('Main');
if ($c->isEditMode()) {
   $a->display($c);
}
else {
   $b = $a->getAreaBlocksArray($c);
   foreach ($b as $i => $block) {
      $html = strip_tags($block->getInstance()->getContent());
      echo '<div class="div-' . $i . ($i ? '">' : ' active">') . $html . '</div>';
   }
}


My "workaround" is where I assign a value to $html. What I would have preferred to be able to do was:

$html = strip_tags($block->display());


Where calling $block->display() would *return* the contents, instead of display it. Instead, there seems like there is no method (defined in the Block class or any inherited classes) of properly accessing the contents of a block, which is exactly what I require.

Creating a template for the block type is one method, however again that affects *only* that specific block type, and on top of that it's not a very "theme portable" method.
griebel replied on at Permalink Reply
griebel
A quick hint, you can use ob_start to capture output.

http://php.net/manual/en/function.ob-start.php...

<?php
function callback($buffer)
{
  // replace all the apples with oranges
  return (str_replace("apples", "oranges", $buffer));
}
ob_start("callback");
?>
<html>
<body>
<p>It's like comparing apples to oranges.</p>
</body>
</html>
<?php
ob_end_flush();
esand replied on at Permalink Best Answer Reply
Yes, I actually mentioned I had tried that in my original post. You did almost the same thing I did, which was use ob_end_flush() (which in your example doesn't really help); I had used ob_get_flush().

I partially blame the PHP documentation for some reason not "recommending" ob_get_clean() when looking at ob_get_flush(). I was sure that a function should exist (in output buffering) to allow me to retrieve all output and *not* display it, but for whatever reason I totally missed seeing ob_get_clean().

Once I found ob_get_clean() I was able to do what I wanted:

$a = new Area('Main');
if ($c->isEditMode()) {
   $a->display($c);
}
else {
   $b = $a->getAreaBlocksArray($c);
   foreach ($b as $i => $block) {
      ob_start();
      $tab->display();
      $html = strip_tags(ob_get_clean());
      echo '<div class="div-' . $i . ($i ? '">' : ' active">') . $html . '</div>';
   }
}
lexbi replied on at Permalink Reply
Thanks for this, really helpful!
chris123uk replied on at Permalink Reply
chris123uk
Hi please can you help me out?

am trying to get back the html of a global area but i must be doing it wrong:

$a = new GlobalArea ('major module description ');
$b = $a->getAreaBlocksArray($c);
foreach ($b as $i => $block) {
ob_start();
$tab->display();
$html = strip_tags(ob_get_clean());
echo $html;
}

please can you tell me what i am missing here?
rainmaker replied on at Permalink Reply
rainmaker
Hey! I was trying to do the same. Were you ever able to figure it out?

Thanks!
rainmaker replied on at Permalink Reply
rainmaker
Actually, I think I just figured this out. Not sure if this helps you any, but Global Areas are kind of like Stacks. I just displayed the Global Area like this.....

$block = Stack::getByName('Reserve Now Header');
if( is_object($block) ) $block->display();


Hope that helps you!
JohntheFish replied on at Permalink Reply
JohntheFish
Enlil has a block in the prb that does that, so a global area can also be displayed as if it were a stack.
chris123uk replied on at Permalink Reply
chris123uk
not as such but maybesome one here can help us? hehe.

i did a workaround though using jquery to update the blocks content. e.g. instead of editing the blocks html before its pushed to the screen... just update the html after page load
JohntheFish replied on at Permalink Reply
JohntheFish
For the php solution you need to capture and end the output buffer. Also you probably need to call ->display() on the block object (I have not checked the api for that)
chris123uk replied on at Permalink Reply
chris123uk
sooo if i needed to do a preg_replace on a blocks html before pushing it to the screen would the code look like this? :

$block = Stack::getByName('my block');
if( is_object($block) ) $html = $block->display();
// am doing this in a page list block so am putting the page list parts into my link here.
$link = "<a href=\"{$url}\" target=\"{$target}\">{$title}</a>";
// Replace the inside contents of the <h4> with the link.
$html = preg_replace("@(<h4 class=\"reusable-heading\">)([^<]+)(</h4>)@","\\1{$link}\\3",$html);
JohntheFish replied on at Permalink Reply
JohntheFish
You still need to capture the block output. display() will output to std out, not return a string.

For capturing the output buffer, see
http://uk3.php.net/manual/en/ref.outcontrol.php...

I am unclear what your ultimate objective is. If all you are doing is adding links to headings you may be able to use my Magic Linkify addon with no need to write php.
JohntheFish replied on at Permalink Reply
JohntheFish
For a page list block, have a look at Page List Teasers by jordanlev. May be a simpler starting point.
chris123uk replied on at Permalink Reply
chris123uk
hi John yes i am getting a pages block out within a page list. the block was the container and the url / link was getting out put above the block so i wanted to combine them by adding the link with the blocks html.

i was using Teasers but it doesn't support global blocks.

i really needed to make it work with global blocks so i just got the stock page list view and output my global block within the loop.

i make my global blocks have there pages collection id appended to there handle so i just asked the page list what collection id each page has in the loop and put that id in the handle to get the correct global bock back.

$myLessonId = $page->getCollectionID();
$a = new GlobalArea ('major module description '. $myLessonId .''); $a->display($c);



i do this because i have a child page that my client can edit that will affect all the blocks in the parent pages.

basically am making site that has lessons with that have modules and then subjects above them. all the blocks on the subject and modules pages can be edit in on place with in each drop down / subject.
JohntheFish replied on at Permalink Reply
JohntheFish
I could be wrong, but my hunch is that every time you update a block, you will be polluting the database with a new global area name (and there is no garbage collection on area names). After a bunch of updates, anything that lists or selects stacks and global areas could become unmanageable.
chris123uk replied on at Permalink Reply
chris123uk
ye the handles dont update them selves.

if the user made a new module by adding a page with that page type then a now global block is created with the modules collection id

then this modules block with its unique id will be out put in the page lists above the module page.
chris123uk replied on at Permalink Reply
chris123uk
i needed the blocks to be global as i wanted the user to have access to the modules description block and subject block from the lessons page that is below the modules.

this allows the user to update everything from the lessons pages.