How to create a block region for node.tpl.php

Update: appparently, today was the day to write about this. Nedjo Rogers submitted a handbook page that shows a different method of achieving the same end.

For the most part, Drupal 4.7's block system is underutilized. This is a shame; with the proper templating, drupal's block system can become a valuable workhorse. In this tutorial, you will learn:

  1. How to override default functions in the phptemplate.engine
  2. Create new regions to place blocks
  3. Pass a block region into node.tpl.php

By the end of this tutorial, you will have the ability to place blocks into node's like a so:

: cool

As with every tutorial in Extreme PHPtemplate theming, you must be working with drupal 4.7, and some background in PHP. If you have no background in PHP, than I suggest you just play along. You may, god forbid, begin to learn.

Step 1: Override phptemplate_regions() in themes/engines/phptemplate/phptemplate.engine

<?php function phptemplate_regions() {  return array(       'left' => t('left sidebar'),       'right' => t('right sidebar'),       'content' => t('content'),       'header' => t('header'),       'footer' => t('footer')  );}?>

Observe the above code. It generates the regions that allow you to place blocks in the header, content, left sidebar, right sidebar, and footer. In order to create our "article blocks" region, we need to first override this default function in template.php. As some of you may have already noted, this function already contains a "phptemplate_" prefix. Obviously, in order to override this function, we therefore cannot use our normal method of adding that prefix. Luckily, the work around is super easy, and intuitive. Simply replace the phptemplate_ prefix with the name of your theme. This tutorials theme is named "xtreme_theming1", thus our template.php file will look like this:

template.php

