The Joys Of Preprocessing

Having fun with preprocess functions in Drupal 6

Photo of Greg Harvey
Tue, 2008-09-23 11:37By greg

I've been having a lot of fun with preprocess functions in Drupal 6.x, particularly when theming Views. It's a great system, but my colleague came across a nice "gotcha" this morning. We have been adding JavaScript in Views preprocess functions if we want to provide tidy jQuery interfaces for Views output. This works great, so we thought nothing of doing the same for pages, which is where we came unstuck. To understand why, you need to understand the process order of preprocess functions, as defined here: http://drupal.org/node/223430 Following the logic in the above link, the preprocess function order for a page is something like this:

  • template_preprocess
  • template_preprocess_page
  • yourmodule_preprocess_page
  • yourtheme_preprocess_page

We also need to understand how drupal_add_js() works. It builds an array called $javascript and each time it is called it adds another item to that array - one item for each time it is called. Just before the page is rendered, Drupal calls a function called drupal_get_js() which renders a HTML line for each item in the $javascript array that drupal_add_js() built.

The key thing is drupal_get_js() is called only once - in template_preprocess_page(), in this line:

 

$variables['scripts'] = drupal_get_js();
?>

Consequently, if you add JavaScript using a drupal_add_js() call in yourmodule_preprocess_page() or yourtheme_preprocess_page() then it *will* be added to the $javascript variable, but it will be too late, because it will be added *after* drupal_get_js() has been called to render the mark-up for the JavaScript to be presented on the page.

The solution?

You can either put your JavaScript elsewhere, somewhere which will render before template_preprocess_page() - a hook_menu() callback function would be a good candidate, for example, if this is possible. Or you can still use a drupal_add_js() in your module's page preprocess function, but you must rebuild the 'scripts' variable, like so:

$base = drupal_get_path('module', 'yourmodule');
drupal_add_js($base . '/js/nav-effect.js');
$variables['scripts'] = drupal_get_js();
?>