Creating a Simple concrete5 Wrapper Custom Block Template (Without Duplicating Code)
Concrete5 / January 20, 2010
While wrapping up a site for a client, I encountered a problem that I decided to solve in new, more sensible way. You see, the client's concrete5 theme – as many do – has a sidebar with some special properties and CSS classes that differ a bit from the main content area. With this in mind, blocks of content and functionality, when added to the sidebar, need to be wrapped in some extra DIVs, to add additional style and padding to the content.
That's easy, right? That's concrete5 101: just create a custom template for your block, and apply that to your block. Copy the view.php file from your core block into your local directory, and apply the changes there. Easy as pie! Right?
There's a problem with that approach. Read on for more.
Custom Template Views: All or Nothing
While the approach above is great and allows for endless flexibility, it's an all-or-nothing option: you have to copy all of the block's view template into your current directory, and work on the template that way. This is great when you want to make fundamental changes to the way the block appears, but when you just want to wrap the block in some content, and leave the block's actual view template unchanged, it's a bit cumbersome.
Furthermore, the two blocks I was working with were the form and the survey blocks. The view templates for these blocks are not lightweight. Plus, these blocks are complex. If the core view templates change in the future, I may miss out on some additional styles or features, having forked the entire template. It seemed like a bit much, since all I wanted to do was wrap the entire contents of the block in two DIVs.
Fortunately, there's an easy solution to this problem.
Create a custom template like you would at any other point. Within this custom template, add the new DIVs required by the special custom template. Within the DIV, instead of cutting and pasting the entirety of the block's view template, cut and paste this instead:
<? $bvt = new BlockViewTemplate($b); $bvt->setBlockCustomTemplate(false); include($bvt->getTemplate()); ?>
I'll walk you through what's going on here. First, we instantiate the BlockViewTemplate class, with our current block's object passed into the constructor. This object is the $b object, and it is always in the scope of a block's view template.
Next, we call setCustomTemplate method for the block's view template, and pass false as its argument. Why? If we didn't do this, we'd have an infinite loop on our hands. That's because the block object we're currently working with already has a custom template. That's the template that we're rendering right now! So what we're doing here is basically refreshing the current block, and grabbing the template for the block when a custom template is not activated.
Finally, once complete, we call getTemplate() to return the block's template before a custom one was set. For the form, this will be /path/to/concrete/blocks/form/view.php. We include this, confident that it will continue to work and remain up to date in the future, and knowing we didn't have to duplicate a large amount of view code just to do something simple.