<?php function xtreme_theming1_regions() {    return array(        // We'll want to return the default regions        'left' => t('left sidebar'),        'right' => t('right sidebar'),        'content' => t('content'),        'header' => t('header'),        'footer' => t('footer'),        // !!Here's our new region "article blocks"!!        'article_blocks' => t('article blocks')    );}?>

Note that this same method can be used to override any function in phptemplate.engine. Thus, phptemplate_comment($comment, $links = 0), becomes xtreme_theming1_comment($comment, $links = 0). And so forth.

Step 2: send the blocks to node.tpl.php

First, Go to administer->blocks, "admin/block". Assuming you followed step one correctly, you have a new region called "article blocks", available to send blocks to. Enable "recent blog entries", and put it into the "article blocks" region.

Second, go to template.php. Call the "theme_blocks($region)" function, and send the output to node.tpl.php. Below is the proper way to do that:

template.php

<?php function  _phptemplate_variables($hook, $vars) {    /* in this case, a hook refers to the beginning of tpl.php file    Thus, case 'page' affects page.tpl.php. 'node' affects node.tpl.php, and case 'block' would affect    block.tpl.php  */    switch($hook) {        case 'node' :            /* $vars['article_blocks'] is $article blocks in node.tpl.php */            $vars['article_blocks']= theme_blocks('article_blocks');        break;    }    return $vars;}?>

The final step is to print the variable in the node.tpl.php file. I recommend that you place the following code directly above the "node" div

node.tpl.php

<?php /* LOOK! */ if ($article_blocks) { ?> <div id="article_blocks"> <?php print $article_blocks;?> </div> <?php } ?>  <div class="node<?php if ($sticky) { print " sticky"; } ?><?php if (!$status) { print " node-unpublished"; } ?>"> ...

Now, click save, and see your new node.tpl.php block region in all its glory:

Step Three: Take Care of the Loose Ends

We have two problems. One we don't want to show the article_blocks region, unless you're viewing the entire node. Second, our article block... to be frank.... looks like crap.

Below, we've gone ahead and taken care of problem one by instructing phptemplate to only return "$article_blocks" when $page doesn't equal zero ($page equals zero when you are not view full nodes). Here's the full template.php file for this tutorial below:

<?php function xtreme_theming1_regions() {    return array(        // We'll want to return the default regions        'left' => t('left sidebar'),        'right' => t('right sidebar'),        'content' => t('content'),        'header' => t('header'),        'footer' => t('footer'),        // !!Here's our new region "article blocks"!!        'article_blocks' => t('article blocks')    );}function  _phptemplate_variables($hook, $vars) {    /* in this case, a hook refers to the beginning of tpl.php file    Thus, case 'page' affects page.tpl.php. 'node' affects node.tpl.php, and case 'block' would affect    block.tpl.php  */    switch($hook) {        case 'node' :            /* $vars['article_blocks'] is $article blocks in node.tpl.php */        if ($vars['page'] /* the equivolent of $page in node.tpl.php */ != 0) {             $vars['article_blocks']= theme_blocks('article_blocks');        }        break;    }    return $vars;}?>

Extra: The CSS to make it look like it look halfway Decent.

The following CSS rules will make your block look like they do in the opening screenshot:

/* CSS Document */#article_blocks { float:right; width:300px; font-size:0.9em; border:1px solid #cccccc; margin:0 12px 12px 12px;}#article_blocks .block { width:100%; margin:6px;}#article_blocks ul li  {width:100%;}

Comments

Region placement, question

How does the region 'know' where it should be displayed?

I have a Theme with a primary links menu partway down. Not at the very top like the default.
I want it to use Nice Menus, so I guess I have to make a new region for it. It will be seen on every page (not just in particular nodes) so I guess I use page.tpl.php.

I see how to create the region, and have a Nice Menus block use it, and have that block inherit from primary links, but I don't see how it gets the information about the *style/location* of the primary links. Which I guess means, the name of the div containing the primary links. Of course that's in style.css, but how does that info get to the Admin/Block section?

Thank you.

Support / Questions...

Thank you for a great website. I wish you had done all documentation on drupal ;-)

First of all I am new to php and havnt done this region- yet.

I need to have following regions (to small regions in the bottom) on all my content pages:

...........
. .
. content .
. .
. .
...........
. R1 . R2 .
...........

These small regions in the bottom is for inserting blocks/views.

I need to be able to tell each block on which sites it should go into (just as standard in drupal). As I read your splented documentation, I'll just get a new region to place my block into and I thereby assume that I will have the same functionallity how to place the block.

My question is therefor:

1) Is this the right/smartest way of getting my regions on all nodes + books?
2) How do I get the two regions besides each other and not in a row (php/css)?

Might be simple basic, but as mentioned I am new to php and have only done some little css

Thank you in advance.
Jakob

Answer to 1. If you you've

Answer to 1.
If you you've declared your regions in phptemplate, and put them in a page.tpl.php file, than they will always be there (unless you hide them in admin/build/block). What's different here is that we are putting it in a node.tpl.php... so the blocks will never show unless a node is being viewed in page view. (jesus, I feel like I might as well be speaking klingon at this point....)

Answer to 2.
This is relatively easy. But don't listen to my nonsense, here's a quality resource to teach you how divs sitting on top of each other become side by side: Floattutorial. I encourage you to study these examples as they will provide more than an answer to this specific question...

nick, u rock!

thanks a lot, nick, i love this code snippet, keep going,

A litte problem

Hi Nick
I added a new region following the steps from your tutorials. Its very much there in the placement combobox but cannot see the region. Can you help..

bantei

Think I get crazy

Servus, Nick. That tutorial looks great -- if I could only get it to work. Must be something really stupid going on... here is how it looks on your page: <?phpfunction  _phptemplate_variables($hook, $vars) {    $vars_return=array();    switch($hook) {        case 'node' :        if (arg(1) != "add" || arg(2) != "edit")) { // Seems here's one ')' too much...            if ($vars['page'] != 0) {               $vars_return['article_blocks']= theme('blocks', 'article_blocks');            }        }        break;    }    return $vars_return;}?> Well, except that closing bracket, things seems fine here. Except one thing: I have to disable the inner "if ($vars... != 0) {" condition or I would get a blank screen. I do a print_r($vars['page']); in the line above the switch and it prints nicely. but when I use it in that conditional statement, a blank page results. Is there a hidden thing in PHP? I'm new to it, but spent some years coding with C, C++, Java, JavaScript and somme more, so I can't believe there's voodoo happening -- but it seems so. Any ideas? Thanks, Norbert (Drupal 4.7.3, PHP 5.1.4)

Disregard Previous Message

I don't know what I did to fix it but it works now. I started from a clean template copy. I think it must have been something I did wrong in a previous tutorial.

Matthew Pare

First Tutorial I have had trouble with, could you please help.

Nick I read several different portions of your site and have enjoyed your work. You are a valuable asset to everyone. Your presence is posted in countless articles. I just want to say thank you now and thank you for tomorrow.

Now to my question. I am sure that I am missing something very simple. The problem that I am experiencing is not limited to this tutorial but only discovered when I assigned my block to the article blocks. After saving blocks nothing displays. I can manually go back and I receive the following error.

warning: Cannot modify header information - headers already sent by (output started at /long_path/themes/bluemarine/template.php:17) in /long_path/includes/common.inc on line 266.

Now this problem only occurs when I send the blocks to node.tpl.php. When I copy the code from step 2 into my template.php file. I have found that either from your drop down menu tutorial or your user login, I'm not sure which at the moment, but I discovered that I had a problem while doing this tutorial.

<?phpfunction  _phptemplate_variables($hook, $vars) {    /* in this case, a hook refers to the beginning of tpl.php file    Thus, case 'page' affects page.tpl.php. 'node' affects node.tpl.php, and case 'block' would affect    block.tpl.php  */    switch($hook) {        case 'node' :            /* $vars['article_blocks'] is $article blocks in node.tpl.php */        if ($vars['page'] /* the equivolent of $page in node.tpl.php */ != 0) {             $vars['article_blocks']= theme_blocks('article_blocks');        }        break;    }    return $vars;}?>

I appreciate your help. Sorry that I was not concise.

-Matt

gah so much cyborg reading

gah so much cyborg reading material here, they should just upgrade flexiblock

I’m not sure I see how

I'm not sure I see how flexiblock would make this matter easier...

buggy?

hi great howto, but it causes me problems with the node previews. <?phpfunction  _phptemplate_variables($hook, $vars) {    $vars_return=array();    switch($hook) {        case 'node' :            if ($vars['page'] != 0) {            $vars_return['article_blocks']= theme('blocks', 'article_blocks');        }        break;    }    return $vars_return;}?>

Try this: <?phpfunction 

Try this:

<?phpfunction  _phptemplate_variables($hook, $vars) {    $vars_return=array();    switch($hook) {        case 'node' :        if (arg(1) != "add" || arg(2) != "edit")) {            if ($vars['page'] != 0) {               $vars_return['article_blocks']= theme('blocks', 'article_blocks');            }        }        break;    }    return $vars_return;}?>

Hey Nick great

Hey Nick great tutorials. Thanks. P.S. Would be easier on the eyes if the screenshots were a tad bigger.

True previously implemented

I am not sure who found this first, but I have an implementation of this on my website (I have different regions like the one with a top banner on the homepage, or the two left/right sections below the body). The object of my comment is to underline your assertion that this technique frees theme developers fromt he structure of header,footer,left,right,content

Thanks a lot!

Hey Nick! ¡You have no idea how much i apresiate this tutorials you´ve made! Thanks you so much! they are great and show the huge potencial of drupal in an easy manner! Thanks!

+1

Really good tutorial series Nick. Thanks for sharing your knowledge.

I’ve learned more here in

I've learned more here in 5 mins, than i did after a few months on the official drupal site. Well admittedly, i just copied and pasted a lot and begged people for help. Nick Lewis, you're a good writer, i don't know how good you're coding is, not being one, for all i know, everything you have written here could very well not work. But there's one thing i can relate to, is pretending i know what i'm talking about. Rock on.

The load problem

You can solve the load problem by overriding theme_blocks and caching it. Then there'll be almost no load issues at all.

How does this compare load-wise with

http://drupal.org/node/29139 Nedjo goes with an array and defines the variable from a different direction. Six of one, half dozen of the other? I am truly enjoying your series, Nick. This is great stuff!!! Thank you!

Its half a matter of taste

Its half a matter of taste -- I haven't compared performance with the two techniques. Both techniques I suppose will work (haven't tested Nedjo's). To tell you the truth, I'm not sure I understand the rationale behind Nedjo's approach. So, for now, all I can say is, "I like mine, because its easier on the eyes".