Last updated April 19, 2011. Created on January 2, 2009.
Edited by pfrenssen, LeeHunter, NancyDru. Log in to edit this page.

PROBLEM

Drupal's block module is limited by the fact that a block can only have one instance. Each block has a 1:1 relationship with its region, weight, visibility (and other) settings. This means that it is impossible to have blocks in multiple regions or to have blocks that have different settings on different pages.

SOLUTION

The Multiblock module will keep track of multiple instances of blocks and dispatch to their appropriate block hooks.

Using this strategy, you would not enable any blocks that are implemented by other modules. Instead, you will go to admin/build/block/instances and create an "instance" of a block. The Multiblock module will then implement this block in its own block hook which will forward any hook_block calls to the original module's hook.

Using this method we can maintain multiple instances of blocks with different settings but the same implementation. This should not affect block-level caching.

One catch here is that the configure and save $op's for hook_block are usually implemented to save only one set of data. This means that for blocks that are unaware of Multiblock you will only be able to save CUSTOM data (this doesn't include visibility, weight, region, etc.) for one set of data.

HOW TO USE IT

  1. Go to
    • admin/build/block/instances (Drupal 6)
    • admin/structure/block/instances (Drupal 7)
  2. Select the type of block you want to create an instance of and type a unique title for that instance
  3. Click "Add Instance"
  4. Go to
    • admin/build/block (Drupal 6)
    • admin/structure/block (Drupal 7)
  5. Enable the block instance you have just created.

DEVELOPING MULTIBLOCK-ENABLED BLOCKS

Multiblock should successfully clone any regular block created with hook_block. However, if you clone a regular block that implements a save or configure $op of hook_block, the custom block settings of one block instance will overwrite the settings of another.

To get around this, you can make a block "multiblock enabled". To do this, you have to first add an $op to your hook_block called 'mb_enabled'. It should always return the string 'mb_enabled'.

Once you do this, the instances you create will get the block instance ID passed in the $edit variable for the view, configure, and save $ops. This will let you save and load different data to different instances based on this instance ID. It is passed in with the multiblock_delta key with the following format:

  $edit['multiblock_delta'] = array(
    '#type' => 'value',
    '#value' => $block_id,
    );

Preventing Multiblock Instances

Modules can block themselves by adding another case to their hook_block (as does Multiblock itself). If a module wants to block MB, it can implement op='mb_blocked' and return the module name as a string. For example:

function multiblock_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'mb_blocked':
      return 'multiblock';
...

With this in place, admins will not be able to add instances of blocks from the blocked module. This could be useful in modules that already provide multiple instances of their blocks.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

cummingscentre’s picture

Hello,

You have mentioned that the $op argument should get the value 'mb_enabled' in order for to keep the different data instances for all multiblockes-enbled blocks. I am very new to drupl and I would appreciate if you could be more specific as to which part of the code I am suppose to look at and where exactly I am suppose to make those changes.

Thank you in advance!

crosshairs’s picture

Could you provide some more details about how this can be done?

Thanks!

NancyDru’s picture

This would be included in the hook_block() implementation in your module.

