multiblock.module in MultiBlock 7
Same filename and directory in other branches
Enhances the block API, as provided by D7 Core.
File
multiblock.moduleView source
<?php
/**
* @file
* Enhances the block API, as provided by D7 Core.
*/
/**
* Implements hook_menu().
*/
function multiblock_menu() {
$items = array();
$items['admin/structure/block/instances'] = array(
'title' => 'Instances',
'description' => 'Create and delete instances of blocks.',
'page callback' => 'multiblock_general',
'access callback' => 'user_access',
'access arguments' => array(
'administer blocks',
),
'type' => MENU_LOCAL_TASK,
'weight' => -15,
);
$items['admin/structure/block/instances/delete'] = array(
'title' => 'Delete Block Instance',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'multiblock_delete_form',
),
'access callback' => 'user_access',
'access arguments' => array(
'administer blocks',
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_block_info().
*/
function multiblock_block_info() {
// Get all of the block instances that exist.
$blocks = array();
$blocks = multiblock_get_block(NULL);
foreach ($blocks as $block) {
$blocks[$block->delta] = array(
'info' => $block->title,
);
$cache = db_query('SELECT cache FROM {block} WHERE module = :module AND delta = :orig_delta', array(
':module' => $block->module,
':orig_delta' => $block->orig_delta,
))
->fetchField();
if ($cache) {
$blocks[$block->delta]['cache'] = $cache;
}
}
return $blocks;
}
/**
* Implements hook_block_view().
*/
function multiblock_block_view($delta = 0, $edit = array()) {
return multiblock_call_block($delta, 'view', $edit);
}
/**
* Implements hook_block_save().
*/
function multiblock_block_save($delta = 0, $edit = array()) {
return multiblock_call_block($delta, 'save', $edit);
}
/**
* Implements hook_block_configure().
*/
function multiblock_block_configure($delta = 0, $edit = array()) {
return multiblock_call_block($delta, 'configure', $edit);
}
/**
* Fetch a given block from the multiblock database table.
*
* @param $delta
* Optional. Retreive a single block based on this delta. If none specified,
* all multiblock instances are returned.
* @param $reset
* Optional. Boolean value to reset the internal cache of this function.
*/
function multiblock_get_block($delta = NULL, $reset = FALSE) {
static $blocks;
if (!isset($blocks) || $reset) {
$blocks = array();
$result = db_query("SELECT * FROM {multiblock}");
$modules = array();
foreach ($result as $row) {
// If we've not checked this module is enabled yet do so.
if (!isset($modules[$row->module])) {
$modules[$row->module] = module_exists($row->module);
}
// Only add this block if the module is enabled.
if ($modules[$row->module]) {
$blocks[$row->delta] = $row;
}
}
}
return is_numeric($delta) ? isset($blocks[$delta]) ? $blocks[$delta] : FALSE : $blocks;
}
/**
* Dispatch a hook_block call to its respective module. Paramater $delta
* is the new multiblock delta that we're using and $op is the op we are
* dispatching.
*
* @param $delta
* The delta of the multiblock block, which is different from the delta
* of the block in the original module
*
* @param $op
* Can be configure, view, save...
*
* @edit
* Information originally passed to multiblock's corresponding hook.
* For example, a call to multiblock_block_view($delta, $edit) will
* result in a call to multiblock_call_block($delta, 'view', $edit).
* Note that Drupal's API does not call for $edit parameters for
* hook_node_view() or hook_node_configure(), but multiblock does.
*
* @return
* Information returned by the corresponding module_invoke() call.
*/
function multiblock_call_block($delta, $op, $edit) {
// Get block info from multiblock_get_block() which now checks that the original module
// still exists before returning the info.
$block_info = multiblock_get_block($delta);
// Check we actually have a block to render.
if ($block_info) {
// 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,
);
}
// This will result in a call to the original module's hook_block_view(),
// hook_block_configure(), or hook_block_save() function. In cases where
// modules define multiblock-enabled blocks (that is, in their
// hook_block_info() function, they return an associative array of block
// machine names to arrays with 'mb_enabled' => TRUE for each mb-enabled
// block), these modules' hook_block_view() and hook_block_configure()
// functions will have an extra $edit = array() parameter, in which
// information about multiblock is passed. This will allow blocks to
// contain and display different configuration information per instance.
$block = module_invoke($block_info->module, 'block_' . $op, $block_info->orig_delta, $edit);
if ($op == 'view') {
if (isset($block['content']['#form_id'])) {
// Handle duplicate form IDs
$block['content']['#id'] = drupal_html_id($block['content']['#id']);
}
$block['orig_module'] = $block_info->module;
$block['orig_delta'] = $block_info->orig_delta;
}
return $block;
}
// No such multiblock, shouldn't ever happen.
return;
}
/**
* Page callback for the "Manage Block Instances page".
*/
function multiblock_general() {
if (func_num_args() && func_get_arg(0) == 'edit' && is_numeric($instance = func_get_arg(1))) {
$req_block = multiblock_get_block($instance);
}
// Fetch blocks directly from modules using block.module function.
$blocks = _block_rehash();
// Sort blocks how we want them.
usort($blocks, 'multiblock_block_sort');
// Fetch "Add Instance" form.
if (isset($req_block)) {
$get_form = drupal_get_form('multiblock_add_form', $blocks, $req_block);
$form = drupal_render($get_form);
}
else {
$get_form = drupal_get_form('multiblock_add_form', $blocks);
$form = drupal_render($get_form);
}
// Get an array of existing blocks.
$multiblocks = multiblock_get_block(NULL, TRUE);
return theme('multiblock_general', array(
'add_block_form' => $form,
'multiblocks' => $multiblocks,
'edit' => isset($req_block),
));
}
/**
* "Add Instance" form.
*/
function multiblock_add_form($form, &$form_state, $blocks, $update = NULL) {
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Instance Title'),
'#maxlength' => 256,
'#required' => TRUE,
'#default_value' => isset($update->title) ? $update->title : NULL,
);
if ($update) {
$form['instance'] = array(
'#type' => 'value',
'#value' => $update->delta,
);
}
else {
// Turn $blocks into form options of block types.
// Remember we need the module and delta to be able to tell what kind of
// blocks we're talking about.
$options = array();
foreach ($blocks as $block) {
// Don't include multiblock module blocks in the list.
if ($block['module'] != 'multiblock') {
$options[$block['module'] . '***MB***' . $block['delta']] = $block['info'];
}
}
$form['block'] = array(
'#type' => 'select',
'#title' => t('Block type'),
'#options' => $options,
'#required' => TRUE,
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
function multiblock_delete_form($form, $form_state, $delta) {
$block = multiblock_get_block($delta);
if (empty($block)) {
drupal_set_message(t('The multiblock with the delta @delta was not found.', array(
'@delta' => $delta,
)), 'error');
return array();
}
$form['delta'] = array(
'#type' => 'value',
'#value' => $delta,
);
return confirm_form($form, t('Delete the block instance %title?', array(
'%title' => $block->title,
)), 'admin/structure/block/instances', t('This will delete the instance of the block %title.', array(
'%title' => $block->title,
)), t('Delete'), t('Cancel'));
}
function multiblock_delete_form_submit($form, &$form_state) {
if (multiblock_delete($form_state['values']['delta'])) {
drupal_set_message(t('Block successfully deleted!'));
}
else {
drupal_set_message(t('There was a problem deleting the block'));
}
$form_state['redirect'] = 'admin/structure/block/instances';
}
/**
* Add a multiblock instance.
*
* @param $original_block
* The original block for which an instance is being created.
* @param $block_instance
* An object contain information about the particular block instance.
* @return
* The delta of the newly added block.
*/
function multiblock_add($original_block, $block_instance) {
// Create new delta for block instance.
$record = array(
'title' => $block_instance->title,
'module' => $original_block->module,
'orig_delta' => $original_block->delta,
'multi_settings' => $block_instance->mb_enabled,
);
drupal_write_record('multiblock', $record);
return $record['delta'];
}
/**
* Delete a multiblock instance.
*/
function multiblock_delete($multiblock_delta) {
// Remove instance from multiblock's storage.
$num_deleted = db_delete('multiblock')
->condition('delta', (int) $multiblock_delta)
->execute();
// Remove block instances from the block modules tables to avoid orphans.
db_delete('block')
->condition('module', 'multiblock')
->condition('delta', (int) $multiblock_delta)
->execute();
db_delete('block_role')
->condition('module', 'multiblock')
->condition('delta', (int) $multiblock_delta)
->execute();
if (ctype_digit($multiblock_delta) && $num_deleted) {
_block_rehash();
return TRUE;
}
else {
return FALSE;
}
}
/**
* Validate "Add Block Instance" form.
*/
function multiblock_add_form_validate($form, &$form_state) {
if (!isset($form_state['values']['instance'])) {
// Make sure we are getting a valid block to add.
if (!preg_match('/^.+\\*\\*\\*MB\\*\\*\\*.+$/', $form_state['values']['block'])) {
form_set_error('block', t('Bad block module input, contact administrator'));
return;
}
// Make sure the block and delta exist.
$orig_block = multiblock_blockinfo_from_form($form_state['values']['block']);
if (!module_hook($orig_block['module'], 'block_info') || !array_key_exists($orig_block['delta'], module_invoke($orig_block['module'], 'block_info'))) {
form_set_error('block', t('Module or block doesn\'t exist, contact administrator'));
}
}
}
/**
* Add block instance to database from "Add Block Instance" form.
*/
function multiblock_add_form_submit($form, &$form_state) {
if (isset($form_state['values']['instance'])) {
$num_updated = db_update('multiblock')
->fields(array(
'title' => $form_state['values']['title'],
))
->condition('delta', $form_state['values']['instance'], '=')
->execute();
$block = multiblock_get_block($form_state['values']['instance'], TRUE);
$cache = db_query('SELECT cache FROM {block} WHERE module = :module AND delta = :orig_delta', array(
":module" => $block->module,
":orig_delta" => $block->orig_delta,
))
->fetchField();
if ($cache) {
db_query('UPDATE {block} SET cache = :cache WHERE delta = :delta AND module = :multiblock', array(
':cache' => $cache,
':delta' => $block->delta,
':multiblock' => 'multiblock',
));
}
$form_state['redirect'] = 'admin/structure/block/instances';
return;
}
// Get the original block info.
$orig_block = multiblock_blockinfo_from_form($form_state['values']['block']);
// Check whether this module is multiblock enabled.
$block_info = module_invoke($orig_block['module'], 'block_info');
$mb_enabled = (int) (!empty($block_info[$orig_block['delta']]['mb_enabled']) && $block_info[$orig_block['delta']]['mb_enabled'] == TRUE);
// Create block instance information.
$orig_block = (object) $orig_block;
$instance = (object) array(
'title' => $form_state['values']['title'],
'mb_enabled' => $mb_enabled,
);
// Add the block instance.
multiblock_add($orig_block, $instance);
drupal_set_message(t('Block instance %instance created.', array(
'%instance' => $form_state['values']['title'],
)));
}
/**
* Custom sort based on info element of array.
*/
function multiblock_block_sort($a, $b) {
return strcmp($a['info'], $b['info']);
}
/**
* Get the module and delta from the "Add Block Instance" block form element.
*/
function multiblock_blockinfo_from_form($form_value) {
$matches = array();
preg_match('/^(.+)\\*\\*\\*MB\\*\\*\\*(.+)$/', $form_value, $matches);
return array(
'module' => $matches[1],
'delta' => $matches[2],
);
}
/**
* Get title of a block by its module and delta.
*/
function multiblock_get_block_title($module, $delta) {
$block_info = module_invoke($module, 'block_info', $delta);
return $block_info[$delta]['info'];
}
/**
* Implementation of hook_theme().
*/
function multiblock_theme() {
return array(
'multiblock_general' => array(
'arguments' => array(
'add_block_form' => NULL,
'multiblocks' => NULL,
'edit' => NULL,
),
),
);
}
/**
* Implements hook_preprocess_block().
*
* Add "{orig_module}" and "{orig_module}-{orig_delta}-instance" classes to
* multiblock blocks.
*/
function multiblock_preprocess_block(&$variables) {
if ($variables['block']->module == 'multiblock') {
$variables['classes_array'][] = drupal_html_class('block-' . $variables['block']->orig_module);
$variables['classes_array'][] = drupal_html_class('block-' . $variables['block']->orig_module) . '-' . $variables['block']->orig_delta . '-instance';
}
}
/**
* Theme function for the "Manage Block Instances" page.
*/
function theme_multiblock_general($variables) {
extract($variables, EXTR_SKIP);
$output = '';
$noyes = array(
'misc/watchdog-error.png',
'misc/watchdog-ok.png',
);
$output .= '<p><h3>' . ($edit ? t('Edit Instance') : t('Add Instance')) . '</h3>' . $add_block_form . '</p>';
$header = array(
t('Title'),
t('Original Block Title'),
t('Original Module'),
t('MultiBlock Enabled'),
t('Original Delta'),
t('Action'),
);
$rows = array();
foreach ($multiblocks as $row) {
$ops_link = l(t('Edit'), 'admin/structure/block/instances/edit/' . $row->delta) . ' ' . l(t('Delete'), 'admin/structure/block/instances/delete/' . $row->delta);
$title = multiblock_get_block_title($row->module, $row->orig_delta);
$mb_enabled = $noyes[$row->multi_settings];
$alt = t('Not Multiblock enabled');
if ($row->multi_settings) {
$alt = t('Multiblock enabled');
}
$rows[] = array(
check_plain($row->title),
check_plain($title),
$row->module,
array(
'data' => theme('image', array(
'path' => $mb_enabled,
'alt' => $alt,
'title' => $alt,
)),
'align' => 'center',
),
$row->orig_delta,
$ops_link,
);
}
$output .= '<p><h3>' . t('Manage Instances') . '</h3>';
if (!empty($rows)) {
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
));
}
else {
$output .= t('No instances defined yet.');
}
$output .= '</p>';
return $output;
}
/**
* Implements hook_modules_uninstalled().
*/
function hook_modules_uninstalled($modules) {
// Delete all multiblock instances for the disabled modules.
db_delete('multiblock')
->condition('module', $modules, 'IN')
->execute();
}
Functions
Name | Description |
---|---|
hook_modules_uninstalled | Implements hook_modules_uninstalled(). |
multiblock_add | Add a multiblock instance. |
multiblock_add_form | "Add Instance" form. |
multiblock_add_form_submit | Add block instance to database from "Add Block Instance" form. |
multiblock_add_form_validate | Validate "Add Block Instance" form. |
multiblock_blockinfo_from_form | Get the module and delta from the "Add Block Instance" block form element. |
multiblock_block_configure | Implements hook_block_configure(). |
multiblock_block_info | Implements hook_block_info(). |
multiblock_block_save | Implements hook_block_save(). |
multiblock_block_sort | Custom sort based on info element of array. |
multiblock_block_view | Implements hook_block_view(). |
multiblock_call_block | Dispatch a hook_block call to its respective module. Paramater $delta is the new multiblock delta that we're using and $op is the op we are dispatching. |
multiblock_delete | Delete a multiblock instance. |
multiblock_delete_form | |
multiblock_delete_form_submit | |
multiblock_general | Page callback for the "Manage Block Instances page". |
multiblock_get_block | Fetch a given block from the multiblock database table. |
multiblock_get_block_title | Get title of a block by its module and delta. |
multiblock_menu | Implements hook_menu(). |
multiblock_preprocess_block | Implements hook_preprocess_block(). |
multiblock_theme | Implementation of hook_theme(). |
theme_multiblock_general | Theme function for the "Manage Block Instances" page. |