Split up your Drupal preprocess functions

Fredrik Johansson
Drupal stories
Published in
2 min readFeb 12, 2016

--

Right now I’m working on a website built with Drupal 7 in my work at Cerpus. I’m not a Drupal pro, but I have been using it sporadically for the last several years, since Drupal 6. For me, one of the most complex parts of the Drupal CMS has been the templating engine and the theme hooks.

I like to work with preprocess functions and template files, but although the latter are selected and loaded based on the theme hook suggestions, the former are not. So they tend to become huge blobs with switch statements. To circumvent this I created a utility function to make it easier to split your preprocess functions into smaller parts and make 1-to-1 correspondences between preprocess functions and template files.

function utils_preprocess_all_hooks(&$variables, $caller=NULL, $prefix=NULL) {
if(!$caller) {
$caller = debug_backtrace()[1]['function'];
}
if(is_null($prefix)) {
$prefix = explode('_preprocess_', $caller)[0];
}
$hooks = array();
if(!empty($variables['theme_hook_original'])) {
$hooks[] = $variables['theme_hook_original'];
}
if(!empty($variables['theme_hook_suggestions'])) {
$hooks = array_merge(
$hooks,
$variables['theme_hook_suggestions']
);
}
$hooks = array_unique($hooks);
foreach($hooks as $hook) {
$func = $prefix.'_preprocess_'.$hook;
if(function_exists($func) && $func != $caller) {
call_user_func_array($func, array(&$variables));
}
}
}

Create the regular preprocess in your theme and then add a call to utils_preprocess_all_hooks inside it, like this:

function MYTHEME_preprocess_node(&$variables) {
utils_preprocess_all_hooks($variables, __FUNCTION__);
}

The function looks through theme_hook_original and theme_hook_suggestions and runs a preprocess function for each one, if it exists. So given an “article” node, it will look for these function or something similar:

MYTHEME_preprocess_node__article
MYTHEME_preprocess_node__106
MYTHEME_preprocess_node__article__full

Be sure to send in the __FUNCTION__ magic constant for performance. Otherwise debug_backtrace will be used to get de caller. This is to prevent utils_preprocess_all_hooks from calling the caller again, creating an infinite loop. The $prefix argument will be derived from the caller name, but you can provide it as well.

Hope you like it! Feel free to share and comment.

--

--