Tuesday, January 29, 2013

A Block to the Head (in Drupal 7)

This is going to be a super specific & technical post, because it took me way too long to figure out how to do this & someone else could probably stand to benefit from it. For the tl;dr skip to the code section.

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 of block_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.

Saturday, January 12, 2013

Openness as an Excuse

I briefly, and somewhat poorly in my own opinion, tried to explain how the openness of the Code4Lib community was being used as an argument against anonymous proposal voting. Well, the latest First Monday has an article titled "'Free as in Sexist?' Free Culture and the Gender Gap" wherein Joseph Reagle makes my point in a far more articulate manner:

At first, the claim that community openness can contribute to a gender gap seems nonsensical as there are no formal restrictions on participation. However, as Freeman (1996) argued, implicit structures and dynamics still exist in the absence of formal ones. For example, a computer science department may not have an exclusionary policy towards female students, but privileging a narrow and obsessive focus might miss female candidates. Similarly, while some might argue any effort to block problematic users is a step away from openness, a chaotic culture of undisciplined vandals would equally disenfranchise those who wish to make a positive contribution [12]. Hence, following Freeman, one might distinguish between formal and informal forms of discrimination. While an open community does not formally discriminate, alienating behavior can still manifest from difficult people and sexist behavior.
The article goes much further (this is just the introductory paragraph of the section that discusses this phenomenon).

Philosophical Digression

To me, using the innate value of openness as an excuse to avoid something empirically proven to increase participation from marginalized groups is a specifically ethical failure. It comes from a deontological stance, as if some spurious and undefined essence of openness is more important than the effects of a particular instance of openness. The antithesis to deontology is consequentialism, which argues that an act's value lies only in its effects or consequences. There is no such thing as innate value.

The article's reference to blocking problematic users is particularly apt; I just finished reading a book on Wikipedia which discusses how Wikipedia's ideal of "the encyclopedia anyone can edit" is worth sacrificing precisely in such a situation. The world's most open encyclopedia blocks users and is better for it. An open community can have a closed sub-community support group and be better for it as well.