You are here

regions.module in Regions 6

Same filename and directory in other branches
  1. 7 regions.module

Add regions to the screen that are cross-theme compliant

File

regions.module
View source
<?php

/**
 * @file
 * Add regions to the screen that are cross-theme compliant
 */

/**
 * Implementation of hook_help().
 */
function regions_help($path, $arg) {
  if ($path == 'admin/help#regions') {
    return '<p>' . t('Regions adds regions that are cross theme compliant.  This way you can add blocks to any number of areas of the screen without having to define them in your themes.') . '</p>';
  }
}

/**
 * Implementation of hook_perm().
 */
function regions_perm() {
  $regions = _regions_list();

  // Generate a list of regions and permissions.
  foreach (array_keys($regions) as $region_name) {
    $perms[] = 'view ' . $region_name . ' region';
  }
  return $perms;
}

/**
 * Implementation of hook_init().
 */
function regions_init() {

  // Check for current theme.
  init_theme();
  global $theme_key;
  $regions = _regions_list($theme_key);
  foreach ($regions as $region_info) {

    // Add optional js files if defined.
    if (isset($region_info['js'])) {
      drupal_add_js($region_info['js']);
    }

    // Add optional stylesheets if defined.
    if (isset($region_info['css'])) {
      drupal_add_css($region_info['css']);
    }
  }
}

/**
 * Implementation of hook_footer().
 *
 * @todo consider implementing drupal_set_content() so we can use theme_blocks()
 *
 * @todo for D7 use hook_page_alter().
 */
function regions_footer($main = 0) {

  // Check for current theme.
  init_theme();
  global $theme_key;
  $regions = _regions_list($theme_key);

  // Regions the user has access to are added the end of the site.
  $output = '';
  foreach ($regions as $region_name => $region_info) {

    // Check for access to regions.
    if (user_access('view ' . $region_name . ' region')) {
      $region = array();

      // Get themed blocks string.
      $blocks = _regions_blocks($region_name, $region_info);
      if (isset($blocks)) {
        $region['start'] = '<div id="' . $region_name . '" class="regions">';
        $region['blocks'] .= $blocks;
        $region['end'] .= '</div>';
      }

      // Allow other modules to alter the region array before the each element
      // is concatenated into a single HTML string.
      drupal_alter('regions_region', $region, $region_name);
      $output .= !empty($region) ? implode('', $region) : NULL;
    }
  }
  return $output;
}

/**
 * Implementation of hook_system_info_alter().
 */
function regions_system_info_alter(&$info, $file) {
  if (isset($info['regions'])) {
    $list = module_invoke_all('define_regions');

    // Add the regions into the definition typically only provided by the theme
    // layer.
    if (count($list) > 0) {
      $info['original_regions'] = $info['regions'];
    }
    foreach ($list as $machine_name => $region) {
      $info['regions'] += array(
        $machine_name => $region['title'],
      );
    }
  }
}

/**
 * Helper function lists newly defined regions against regions already declared by a theme.
 *
 * @param $theme_key
 *   A theme key to check against. Defaults to current theme.
 *
 * @return
 *   An array keyed by region identifier, containing:
 *   - title: the region title
 *   - css: optional path to stylesheet for theming the new region, relative to
 *     implementing module directory.
 *   - js: optional path to javascript file, relative to implementing module
 *     directory.
 *   - render_callback: optional function to use in rendering blocks of this
 *     region (will be passed 'block' and $block parameters).
 *   Or an empty array.
 */
function _regions_list($theme_key = NULL) {
  if (!isset($theme_key)) {
    init_theme();
    global $theme_key;
  }

  // Tap the stored info file for the original_regions variable.
  $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
  if (isset($info['original_regions'])) {
    $theme_regions = array_map('t', $info['original_regions']);
  }
  else {
    $theme_regions = array_map('t', $info['regions']);
  }

  // Allow modules to define new regions.
  $defined_regions = module_invoke_all('define_regions');

  // Build an array of new regions, if defined ones don't already exist.
  $new_regions = array();
  if (!empty($defined_regions)) {
    foreach ($defined_regions as $key => $value) {
      if (!in_array($key, array_keys($theme_regions))) {
        $new_regions[$key] = $value;
      }
    }
  }
  return $new_regions;
}

/**
 * Helper function to get a list of blocks per region, as provided by core block and context modules.
 *
 * @param string $region_name
 *   The region identifier.
 * @param array $region_info
 *   An individual element child of the array returned by _regions_list().
 *
 * @return
 *   A string containing the rendered blocks for this region.
 *
 * @see _regions_list()
 * @see regions_footer()
 */
function _regions_blocks($region_name, $region_info) {

  // Update the {blocks} table with the blocks currently exported by modules.
  _block_rehash();
  $blocks = array();
  if (module_exists('context') && function_exists('context_get_plugin')) {
    $blocks = context_get_plugin('reaction', 'block')
      ->block_list($region_name);
  }
  else {
    $blocks = block_list($region_name);
  }

  // Allow other modules to alter the blocks array before the each block object
  // is rendered by theme_block().
  drupal_alter('regions_blocks', $blocks, $region_name);

  // Render the array of blocks using either an optional module-provided
  // callback, or the default theme('block', $block).
  $render_callback = isset($region_info['render_callback']) && function_exists($region_info['render_callback']) ? $region_info['render_callback'] : 'theme';
  $output = '';
  foreach ($blocks as $block) {
    $output .= call_user_func_array($render_callback, array(
      'block',
      $block,
    ));
  }
  return $output;
}

/**
 * Implementation of hook_theme_registry_alter().
 */
function regions_theme_registry_alter(&$theme_registry) {

  // Remove any existing instances of our pre page preprocessor.
  $position = array_search('regions_preprocess_pre_page', $theme_registry['page']['preprocess functions']);
  if ($position !== FALSE) {
    unset($theme_registry['page']['preprocess functions'][$position]);
  }

  // Add an additional page preprocess function prior to template_preprocess_page()
  $position = array_search('template_preprocess_page', $theme_registry['page']['preprocess functions']);
  if ($position !== FALSE) {
    array_splice($theme_registry['page']['preprocess functions'], $position, 0, 'regions_preprocess_pre_page');
  }
}

/**
 * Preprocessor that runs *before* template_preprocess_page().
 */
function regions_preprocess_pre_page(&$vars) {

  // stub for now
}

/**
 * Implementation of hook_preprocess_page().
 */
function regions_preprocess_page(&$vars) {
  global $theme_key;
  $regions = _regions_list($theme_key);
  foreach ($regions as $region_name => $region_info) {

    // Check for access to regions.
    if (user_access('view ' . $region_name . ' region')) {
      $vars['body_classes'] .= " bclass_enabled_{$region_name} ";
    }
  }
}

Functions

Namesort descending Description
regions_footer Implementation of hook_footer().
regions_help Implementation of hook_help().
regions_init Implementation of hook_init().
regions_perm Implementation of hook_perm().
regions_preprocess_page Implementation of hook_preprocess_page().
regions_preprocess_pre_page Preprocessor that runs *before* template_preprocess_page().
regions_system_info_alter Implementation of hook_system_info_alter().
regions_theme_registry_alter Implementation of hook_theme_registry_alter().
_regions_blocks Helper function to get a list of blocks per region, as provided by core block and context modules.
_regions_list Helper function lists newly defined regions against regions already declared by a theme.