front and back-end web development, Leeds, UK


Richard's Blog - Design, coding and life in Japan

Richard

Creating multiple blocks easily in a Drupal module

 In my latest Drupal project, we needed to be able to easily add new blocks to the main module based application, but also to be able to them easily in the theme folder. The theme based block templates will be altered regularly by designers to fit is with the site and its style. The module specific blocks will not be changed as it is a part of the applications core.

I will refer to the module name as MYMODULE and the theme name as MYTHEME from now on.

In my MYMODULE.module file I create the following hook_block and regi

function MYMODULE_block($op = 'list', $delta = 0, $edit = array()) {
	$block = array();
	if ($op == 'list') { 
		$block['block_cart']['info'] = t('Header Cart');          
		$block['block_cart']['cache'] = BLOCK_NO_CACHE; 	 
		$block['block_cart']['region'] = 'mini_cart'; 	 
		$block['block_cart']['status'] = TRUE;  	 
		
		$block['block_left_search']['info'] = t('Left Search'); 	 
		$block['block_left_search']['cache'] = BLOCK_NO_CACHE; 	 
		$block['block_left_search']['region'] = 'left'; 	 
		$block['block_left_search']['status'] = TRUE; 	 
		$block['left_search']['weight'] = '-9';
		
	}
	else if ($op == 'view') {          
		$themes = takara_theme(); 	
		if(isset($themes['block_'.$delta])) {             
			$block = array('content'= theme('block_'.$delta)); 	
		}
	}     
	return $block; 
}

I then go and create my MYMODULE_theme with a few changes and a function at the end to auto process where I want some of the blocks to live by default

function MYMODULE_theme(){
  
  define('MODULE_BLOCK', drupal_get_path('module', 'MYMODULE').'/themes/block');
  define('THEME_INCLUDES', path_to_theme().'/includes');
  
  $themes = array(

    'block_cart'=>array(),
    'block_left_search'=>array(),
      
    );
    return process_themes($themes);
}

I then add the following processing function to be able to add template files in a default directory

function process_themes($themes){

	$remove=array('block_');
	foreach($themes as $key=>&$theme){
		if(!isset($theme['path'])){
			elseif(substr($key,0,6)=='block_') {
				$theme['path']=MODULE_BLOCK;
			}
		}
		if(isset($theme['path'])&&!isset($theme['template'])){
			$theme['template']=str_replace($remove, '', $key);
		}	
		if(!isset($theme['arguments'])){
			$theme['arguments']=array();
		}
	}
	return $themes;
}

Now once your theme registry cache is refreshed you can the following files:

  • /MYMODULES/theme/blocks/left_menu.tpl.php
  • /MYMODULES/theme/blocks/cart.tpl.php

This works easily if these are static files or if you want them in this directory, but I have purposefully allowed this path to only be used as an optional over-ride should your theme path should not be set. If you want your template files accessible as /MYTHEME/includes/left_menu.tpl.php, you can add the following in your hook_theme function.

function MYMODULE_theme(){
  
  define('MODULE_BLOCK', drupal_get_path('module', 'MYMODULE').'/themes/block');
  define('THEME_INCLUDES', path_to_theme().'/includes');
  
  $themes = array(
	
    'block_left_search'=>array('path' => THEME_INCLUDES),
    'block_cart'=>array(),
      
    );
    return process_themes($themes);
}

This is again good if these are only static files, but I am sure you will probably want to be using data from an the database or a data source. This is where we use the preprocess function. If I want to inject cart detail contents into the mini-cart above I can do the following. (I am getting data from a json data source and have saved the contents in the global $json_data)

function MYMODULE_preprocess_block_cart(&$vars){
  GLOBAL $json_data;
  $vars['cart'] = $json_data->cart;
  $vars['costs'] = $json_data->costs;
}

The block_cart part of the function name is taken directly from the theme you registered in hook theme.

Now I can happily read data from my block template /MYMODULES/theme/blocks/cart.tpl.php

<fieldset>
  <legend>Cart Contents</legend>
  <?php if(!empty($cart->cart_items)): ?>
  <table>
    <?php foreach($cart->cart_items as $cart_item): ?>
      <tr>
        <td colspan="3"><?php echo strip_tags($cart_item->title); ?></td>
      </tr>
      <tr>
        <td><?php echo $cart_item->qty; ?></td>
        <td><?php echo $cart_item->category.':'.$cart_item->maker; ?></td>
        <td><?php echo $cart_item->price; ?></td>
      </tr>
    <?php endforeach; ?>
  </table>
  <?php print theme('MYMODULE_costs', $costs); ?>
  <?php else: ?>
    <p><?php echo t('The cart is empty'); ?></p>
  <?php endif; ?>
</fieldset>

Tags:

Recent Blog Posts