Need some help with your project? Contact me

Add a block in the middle of a node Body field in Drupal 7

Have you ever wondered how you can get a block to display smack down in the middle of your Body content? Say you write articles and these get displayed like normally in the Content region. You can add blocks to regions around it but only if your theme has them declared or if you did that yourself in the template of with Display Suite. And the cat is cute.

What you cannot so easily do is have a block displayed on each Article node in the middle of your Body. Not even with Display Suite. If you know a little .php however, it is not so difficult. And of course if the node.tpl.php file does not scare you.

This is what I did for my Article Content Type. I created a dedicated node.tpl.php file for the Article Content Type by copying node.tpl.php and renaming the new file node--article.tpl.php. You can do this also for you Page Content Type and any other you may have - in the same naming style.

I searched for the following .php line print render($content); and commented it out. Note that this line outputs the Body field of all the Article nodes on your site. If you comment it out on your production website, none of your Article nodes will have any Body fields till you are finished with this entire process. So make sure you work first in your development environment, perform adequate testing there and then make all the changes at once.

Next, I added a new region to my theme called new-region (Of course change the name to whatever you want).

The reason I did this is so that I can create a block of content in the Drupal UI and assign it to this region. This will in turn be called with .php in the middle of the Article Body fields. So after this, I went back to my article--note.tpl.php and declared a new variable ($added_string) containing said call for the region:

$added_string = render(block_get_blocks_by_region('new-region'));

Next, I used a .php command to break up the render version of the $content variable (which holds the Body text). Seeing that this text is mostly a sequence of paragraphs, I broke it up at each paragraph and stored all the resulting pieces in the array named $content_array:

$content_array = explode("<p>", render($content));

UPDATE: Here if you have more fields in your content type and you want to add your block in the middle of the body field - which is expected to be simple html - you should explode only the specific body array element, like so:

$content_array = explode("<p>", render($content['body']));

OK, so what I wanted to do is have the block display roughly in the middle of the Body field. It is difficult to be precise given that you cannot break up the $content variable exactly in the middle. The .php command above, however, created an array with a number of elements (and since we used the paragraph as the separator) we can also deduce that $content_array is now an array of all the paragraphs in the Body.

Now, we find out how many paragraphs it has and divide that number in 2 to figure out where we want to insert the block content (after how many paragraphs). For this you can also set a number of your own, but in my case I wanted the block to be more or less in the middle, no matter how long the Article content got:

$content_array_half_size = count($content_array) / 2;

The above command retrieved the half of the total number of items (paragraphs) in the array and stored that number in the variable called $content_array_half_size. Next, I used another command to insert the region I wanted (now found in the variable $added_string) into the Body array ($content_array) placing it after the item that equals to the number representing half of the total items:

array_splice($content_array, $content_array_half_size, 0, $added_string);

And finally, I needed to recreate the string to be outputted as the Body field because currently $content_array is an array which holds a number of paragraphs - with the block included in the middle:

$final_content = implode("<p>", $content_array); 

As you notice, I used the same selector ("<p>") as criterion to implode the array elements. And now the $final_content variable holds a big string with our Body and block in the middle of it. All we need to do is print it out:

print $final_content;

OK, so after saving this file and adding your block to that region in your Drupal administration interface, you can test. If you are satisfied, you can go ahead and implement these changes on your production site.

You could of course not use a block as a content holder to be placed in the middle of the Body. You can hardcode in the node--article.tpl.php file the $added_string to whatever you want. But using a block in a region gives you then the opportunity to always return to the Drupal UI to show/hide that block based on various dependencies: page, role, or even add more blocks to that region. Also, you can use the Context module to disable the region itself etc. And that is cool.

Hope this helps.

Comments

Thank you, you're tutorial was of great help. I did however not use the template files but used template_preprocess_node(&$variables,$hook). You can use it in template.php or a custom module.

Instead of render($content), I update the body text in $variables['content']['body'][0]['#markup'] and made a switch command based on $variables['type']. Maybe not the nicest solution but it prevents multiple template files with php in it.

But for the ones who do not want to go into the code there is always your module. Thanks again.

Yes,

Check out my module Block Inject I wrote for this use case in the meantime :)

D

Hey, thank you so much for this tutorial! I had to do exactly the same and already figured it could work something like this but your code definitely was a big time-saver. :)

Could you ad an image of your node.tpl.php with the above code in it?

Thanks,

Mike

Add new comment

You can post comments in Markdown and basic HTML tags.
For code blocks, wrap your code within '~~~'. For example:
~~~
$var = 'my variable';
~~~