The Scenario
In general, the<head>
of your HTML document is not editable in Drupal. The <title>
changes to reflect what page you're on, sure, & tags are added or removed by modules frequently, but you can't tweak the markup in the same way you can the contents of a block or main content. For the most part, that's fine; 90% of the <head>
should stay the same from page to page, such as site styles & must-have <meta>
tags like viewport
. If you need to change something site-wide, that can be done through theme templates. But sometimes that's not enough; what if I want to add different <meta>
tags to different pages? Or load variegated builds of Modernizr on variegated pages? Or use a special font on a set of pages? There are numerous reasons why you might want a specific subset of pages to have a bit of custom markup; in short, you want to put one of Drupal's blocks in the document's <head>
. Without further ado, here's how you do that.The Code
In yourtheme.info, find the list of regions & add one for your new<head>
region:regions[html_head] = HTML Head
The name that you'll use in the code has to be a valid PHP variable name, so no spaces.In your theme's template.php, add the following to the
yourtheme_preprocess_html
function:$variables[ 'html_head' ] = block_get_blocks_by_region( 'html_head' );
If you're using a subtheme without a template.php, you can create it & write the function like this:function mastertheme_subtheme_preprocess_html(&$variables) {
/* so that html_head is available in html.tpl.php */
$variables[ 'html_head' ] = block_get_blocks_by_region( 'html_head' );
}
In html.tpl.php, your theme's HTML template, find the spot where you want the block's markup to be inserted & add:
<?php if ( $html_head ): ?>
<?php print render( $html_head ); ?>
<?php endif; ?>
If you're using a subtheme where html.tpl.php doesn't exist, copy the master theme's html.tpl.php into the templates directory & then add the above.Right now, that would be enough to insert some code into the
<head>
but the code will likely be wrapped in problematic tags that don't belong in the <head>
like <div>
& <section>
. To get rid of that junk, we create a new region-specific block template that only prints out the contents of the block & nothing else. Create a block--html-head.tpl.php file & put it in the templates directory with the following line as its only contents:<?php print $content; ?>
Now clear the cache & add a block to the new region; it should appear in your site's <head>
.If you've named your block something other than "html_head" then you'll need to change the references throughout, but this should work for any Drupal 7 site. Note that if you rename a region (or perhaps otherwise screw with its templates? not entirely clear to me), all the blocks you had previously assigned to it become unassigned. That was what wasted the majority of my time; I couldn't understand why my block wasn't showing up when the
$html_head
variable should have been available but the block had been unassigned during my shenanigans.The References
The Drupal Answers thread Printing regions in html.tpl.php provided most of the special sauce for this one, specifically the idea to store the return value ofblock_get_blocks_by_region
in a variable that's accessible later when html.tpl.php runs.The
template_preprocess_html
, block_get_blocks_by_region
, & html.tpl.php API documents all provide useful reference material.Lastly, the
drupal_add_html_head
function appears to provide another avenue to the same destination. However, it's much more convenient to store markup in a block. I also want to write straight HTML & not Drupal's weird "renderable array" content, which is what the function takes as a parameter.