function taxonomy_image_block($op = 'list', $delta = 0, $edit = array()) {
  $multi_id = isset($edit['multiblock_delta']) ? '_'. $edit['multiblock_delta']['#value'] : NULL;

  switch ($op) {
    case 'list':
      $blocks[0] = array(
        'info' => t('Taxonomy Image: Node Images'),
        'cache' => BLOCK_CACHE_PER_PAGE,
        );
      return $blocks;

    case 'mb_enabled':
      return 'mb_enabled';

    case 'view':
      switch ($delta) {
        case 0:
...

crosshairs’s picture

Thank you for the explanation and link to further reading! In case anyone else is wondering, you just need to add the following 2 lines of code

case 'mb_enabled':
     return 'mb_enabled';

to the xxx.module file (where xxx is the module which you want to make multiblock enabled), as shown in the examples, and it works great.

alexan_d’s picture

Can you help me?

I understand that I need to include these two lines. But where?
Where is stored the Hook_block ()?

Where is the 'xxx.module file' you mentioned, in my case I want to instantiate a block, not a module.

Thanks.

Alex.

NancyDru’s picture

What ever module creates the block, you need to add that code. See the example above.

alexan_d’s picture

Sorry, but I do not understand.
I installed the module Multiblock, then enable the module.
Then I created an instance of a block called 'Navigation' Menu called navigation2.

However the information regarding navigation2 instance, newly created, appears MULTIBLOCK disabled.

Na interface do Drupal não aparece nenhuma opção para eu ativar essa opção MULTIBLOCK.

Regarding the code you posted above, still not understanding where I should include these lines. I do not have a module called Navigation, and the block Navigation that I instantiate gives no option to allow me to include code.

Which module would be one where I have to insert the code? If I do not have the Navigation Module?

NancyDru’s picture

First, that would be the core Menu module, and that would mean a core hack, and I strongly urge you not to do that.

You should never have to have multiple instances of the Navigation menu. Simply create another menu and add links to it as you desire. Then enable the block that will be automatically created and place it where you want.

In Drupal 7, I rarely even enable the Navigation block any more because the good stuff goes in the Main Menu.

alexan_d’s picture

OK. Thanks!

rehan.3690’s picture

Could u plz help me how to make appear "Add Instance" in blocks
i hav installed and enabled multi block module but i dont find "Add Instance" at admin/build/block

plz help me

khadlock’s picture

Does anyone have experience enabling the NodeBlock module as a MultiBlock? I don't see any functions that include the $ops parameter.

dTr303’s picture

Hi,

I made a Drupal 7 module to generate a league table based on fixtures.
The league table will be a block with a settings page, where you can select the league you need.
Problem is, I will need different blocks with all their own settings.
Eg in the configuration page of the module I will select 'league 1' and then all fixtures of league 1 will be looked at and a league table will be generated.
I installed the Multiblock, and I can create multiple instances.. but under Configuration, I only see one settings page.
I want to have a settings page per instance I've created..
So I will have a settings page with league 1 for instance of module block league 1.. another one for league 2..

This is my code in my .module page

<?php
/**
* Implements hook_help.
*
* Displays help and module information.
*
* @param path
*   Which path of the site we're using to display help
* @param arg
*   Array that holds the current path as returned from arg() function
*/
function league_table_help($path, $arg) {
  switch (
$path) {
    case
"admin/help#league_table":
      return
'<p>'t("Display league standings, please select your league under configuration") .'</p>';
      break;
  }
}

/**
* Implements hook_block_info().
*/
function league_table_block_info() {
 
$blocks['league_table'] = array(
   
'info' => t('League table'), //The name that will appear in the block list.
   
'cache' => DRUPAL_NO_CACHE,
   
'mb_enabled' => TRUE, //Default
 
);
  return
$blocks;
}


/**
* Custom content function.
*
* Set beginning and end dates, retrieve posts from database
* saved in that time period.
*
* @return
*   A result set of the targeted posts.
*/
function league_table_contents(){  
 
//Use Database API to retrieve current posts.
 
}


/**
* Implements hook_block_view().
*
* Prepares the contents of the block.
*/
function league_table_block_view($delta = '') {
  switch(
$delta){
    case
'league_table':
     
       
$win = 3;
       
$tie = 1;
       
$loss = 0;
       
       
$teams = array();
       
       
$block['subject'] = t('League table');
     
$query = db_select('node', 'n');
   
$query->join('field_data_field_home_team', 'ht', 'n.nid = ht.entity_id');
   
$query->join('node', 'm', 'm.nid = ht.field_home_team_nid');
   
$query->join('field_data_field_score_home_team', 'hts', 'n.nid = hts.entity_id');
   
$query->join('field_data_field_home_team_goal_difference','htgd','n.nid = htgd.entity_id');
   
$query->join('field_data_field_score_visiting_team', 'vts', 'n.nid = vts.entity_id');
   
$query->addField('ht','field_home_team_nid');
   
$query->addField('m','title');
   
$query->addField('hts','field_score_home_team_value');
   
$query->addField('htgd','field_home_team_goal_difference_value');
   
$query->addField('vts','field_score_visiting_team_value');
   
$result = $query->execute();
   
$i=0;
   
foreach (
$result as $row) {
 
// Do something with $row.
   
$team = $row->title;
       
$teams[$i]['name'] = $row->title;
       
$teams[$i]['score'] = $row->field_home_team_goal_difference_value;
       
$resultaat = $row->field_home_team_goal_difference_value;
       
$teams[$i]['wedstrijden'] = 0;
       
$teams[$i]['wgewonnen'] = 0;
       
$teams[$i]['wgelijk'] = 0;
       
$teams[$i]['wverloren'] = 0;
       
$teams[$i]['dvoor'] = 0;
       
$teams[$i]['dtegen'] = 0;
       
$teams[$i]['dsaldo'] = 0;
       
$teams[$i]['punten'] = 0;


        if (
$resultaat > 0)
        {
               
$teams[$i]['wedstrijden'] += 1;
               
$teams[$i]['wgewonnen'] += 1;
               
$teams[$i]['punten'] += $win;
        }
        if (
$resultaat == 0)
        {
               
$teams[$i]['wedstrijden'] += 1;
               
$teams[$i]['wgelijk'] += 1;
               
$teams[$i]['punten'] += $tie;
        }
        if (
$resultaat < 0)
        {
               
$teams[$i]['wedstrijden'] += 1;
               
$teams[$i]['wverloren'] += 1;
               
$teams[$i]['punten'] += $loss;
        }
       
$teams[$i]['dvoor'] += $row->field_score_home_team_value;
       
$teams[$i]['dtegen'] += $row->field_score_visiting_team_value;
       
$teams[$i]['dsaldo'] += $resultaat;
       
   
     
$i++;
}

$query = db_select('node', 'n');
   
$query->join('field_data_field_visiting_team', 'vt', 'n.nid = vt.entity_id');
   
$query->join('node', 'm', 'm.nid = vt.field_visiting_team_nid');
   
$query->join('field_data_field_score_visiting_team', 'vts', 'n.nid = vts.entity_id');
   
$query->join('field_data_field_visit_team_goal_difference','vtgd','n.nid = vtgd.entity_id');
   
$query->join('field_data_field_score_home_team', 'hts', 'n.nid = hts.entity_id');
   
$query->addField('vt','field_visiting_team_nid');
   
$query->addField('m','title');
   
$query->addField('vts','field_score_visiting_team_value');
   
$query->addField('vtgd','field_visit_team_goal_difference_value');
   
$query->addField('hts','field_score_home_team_value');
   
$result = $query->execute();
    
    foreach (
$result as $row) {
 
// Do something with $row.
   
$team = $row->title;
 
       
$teams[$i]['name'] = $row->title;
       
$teams[$i]['score'] = $row->field_visit_team_goal_difference_value;
       
$resultaat = $row->field_visit_team_goal_difference_value;
       
$teams[$i]['wedstrijden'] = 0;
       
$teams[$i]['wgewonnen'] = 0;
       
$teams[$i]['wgelijk'] = 0;
       
$teams[$i]['wverloren'] = 0;
       
$teams[$i]['dvoor'] = 0;
       
$teams[$i]['dtegen'] = 0;
       
$teams[$i]['dsaldo'] = 0;
       
$teams[$i]['punten'] = 0;


        if (
$resultaat > 0)
        {
               
$teams[$i]['wedstrijden'] += 1;
               
$teams[$i]['wgewonnen'] += 1;
               
$teams[$i]['punten'] += $win;
        }
        if (
$resultaat == 0)
        {
               
$teams[$i]['wedstrijden'] += 1;
               
$teams[$i]['wgelijk'] += 1;
               
$teams[$i]['punten'] += $tie;
        }
        if (
$resultaat < 0)
        {
               
$teams[$i]['wedstrijden'] += 1;
               
$teams[$i]['wverloren'] += 1;
               
$teams[$i]['punten'] += $loss;
        }
       
$teams[$i]['dvoor'] += $row->field_score_visiting_team_value;
       
$teams[$i]['dtegen'] += $row->field_score_home_team_value;
       
$teams[$i]['dsaldo'] += $resultaat;
   
       
$i++;

       
    }
   


$teams2 = array();
foreach(
$teams as $team) {
   
$index = team_exists($team['name'], $teams2);
    if (
$index < 0) {
       
$teams2[] = $team;
    }
    else {
       
$teams2[$index]['dsaldo'] +=  $team['dsaldo'];
       
$teams2[$index]['dvoor'] +=  $team['dvoor'];
       
$teams2[$index]['dtegen'] +=  $team['dtegen'];
       
$teams2[$index]['wedstrijden'] +=  $team['wedstrijden'];
       
$teams2[$index]['wgewonnen'] +=  $team['wgewonnen'];
       
$teams2[$index]['wgelijk'] +=  $team['wgelijk'];
       
$teams2[$index]['wverloren'] +=  $team['wverloren'];
       
$teams2[$index]['punten'] +=  $team['punten'];
    }
}


  }
 
//sort data points, goal difference, goals made
foreach($teams2 as $c=>$key) {
       
$sort_points[] = $key['punten'];
       
$sort_goal_difference[] = $key['dsaldo'];
       
$sort_goals[] = $key['dvoor'];
    }

   
array_multisort($sort_points, SORT_DESC, $sort_goal_difference, SORT_DESC,$sort_goals, SORT_DESC, $teams2);

   
   
$table ="<table border="1">";

foreach(
$teams2 as $teamitem)
{
 
 
  if(
$teamitem['name'] == 'K. SV Bredene')
  {
   
$table .="<tr bgcolor='grey'><td>".$teamitem['name']."</td><td>".$teamitem['wedstrijden']."</td><td>".$teamitem['wgewonnen']."</td><td>".$teamitem['wgelijk']."</td><td>".$teamitem['wverloren']."</td><td>".$teamitem['dsaldo']."</td><td>".$teamitem['dvoor']."</td><td>".$teamitem['dtegen']."</td><td>".$teamitem['punten']."</td></tr>";
  }else{
   
$table .="<tr><td>".$teamitem['name']."</td><td>".$teamitem['wedstrijden']."</td><td>".$teamitem['wgewonnen']."</td><td>".$teamitem['wgelijk']."</td><td>".$teamitem['wverloren']."</td><td>".$teamitem['dsaldo']."</td><td>".$teamitem['dvoor']."</td><td>".$teamitem['dtegen']."</td><td>".$teamitem['punten']."</td></tr>";
  }

}

$table .="</table>";
   
 
//$block['content'] = print_r($teams2)."<br/>".$table;
$block['content'] = $table;
  return
$block;
}




function
team_exists($teamname, $array) {
   
$result = -1;
    for(
$i=0; $i<sizeof($array); $i++) {
        if (
$array[$i]['name'] == $teamname) {
           
$result = $i;
            break;
        }
    }
    return
$result;
}

/**
* Implements hook_menu().
*/
function league_table_menu() {
 
$items = array();

 
$items['admin/config/content/league_table'] = array(
   
'title' => 'League Table',
   
'description' => 'Configuration for League table module',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('league_table_form'),
   
'access arguments' => array('access administration pages'),
   
'type' => MENU_NORMAL_ITEM,
  );
 
  return
$items;
}

/**
* Form function, called by drupal_get_form()
* in current_posts_menu().
*/
function league_table_form($form, &$form_state) {
 
$form['legaue_table_max'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Maximum number of posts'),
   
'#default_value' => variable_get('league_table_max', 3),
   
'#size' => 2,
   
'#maxlength' => 2,
   
'#description' => t('The maximum number of links to display in the block.'),
   
'#required' => TRUE,
  );

  return
system_settings_form($form);
}

function
league_table_block($op = 'list', $delta = 0, $edit = array()) {
 
$multi_id = isset($edit['multiblock_delta']) ? '_'. $edit['multiblock_delta']['#value'] : NULL;

  switch (
$op) {
   
    case
'mb_enabled':
      return
'mb_enabled';
  }

?>
anou’s picture

I've installed multiblock module on D7 and I believed that I could create different instances of a block with different data (and not just different title). Maybe I understood wrong what is possible with multiblock ? Maybe having different data is not possible with multiblock ?

If someone can tell me if what I'm trying to do is out of subject or if I'm understanding something wrong ?

Thank you for your advice

David

David THOMAS
http://www.smol.org

rehan.3690’s picture

hello

i am newbie to drupal 7
I dont find "instances" at admin/build/block/instances
I have installed and enabled the module but nothing works
Could anyone plz help me.

lmeurs’s picture

On D7 one should visit admin/structure/block/instances

Laurens Meurs
wiedes.nl

jordilondoner’s picture

Hi all,
I've been working with multiblocks trying to get it ready for a custom blocks. What has been really hard because I wasn't able to retrieve the delta of my instance on hook_block_view() using $edit['multiblock_delta'] as the doc says to do.
However, I was able to:
enable the ability of my block to be resinstaced for mutiblock:
'mb_enabled' => TRUE, // on my hoock_block_info() --> worked fine
assign a new 'subdelta' to each instance on hoock_block_configure($delta = '') :

$form['multiblock_delta'] = array(
      '#type' => 'value',
      '#value' => $block_id,
);

then, save it in a different variable using our 'subdelta' on hook_block_save($delta = '', $edit = array()):
$multiblock_delta = $edit['multiblock_delta']; --> worked fine, as expected.
But I've got an issue using it on hook_block_view($delta = '', $edit = array()):

$form['multiblock_delta'] = array(
      '#type' => 'value',
      '#value' => $block_id,
);

the above part never got tired to return a huge and frustrating NULL.

After try everything that came to my mind, I think I found a """""""bug"""""""" ?

on multiblock.modeule, line 90 I found:

/**
* Dispatch a hook_block call to it's respective module. Paramater $delta
* is the new multiblock delta that we're using and $op is the op we are
* dispatching.
*/
function multiblock_call_block($delta, $op, $edit) {
  $result = db_query("SELECT module, orig_delta, delta, multi_settings FROM {multiblock} WHERE delta = :delta", array(
    ':delta' => $delta,
  ));
  if ($block_info = $result->fetchObject()) {
    // If this block is multiblock enabled, send it the delta of the block we're using.
    if ($block_info->multi_settings == 1 ) {
      $edit['multiblock_delta'] = array(
        '#type' => 'value',
        '#value' => $block_info->delta,
        );
    }
    if ($op == 'save') {
      $block = module_invoke($block_info->module, 'block_'. $op, $block_info->orig_delta, $edit);
    }
    else {
      $block = module_invoke($block_info->module, 'block_'. $op, $block_info->orig_delta);
    }
    return $block;
  }
  // No such multiblock, shouldn't ever happen.
  return;
}

I realised that on that way I couldn't access $edit on view hook and I changed it for:

/**
* Dispatch a hook_block call to it's respective module. Paramater $delta
* is the new multiblock delta that we're using and $op is the op we are
* dispatching.
*/
function multiblock_call_block($delta, $op, $edit) {
  $result = db_query("SELECT module, orig_delta, delta, multi_settings FROM {multiblock} WHERE delta = :delta", array(
    ':delta' => $delta,
  ));
  if ($block_info = $result->fetchObject()) {
    // If this block is multiblock enabled, send it the delta of the block we're using.
    if ($block_info->multi_settings == 1 ) {
      $edit['multiblock_delta'] = array(
        '#type' => 'value',
        '#value' => $block_info->delta,
        );
    }
      switch ($op) {
         case 'configure':
         $block = module_invoke($block_info->module, 'block_'. $op, $block_info->orig_delta);
        break;
        default:
         $block = module_invoke($block_info->module, 'block_'. $op, $block_info->orig_delta, $edit);
       break;
     }
    return $block;
  }
  // No such multiblock, shouldn't ever happen.
  return;
}

And fianlly I can acces the multiinstance referent or how I called it before 'subdelta'
I think I am not breaking anything doing that on that way, if so, and someone catches it, please let me know.
With my current knowledge about Drupal (only six month using it) I'd say it was a buck on the module...

sterlingedsrv@gmail.com’s picture

Hi, I am a newbie, and working to prep my site for public launch. I have really been frustrated by need to recreate blocks to put them in different section of various pages, and then I saw something about the Multiblock module. However, I'm in D7 and there is not a "Recommended Version" available.

- Is is safe to use the version listed under "Other" for D7?
- Has anyone had issues with it?
- Is there a plan/timeline to have a "Recommended" version for 7?

(The site will be ecommerce and eventually multiuser)

Thanks for your help!

ryan_21’s picture

Hi,

Currently i am creating a custom module with hook info and hook block configure with some additional form fields under hook configure in D7 want to make this module as multi instance so that stored variable data will be different for each instance. can some one help me with a piece of code. Any help will be highly appreciated.

Thanks.

Abhishek Sawant’s picture

How do we delete custom module multiblock variable from variables table on uninstalling the block.
Any help would be highly appreciated.

Thanks.

Abhishek Sawant
Drupal Developer

trumpetmercenary’s picture

Where exactly in the .module does the mb_enabled code go?

I added to my .module:

/**
* Implements hook_block_info().
*/
function dexp_layerslider_block_info()
{
  $blocks = array();
  $num    = variable_get('dexp_layerslider_block_num', 3);
  for ($i = 1; $i <= $num; $i++) {
    $blocks['dexp_layerslider_block_' . $i] = array(
      'info' => t('Layer Slider block ' . $i),
      'cache' => DRUPAL_NO_CACHE
        'mb_enabled' => TRUE, //Default
    );
  }
  return $blocks;
}

function dexp_layerslider_block($op = 'list', $delta = 0, $edit = array()) {
  $multi_id = isset($edit['multiblock_delta']) ? '_'. $edit['multiblock_delta']['#value'] : NULL;

  switch ($op) {
  
    case 'mb_enabled':
      return 'mb_enabled';
  }
}

But all this does is bring the site down with a white screen of death.

The error log reports
PHP Parse error:  syntax error, unexpected ''mb_enabled'' (T_CONSTANT_ENCAPSED_STRING), expecting ')' in sites/all/modules/drupalexp/modules/dexp_layerslider/dexp_layerslider.module on line 164

Is there a cleaner way to do this?

Abhishek Sawant’s picture

As per your current code I can only see it has "," missing after 'cache' => DRUPAL_NO_CACHE.

try to add the semi-colon if it doesn't work please paste your complete code.

Cheers,

Abhishek Sawant
Drupal Developer