Drupal 7 Preprocess Tricks: Tips From a Themer


In the course of a day as a Drupal Themer, I need to code a wide variety of functionality into a given site I'm working on. I try to follow Drupal best practices as well and this usually means implementing theme preprocess functions; these become key to a Themer's toolbox. This article is a selection of snippets I've picked up along the way that might help others out. When I first started building with and theming Drupal several years ago, at first I did not see the value of preprocessing but it's turned out to be quite valuable.

Add JS or CSS with a Pattern Match / Wildcard

This method is ideal if you want to add special or custom JS or CSS files to a specific path with a pattern match or wildcard. For example I might have unlimited URLs associated with a Taxonomy with patterns such as:

/portfolio/cars
/portfolio/trains
/portfolio/architecture
/portfolio/foo

… but then maybe I want to also add this code to some individual pages not associated with the Taxonomy. I can do something like this with a preprocess HTML function.

function MYTHEME_preprocess_html(&$vars) {
  $path = drupal_get_path_alias();
  $pattern = "portfolio/*\nfoo-page";
    if (drupal_match_path($path, $pattern)) {
    drupal_add_js(drupal_get_path('theme', 'MYTHEME') . '/js/jquery.foo.js', 'file');
  }
}

As you can see from the above code, we are adding JS to anything under the path or /portfolio/ but also to a page called foo-page. Note the newline character between the two pattern matches as well as the * which serves as a wildcard. We are also using the Drupal API function drupal_get_ path_alias which returns the alias of an internal path. You can imagine the possibilities using this method which could potentially cut back on the number of scripts being aggregated on any given part of your site.

A Caveat

The one caveat using this method is that you'll want to be sure to add a test to your script instantiation. So for example, in my scripts file, if I am instantiating the above script, I want to be sure to add an if clause, otherwise you run the risk of calling the script when it does not exist on various pages which would in turn throw a nasty error. So you'd want to do something like so:

if($().foo) {

// your script foo here…

}

Weight, Scope and Group

In certain cases, you need to load a script last or set a specific weight to place it at a specific point in relation to other scripts that are loading. This can be achieved by "weighting" and "scoping." Scope has two possible constants, header and footer which are self-apparent, you can either load the script in the head of the page or in the footer after everything else; there's lots of advantages to this in regard to Javascript. For grouping, typically a themer is going to use JS_THEME but there's also two other constants available, JS_DEFAULT and JS_LIBRARY which would commonly be used within a module context. Below is a sample

function MYTHEME_preprocess_html(&$vars) {
drupal_add_js(path_to_theme() . '/js/foo.js',
  array(
    'group' => JS_THEME,
    'preprocess' => TRUE,
    'scope' => 'footer',
    'weight' => '9999',
  )
);
}

Note also that preprocess is set to TRUE as we want this internal script to be aggregated. However, there's some cases where you'd set this to FALSE perhaps in the case of an external JS file. The high weight number would most likely make it load last but it's a good idea to test this with aggregation off on your dev site so you can actually see where and how it loads. Play with the number if you don't get the desired result.

CSS Parameters

You can also weight CSS and it has three group constants available as per the Drupal API page:

  • CSS_SYSTEM: Any system-layer CSS.
  • CSS_DEFAULT: (default) Any module-layer CSS.
  • CSS_THEME: Any theme-layer CSS.

It should be pointed out that the groups themselves have weight so you can really fine tune this using a numbered weight as well as a named group 'weight'.

Browsers

if you still develop for older versions of Internet Explorer (gasp!), there's a nice add_css Parameter called browsers which combines with the drupal_pre_render_conditional_comments function. This is also a theme preprocess_html function. For example, if you want to render an IE8 fixes stylesheet conditionally, you could do something like this:

function MYTHEME_preprocess_html(&$vars) {
// Add IE 8 fixes style sheet.
  drupal_add_css(path_to_theme() . '/css/ie8-fixes.css',
    array(
      'group' => CSS_THEME,
      'browsers' =>
      array(
        'IE' => 'lte IE 8',
        '!IE' => FALSE),
      'preprocess' => FALSE));
}

Here we say that we want this to be a conditional stylesheet for less than or equal to IE8 and false for all others and this would render as:

<!--[if lte IE 8]>
<link type="text/css" rel="stylesheet" href="http://example.com/sites/all/themes/MYTHEME/css/ie8-fixes.css" media="all" />
<![endif]-->

There's plenty of other parameters, options and constants for adding CSS and JS within theme preprocessing functions and I suggest checking out the Drupal API pages, links referenced below. There's your tips from a themer, I'll be back sometime soon with more!

Resources

Tags