Understanding advance page template preprocessing

The main role of the page preprocessor is to set up custom variables to be rendered through the template (.tpl.php) files. Mostly the page preprocessing is used to handle theme template suggestions. This means that based on some custom logic we can suggest any page--*.tpl.php file instead of generic page.tpl.php but this is not the limit, most advance developers use these preprocessors to do heavy calculation of their logic and then pass the results to the page.tpl.php in form of some custom variable, this avenue has endless possiblities.

Drupal 7 framework allows numerous preprocessors for each theming hook(page, node, field) but here we are only going to address page.tpl.php. Every layer in Drupal frame work from core, modules, engines and themes can have one page preprocessor, each layer is progressively building variables before being rendered through template files. As I described above this helps in keeping the markup clean and easy to work with inside templates by placing most of the logic inside page preprocessors.

Lets have a look at page preprocessors on each layer and their order in which they build variables.

  1. template_preprocess_page
    The module or core file that implements the theming hook supplies this. The initial generation of all the variables specific to the page is usually done here.
  2. [moduleName]_preprocess_page
    This one is little bit confusing, lets say this one is used by all modules that were not shipped with Drupal, this includes all contrib and custom in house modules. This allows modules that did not originally implement the hook to influence the variables
  3. [engineName]_engine_preprocess_page
    Normally its phptemplate_engine_preprocess_page preprocessor for theming engines
  4. [engineName]_preprocess_page
    This one is NOT RECOMMENDED but this usually is the first preprocessor that can be used inside the theme. It can be named after the theme engine the theme is running under, so as stated in 3 this function will look like phptempate_preprocess_page
  5. [themeName]_preprocess_page
    This one is named after the theme itself and this one is the last one that can be used to amend variables that are going to be rendered on page.tpl.php. This is 

There are many possibilities here for modifying the variables. In most cases, it is only the first preprocessors that exist. The first adds the default baseline variables and adds a set specific to the theming hook. In normal circumstances you have your preprocessor on 2 or 5 where you play with the logic and assign a custom variable to $variable['customvariable'] array.

Theme Template Suggestions:

One of the main reason we use page preprocessors in our modules and themes is to suggest different page template that normally does not comes with Drupal Core. Just to let you know following are the template suggestions that are part of Drupal 7. page--[front|internal/path].tpl.php

base template: page.tpl.php

The suggestions are numerous. The one that takes precedence is for the front page. The rest are based on the internal path of the current page. Do not confuse the internal path to path aliases which are not accounted for"page--front.tpl.php" for it.

  1. page--node--edit.tpl.php
  2. page--node--1.tpl.php
  3. page--node.tpl.php
  4. page.tpl.php

Following code snippet will let you know how to add page templates based on node-types, taxonomy-vocabulary and taxonomy-term.

/**
 * @file template.php
 */

function mytheme_preprocess_page(&$variables) {
   //dsm($variables); // Just in case you want to see whats in this variable, this function works if devel module is enabled

 
 if (isset($variables['node']->type)) { // Check to see if the page being viewed is of type node
    $nodetype = $variables['node']->type;
    $variables['theme_hook_suggestions'][] = 'page__node_type__' . $nodetype;
 }

 if(arg(0) == 'taxonomy' && arg(1) == 'term' && arg(2) && !arg(3)) { // Check to see if the page being viewed is a vocabulary-term page

    $term = $variables['page']['content']['system_main']['term_heading']['term']['#term'];
    if(is_object($term)) {
      $variables['theme_hook_suggestions'][] = 'page__taxonomy__'.$term->vocabulary_machine_name; // Template suggestion based on vocabulary name
      $variables['theme_hook_suggestions'][] = 'page__taxonomy__'.$term->vocabulary_machine_name.'__'.$term->tid; // Template suggestion based on vocabulary term name
      $variables['term'] = $term; // Also pass this $term variable to page template so this can be used if further logic is required
    } 
  }
}

 Custom Breadcrumbs in page preprocessor

I would play with my page breadcrumbs in page preprocessors, I can have different variations of logical breadcrumbs here. Lets see the code how this can be achieved in a more structured way.

/**
 * @file template.php
 */
function mytheme_preprocess_page(&$variables) {
 
  //dsm($variables);
  if (arg(0) == "aboutus" && !arg(1)) { // lets see if its a page generated through views.
    $object = new stdClass();
    $object->type = 'aboutus';
    _mytheme_set_breadcrumb($object, 'view-page'); //internal function to setup logical breadcrumbs.
  }

  if (isset($variables['node']->type)) {  
    _mytheme_set_breadcrumb($variables['node'], 'node');
  }
 
  if(arg(0) == 'taxonomy' && arg(1) == 'term' && arg(2) && !arg(3)) {
    $term = $variables['page']['content']['system_main']['term_heading']['term']['#term'];
    if(is_object($term)) {
      $variables['term'] = $term;
      _mytheme_set_breadcrumb($term, 'term');
    }
  }
}

function  _mytheme_set_breadcrumb($object, $type) {
  $breadcrumb = array();
  $separator = "  >  ";
  if ($type == 'term') { // If the object is a taxonomy term
    if($object->vocabulary_machine_name == 'country') { // Lets say its country vocabulary
      $breadcrumb[] = l('Home', '<front>');
      $breadcrumb[] = t('Country'). $separator .drupal_get_title();
     
    }     
  }

  if ($type == 'node') {   // If the object is a node
    $breadcrumb[] = l('Home', '<front>');
    if ($object->type == 'page') { // If the node is of type 'page'
       $breadcrumb[] = 'Site Page';
       $breadcrumb[] = drupal_get_title();
    } 
    else {
       $breadcrumb[] = $object->type;
       $breadcrumb[] = drupal_get_title();
    } 
  }

  if ($type == 'view-page') {
    if ($object->type == 'aboutus') {
      $breadcrumb[] = l('Home', '<front>');
      $breadcrumb['active'] = t('About Us');
    }
  }
  // Set Breadcrumbs
  drupal_set_breadcrumb($breadcrumb);
}