| 1 | | <?php |
| 2 | | // $Id: block.module,v 1.312 2008/10/09 15:15:50 webchick Exp $ |
| 3 | | |
| 4 | | /** |
| 5 | | * @file |
| 6 | | * Controls the boxes that are displayed around the main content. |
| 7 | | */ |
| 8 | | |
| 9 | | /** |
| 10 | | * Denotes that a block is not enabled in any region and should not be
shown. |
| 11 | | */ |
| 12 | 2366 | define('BLOCK_REGION_NONE', -1); |
| 13 | | |
| 14 | | /** |
| 15 | | * Constants defining cache granularity for blocks. |
| 16 | | * |
| 17 | | * Modules specify the caching patterns for their blocks using binary |
| 18 | | * combinations of these constants in their hook_block(op 'list'): |
| 19 | | * $block[delta]['cache'] = BLOCK_CACHE_PER_ROLE | BLOCK_CACHE_PER_PAGE; |
| 20 | | * BLOCK_CACHE_PER_ROLE is used as a default when no caching pattern is |
| 21 | | * specified. |
| 22 | | * |
| 23 | | * The block cache is cleared in cache_clear_all(), and uses the same
clearing |
| 24 | | * policy than page cache (node, comment, user, taxonomy added or
updated...). |
| 25 | | * Blocks requiring more fine-grained clearing might consider disabling the |
| 26 | | * built-in block cache (BLOCK_NO_CACHE) and roll their own. |
| 27 | | * |
| 28 | | * Note that user 1 is excluded from block caching. |
| 29 | | */ |
| 30 | | |
| 31 | | /** |
| 32 | | * The block should not get cached. This setting should be used: |
| 33 | | * - for simple blocks (notably those that do not perform any db query), |
| 34 | | * where querying the db cache would be more expensive than directly
generating |
| 35 | | * the content. |
| 36 | | * - for blocks that change too frequently. |
| 37 | | */ |
| 38 | 2366 | define('BLOCK_NO_CACHE', -1); |
| 39 | | |
| 40 | | /** |
| 41 | | * The block can change depending on the roles the user viewing the page
belongs to. |
| 42 | | * This is the default setting, used when the block does not specify
anything. |
| 43 | | */ |
| 44 | 2366 | define('BLOCK_CACHE_PER_ROLE', 0x0001); |
| 45 | | |
| 46 | | /** |
| 47 | | * The block can change depending on the user viewing the page. |
| 48 | | * This setting can be resource-consuming for sites with large number of
users, |
| 49 | | * and thus should only be used when BLOCK_CACHE_PER_ROLE is not
sufficient. |
| 50 | | */ |
| 51 | 2366 | define('BLOCK_CACHE_PER_USER', 0x0002); |
| 52 | | |
| 53 | | /** |
| 54 | | * The block can change depending on the page being viewed. |
| 55 | | */ |
| 56 | 2366 | define('BLOCK_CACHE_PER_PAGE', 0x0004); |
| 57 | | |
| 58 | | /** |
| 59 | | * The block is the same for every user on every page where it is visible. |
| 60 | | */ |
| 61 | 2366 | define('BLOCK_CACHE_GLOBAL', 0x0008); |
| 62 | | |
| 63 | | /** |
| 64 | | * Implementation of hook_help(). |
| 65 | | */ |
| 66 | 2366 | function block_help($path, $arg) { |
| 67 | | switch ($path) { |
| 68 | 1676 | case 'admin/help#block': |
| 69 | 27 | $output = '<p>' . t('Blocks are boxes of content rendered into an
area, or region, of a web page. The default theme Garland, for example,
implements the regions "left sidebar", "right sidebar", "content",
"header", and "footer", and a block may appear in any one of these areas.
The <a href="@blocks">blocks administration page</a> provides a
drag-and-drop interface for assigning a block to a region, and for
controlling the order of blocks within regions.', array('@blocks' =>
url('admin/build/block'))) . '</p>'; |
| 70 | 27 | $output .= '<p>' . t('Although blocks are usually generated
automatically by modules (like the <em>User login</em> block, for example),
administrators can also define custom blocks. Custom blocks have a title,
description, and body. The body of the block can be as long as necessary,
and can contain content supported by any available <a
href="@input-format">input format</a>.', array('@input-format' =>
url('admin/settings/filters'))) . '</p>'; |
| 71 | 27 | $output .= '<p>' . t('When working with blocks, remember that:') .
'</p>'; |
| 72 | 27 | $output .= '<ul><li>' . t('since not all themes implement the same
regions, or display regions in the same way, blocks are positioned on a
per-theme basis.') . '</li>'; |
| 73 | 27 | $output .= '<li>' . t('disabled blocks, or blocks not in a region,
are never shown.') . '</li>'; |
| 74 | 27 | $output .= '<li>' . t('blocks can be configured to be visible only on
certain pages.') . '</li>'; |
| 75 | 27 | $output .= '<li>' . t('blocks can be configured to be visible only
when specific conditions are true.') . '</li>'; |
| 76 | 27 | $output .= '<li>' . t('blocks can be configured to be visible only
for certain user roles.') . '</li>'; |
| 77 | 27 | $output .= '<li>' . t('when allowed by an administrator, specific
blocks may be enabled or disabled on a per-user basis using the <em>My
account</em> page.') . '</li>'; |
| 78 | 27 | $output .= '<li>' . t('some dynamic blocks, such as those generated
by modules, will be displayed only on certain pages.') . '</li></ul>'; |
| 79 | 27 | $output .= '<p>' . t('For more information, see the online handbook
entry for <a href="@block">Block module</a>.', array('@block' =>
'http://drupal.org/handbook/modules/block/')) . '</p>'; |
| 80 | 27 | return $output; |
| 81 | 1676 | case 'admin/build/block': |
| 82 | 20 | $output = '<p>' . t('This page provides a drag-and-drop interface for
assigning a block to a region, and for controlling the order of blocks
within regions. To change the region or order of a block, grab a
drag-and-drop handle under the <em>Block</em> column and drag the block to
a new location in the list. (Grab a handle by clicking and holding the
mouse while hovering over a handle icon.) Since not all themes implement
the same regions, or display regions in the same way, blocks are positioned
on a per-theme basis. Remember that your changes will not be saved until
you click the <em>Save blocks</em> button at the bottom of the page.') .
'</p>'; |
| 83 | 20 | $output .= '<p>' . t('Click the <em>configure</em> link next to each
block to configure its specific title and visibility settings. Use the <a
href="@add-block">add block page</a> to create a custom block.',
array('@add-block' => url('admin/build/block/add'))) . '</p>'; |
| 84 | 20 | return $output; |
| 85 | 1656 | case 'admin/build/block/add': |
| 86 | 1 | return '<p>' . t('Use this page to create a new custom block. New
blocks are disabled by default, and must be moved to a region on the <a
href="@blocks">blocks administration page</a> to be visible.',
array('@blocks' => url('admin/build/block'))) . '</p>'; |
| 87 | 0 | } |
| 88 | 1655 | } |
| 89 | | |
| 90 | | /** |
| 91 | | * Implementation of hook_theme(). |
| 92 | | */ |
| 93 | 2366 | function block_theme() { |
| 94 | | return array( |
| 95 | | 'block_admin_display_form' => array( |
| 96 | 178 | 'template' => 'block-admin-display-form', |
| 97 | 178 | 'file' => 'block.admin.inc', |
| 98 | 178 | 'arguments' => array('form' => NULL), |
| 99 | 178 | ), |
| 100 | 178 | ); |
| 101 | 0 | } |
| 102 | | |
| 103 | | /** |
| 104 | | * Implementation of hook_perm(). |
| 105 | | */ |
| 106 | 2366 | function block_perm() { |
| 107 | | return array( |
| 108 | | 'administer blocks' => array( |
| 109 | 172 | 'title' => t('Administer blocks'), |
| 110 | 172 | 'description' => t('Select which blocks are displayed, and arrange
them on the page.'), |
| 111 | 172 | ), |
| 112 | | 'use PHP for block visibility' => array( |
| 113 | 172 | 'title' => t('Use PHP for block visibility'), |
| 114 | 172 | 'description' => t('Enter PHP code in the field for block visibility
settings. %warning', array('%warning' => t('Warning: Give to trusted roles
only; this permission has security implications.'))), |
| 115 | 172 | ), |
| 116 | 172 | ); |
| 117 | 0 | } |
| 118 | | |
| 119 | | /** |
| 120 | | * Implementation of hook_menu(). |
| 121 | | */ |
| 122 | 2366 | function block_menu() { |
| 123 | 161 | $items['admin/build/block'] = array( |
| 124 | 161 | 'title' => 'Blocks', |
| 125 | 161 | 'description' => 'Configure what block content appears in your site\'s
sidebars and other regions.', |
| 126 | 161 | 'page callback' => 'block_admin_display', |
| 127 | 161 | 'access arguments' => array('administer blocks'), |
| 128 | | ); |
| 129 | 161 | $items['admin/build/block/list'] = array( |
| 130 | 161 | 'title' => 'List', |
| 131 | 161 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 132 | 161 | 'weight' => -10, |
| 133 | | ); |
| 134 | 161 | $items['admin/build/block/list/js'] = array( |
| 135 | 161 | 'title' => 'JavaScript List Form', |
| 136 | 161 | 'page callback' => 'block_admin_display_js', |
| 137 | 161 | 'access arguments' => array('administer blocks'), |
| 138 | 161 | 'type' => MENU_CALLBACK, |
| 139 | | ); |
| 140 | 161 | $items['admin/build/block/configure'] = array( |
| 141 | 161 | 'title' => 'Configure block', |
| 142 | 161 | 'page callback' => 'drupal_get_form', |
| 143 | 161 | 'page arguments' => array('block_admin_configure'), |
| 144 | 161 | 'access arguments' => array('administer blocks'), |
| 145 | 161 | 'type' => MENU_CALLBACK, |
| 146 | | ); |
| 147 | 161 | $items['admin/build/block/delete'] = array( |
| 148 | 161 | 'title' => 'Delete block', |
| 149 | 161 | 'page callback' => 'drupal_get_form', |
| 150 | 161 | 'page arguments' => array('block_box_delete'), |
| 151 | 161 | 'access arguments' => array('administer blocks'), |
| 152 | 161 | 'type' => MENU_CALLBACK, |
| 153 | | ); |
| 154 | 161 | $items['admin/build/block/add'] = array( |
| 155 | 161 | 'title' => 'Add block', |
| 156 | 161 | 'page callback' => 'drupal_get_form', |
| 157 | 161 | 'page arguments' => array('block_add_block_form'), |
| 158 | 161 | 'access arguments' => array('administer blocks'), |
| 159 | 161 | 'type' => MENU_LOCAL_TASK, |
| 160 | | ); |
| 161 | 161 | $default = variable_get('theme_default', 'garland'); |
| 162 | 161 | foreach (list_themes() as $key => $theme) { |
| 163 | 161 | $items['admin/build/block/list/' . $key] = array( |
| 164 | 161 | 'title' => check_plain($theme->info['name']), |
| 165 | 161 | 'page arguments' => array($key), |
| 166 | 161 | 'type' => $key == $default ? MENU_DEFAULT_LOCAL_TASK :
MENU_LOCAL_TASK, |
| 167 | 161 | 'weight' => $key == $default ? -10 : 0, |
| 168 | 161 | 'access callback' => '_block_themes_access', |
| 169 | 161 | 'access arguments' => array($theme), |
| 170 | | ); |
| 171 | 161 | } |
| 172 | 161 | return $items; |
| 173 | 0 | } |
| 174 | | |
| 175 | | /** |
| 176 | | * Menu item access callback - only admin or enabled themes can be
accessed. |
| 177 | | */ |
| 178 | 2366 | function _block_themes_access($theme) { |
| 179 | 22 | return user_access('administer blocks') && ($theme->status ||
$theme->name == variable_get('admin_theme', '0')); |
| 180 | 0 | } |
| 181 | | |
| 182 | | /** |
| 183 | | * Implementation of hook_block(). |
| 184 | | * |
| 185 | | * Generates the administrator-defined blocks for display. |
| 186 | | */ |
| 187 | 2366 | function block_block($op = 'list', $delta = 0, $edit = array()) { |
| 188 | | switch ($op) { |
| 189 | 32 | case 'list': |
| 190 | 31 | $blocks = array(); |
| 191 | | |
| 192 | 31 | $result = db_query('SELECT bid, info FROM {boxes} ORDER BY info'); |
| 193 | 31 | while ($block = db_fetch_object($result)) { |
| 194 | 4 | $blocks[$block->bid]['info'] = $block->info; |
| 195 | | // Not worth caching. |
| 196 | 4 | $blocks[$block->bid]['cache'] = BLOCK_NO_CACHE; |
| 197 | 4 | } |
| 198 | 31 | return $blocks; |
| 199 | | |
| 200 | 4 | case 'configure': |
| 201 | 2 | $box = array('format' => FILTER_FORMAT_DEFAULT); |
| 202 | 2 | if ($delta) { |
| 203 | 0 | $box = block_box_get($delta); |
| 204 | 0 | } |
| 205 | 2 | if (filter_access($box['format'])) { |
| 206 | 2 | return block_box_form($box); |
| 207 | 0 | } |
| 208 | 0 | break; |
| 209 | | |
| 210 | 2 | case 'save': |
| 211 | 0 | block_box_save($edit, $delta); |
| 212 | 0 | break; |
| 213 | | |
| 214 | 2 | case 'view': |
| 215 | 2 | $block = db_fetch_object(db_query('SELECT body, format FROM {boxes}
WHERE bid = %d', $delta)); |
| 216 | 2 | $data['content'] = check_markup($block->body, $block->format, FALSE); |
| 217 | 2 | return $data; |
| 218 | 0 | } |
| 219 | 0 | } |
| 220 | | |
| 221 | | /** |
| 222 | | * Update the 'blocks' DB table with the blocks currently exported by
modules. |
| 223 | | * |
| 224 | | * @return |
| 225 | | * Blocks currently exported by modules. |
| 226 | | */ |
| 227 | 2366 | function _block_rehash() { |
| 228 | 29 | global $theme_key; |
| 229 | | |
| 230 | 29 | init_theme(); |
| 231 | | |
| 232 | 29 | $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'",
$theme_key); |
| 233 | 29 | $old_blocks = array(); |
| 234 | 29 | while ($old_block = db_fetch_array($result)) { |
| 235 | 29 | $old_blocks[$old_block['module']][$old_block['delta']] = $old_block; |
| 236 | 29 | } |
| 237 | | |
| 238 | 29 | $blocks = array(); |
| 239 | | // Valid region names for the theme. |
| 240 | 29 | $regions = system_region_list($theme_key); |
| 241 | | |
| 242 | 29 | foreach (module_list() as $module) { |
| 243 | 29 | $module_blocks = module_invoke($module, 'block', 'list'); |
| 244 | 29 | if ($module_blocks) { |
| 245 | 29 | foreach ($module_blocks as $delta => $block) { |
| 246 | 29 | if (empty($old_blocks[$module][$delta])) { |
| 247 | | // If it's a new block, add identifiers. |
| 248 | 6 | $block['module'] = $module; |
| 249 | 6 | $block['delta'] = $delta; |
| 250 | 6 | $block['theme'] = $theme_key; |
| 251 | 6 | if (!isset($block['pages'])) { |
| 252 | | // {block}.pages is type 'text', so it cannot have a |
| 253 | | // default value, and not null, so we need to provide |
| 254 | | // value if the module did not. |
| 255 | 6 | $block['pages'] = ''; |
| 256 | 6 | } |
| 257 | | // Add defaults and save it into the database. |
| 258 | 6 | drupal_write_record('blocks', $block); |
| 259 | | // Set region to none if not enabled. |
| 260 | 6 | $block['region'] = $block['status'] ? $block['region'] :
BLOCK_REGION_NONE; |
| 261 | | // Add to the list of blocks we return. |
| 262 | 6 | $blocks[] = $block; |
| 263 | 6 | } |
| 264 | | else { |
| 265 | | // If it's an existing block, database settings should overwrite |
| 266 | | // the code. But aside from 'info' everything that's definable in |
| 267 | | // code is stored in the database and we do not store 'info', so
we |
| 268 | | // do not need to update the database here. |
| 269 | | // Add 'info' to this block. |
| 270 | 29 | $old_blocks[$module][$delta]['info'] = $block['info']; |
| 271 | | // If the region name does not exist, disable the block and
assign it to none. |
| 272 | 29 | if (!empty($old_blocks[$module][$delta]['region']) &&
!isset($regions[$old_blocks[$module][$delta]['region']])) { |
| 273 | 0 | drupal_set_message(t('The block %info was assigned to the
invalid region %region and has been disabled.', array('%info' =>
$old_blocks[$module][$delta]['info'], '%region' =>
$old_blocks[$module][$delta]['region'])), 'warning'); |
| 274 | 0 | $old_blocks[$module][$delta]['status'] = 0; |
| 275 | 0 | $old_blocks[$module][$delta]['region'] = BLOCK_REGION_NONE; |
| 276 | 0 | } |
| 277 | | else { |
| 278 | 29 | $old_blocks[$module][$delta]['region'] =
$old_blocks[$module][$delta]['status'] ?
$old_blocks[$module][$delta]['region'] : BLOCK_REGION_NONE; |
| 279 | | } |
| 280 | | // Add this block to the list of blocks we return. |
| 281 | 29 | $blocks[] = $old_blocks[$module][$delta]; |
| 282 | | // Remove this block from the list of blocks to be deleted. |
| 283 | 29 | unset($old_blocks[$module][$delta]); |
| 284 | | } |
| 285 | 29 | } |
| 286 | 29 | } |
| 287 | 29 | } |
| 288 | | |
| 289 | | // Remove blocks that are no longer defined by the code from the
database. |
| 290 | 29 | foreach ($old_blocks as $module => $old_module_blocks) { |
| 291 | 29 | foreach ($old_module_blocks as $delta => $block) { |
| 292 | 0 | db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s'
AND theme = '%s'", $module, $delta, $theme_key); |
| 293 | 0 | } |
| 294 | 29 | } |
| 295 | 29 | return $blocks; |
| 296 | 0 | } |
| 297 | | |
| 298 | 2366 | function block_box_get($bid) { |
| 299 | 2 | return db_fetch_array(db_query("SELECT * FROM {boxes} WHERE bid = %d",
$bid)); |
| 300 | 0 | } |
| 301 | | |
| 302 | | /** |
| 303 | | * Define the custom block form. |
| 304 | | */ |
| 305 | 2366 | function block_box_form($edit = array()) { |
| 306 | | $edit += array( |
| 307 | 2 | 'info' => '', |
| 308 | 2 | 'body' => '', |
| 309 | 0 | ); |
| 310 | 2 | $form['info'] = array( |
| 311 | 2 | '#type' => 'textfield', |
| 312 | 2 | '#title' => t('Block description'), |
| 313 | 2 | '#default_value' => $edit['info'], |
| 314 | 2 | '#maxlength' => 64, |
| 315 | 2 | '#description' => t('A brief description of your block. Used on the <a
href="@overview">block overview page</a>.', array('@overview' =>
url('admin/build/block'))), |
| 316 | 2 | '#required' => TRUE, |
| 317 | 2 | '#weight' => -19, |
| 318 | | ); |
| 319 | 2 | $form['body_field']['#weight'] = -17; |
| 320 | 2 | $form['body_field']['body'] = array( |
| 321 | 2 | '#type' => 'textarea', |
| 322 | 2 | '#title' => t('Block body'), |
| 323 | 2 | '#default_value' => $edit['body'], |
| 324 | 2 | '#input_format' => isset($edit['format']) ? $edit['format'] :
FILTER_FORMAT_DEFAULT, |
| 325 | 2 | '#rows' => 15, |
| 326 | 2 | '#description' => t('The content of the block as shown to the user.'), |
| 327 | 2 | '#weight' => -17, |
| 328 | | ); |
| 329 | | |
| 330 | 2 | return $form; |
| 331 | 0 | } |
| 332 | | |
| 333 | 2366 | function block_box_save($edit, $delta) { |
| 334 | 0 | if (!filter_access($edit['body_format'])) { |
| 335 | 0 | $edit['body_format'] = FILTER_FORMAT_DEFAULT; |
| 336 | 0 | } |
| 337 | | |
| 338 | 0 | db_query("UPDATE {boxes} SET body = '%s', info = '%s', format = %d WHERE
bid = %d", $edit['body'], $edit['info'], $edit['body_format'], $delta); |
| 339 | | |
| 340 | 0 | return TRUE; |
| 341 | 0 | } |
| 342 | | |
| 343 | | /** |
| 344 | | * Implementation of hook_user_form(). |
| 345 | | */ |
| 346 | 2366 | function block_user_form(&$edit, &$account, $category = NULL) { |
| 347 | 58 | if ($category == 'account') { |
| 348 | 15 | $rids = array_keys($account->roles); |
| 349 | 15 | $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN
{blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE
b.status = 1 AND b.custom != 0 AND (r.rid IN (" . db_placeholders($rids) .
") OR r.rid IS NULL) ORDER BY b.weight, b.module", $rids); |
| 350 | 15 | $form['block'] = array('#type' => 'fieldset', '#title' => t('Block
configuration'), '#weight' => 3, '#collapsible' => TRUE, '#tree' => TRUE); |
| 351 | 15 | while ($block = db_fetch_object($result)) { |
| 352 | 0 | $data = module_invoke($block->module, 'block', 'list'); |
| 353 | 0 | if ($data[$block->delta]['info']) { |
| 354 | 0 | $return = TRUE; |
| 355 | 0 | $form['block'][$block->module][$block->delta] = array('#type' =>
'checkbox', '#title' => check_plain($data[$block->delta]['info']),
'#default_value' => isset($account->block[$block->module][$block->delta]) ?
$account->block[$block->module][$block->delta] : ($block->custom == 1)); |
| 356 | 0 | } |
| 357 | 0 | } |
| 358 | | |
| 359 | 15 | if (!empty($return)) { |
| 360 | 0 | return $form; |
| 361 | 0 | } |
| 362 | 15 | } |
| 363 | 58 | } |
| 364 | | |
| 365 | | /** |
| 366 | | * Implementation of hook_user_validate(). |
| 367 | | */ |
| 368 | 2366 | function block_user_validate(&$edit, &$account, $category = NULL) { |
| 369 | 15 | if (empty($edit['block'])) { |
| 370 | 15 | $edit['block'] = array(); |
| 371 | 15 | } |
| 372 | 15 | return $edit; |
| 373 | 0 | } |
| 374 | | |
| 375 | | /** |
| 376 | | * Return all blocks in the specified region for the current user. |
| 377 | | * |
| 378 | | * @param $region |
| 379 | | * The name of a region. |
| 380 | | * |
| 381 | | * @return |
| 382 | | * An array of block objects, indexed with <i>module</i>_<i>delta</i>. |
| 383 | | * If you are displaying your blocks in one or two sidebars, you may
check |
| 384 | | * whether this array is empty to see how many columns are going to be |
| 385 | | * displayed. |
| 386 | | * |
| 387 | | * @todo |
| 388 | | * Now that the blocks table has a primary key, we should use that as the |
| 389 | | * array key instead of <i>module</i>_<i>delta</i>. |
| 390 | | */ |
| 391 | 2366 | function block_list($region) { |
| 392 | 1740 | static $blocks = array(); |
| 393 | | |
| 394 | 1740 | if (!count($blocks)) { |
| 395 | 1740 | $blocks = _block_load_blocks(); |
| 396 | 1740 | } |
| 397 | | |
| 398 | | // Create an empty array if there were no entries. |
| 399 | 1740 | if (!isset($blocks[$region])) { |
| 400 | 1740 | $blocks[$region] = array(); |
| 401 | 1740 | } |
| 402 | | |
| 403 | 1740 | $blocks[$region] = _block_render_blocks($blocks[$region]); |
| 404 | | |
| 405 | 1740 | return $blocks[$region]; |
| 406 | 0 | } |
| 407 | | |
| 408 | | /** |
| 409 | | * Load blocks information from the database. |
| 410 | | */ |
| 411 | 2366 | function _block_load_blocks() { |
| 412 | 1740 | global $user, $theme_key; |
| 413 | | |
| 414 | 1740 | $blocks = array(); |
| 415 | 1740 | $rids = array_keys($user->roles); |
| 416 | 1740 | $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b
LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta
WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (" .
db_placeholders($rids) . ") OR r.rid IS NULL) ORDER BY b.region, b.weight,
b.module", 'b', 'bid'), array_merge(array($theme_key), $rids)); |
| 417 | 1740 | while ($block = db_fetch_object($result)) { |
| 418 | 1740 | if (!isset($blocks[$block->region])) { |
| 419 | 1740 | $blocks[$block->region] = array(); |
| 420 | 1740 | } |
| 421 | | // Use the user's block visibility setting, if necessary. |
| 422 | 1740 | if ($block->custom != 0) { |
| 423 | 0 | if ($user->uid && isset($user->block[$block->module][$block->delta]))
{ |
| 424 | 0 | $enabled = $user->block[$block->module][$block->delta]; |
| 425 | 0 | } |
| 426 | | else { |
| 427 | 0 | $enabled = ($block->custom == 1); |
| 428 | | } |
| 429 | 0 | } |
| 430 | | else { |
| 431 | 1740 | $enabled = TRUE; |
| 432 | | } |
| 433 | | |
| 434 | | // Match path if necessary. |
| 435 | 1740 | if ($block->pages) { |
| 436 | 0 | if ($block->visibility < 2) { |
| 437 | 0 | $path = drupal_get_path_alias($_GET['q']); |
| 438 | | // Compare with the internal and path alias (if any). |
| 439 | 0 | $page_match = drupal_match_path($path, $block->pages); |
| 440 | 0 | if ($path != $_GET['q']) { |
| 441 | 0 | $page_match = $page_match || drupal_match_path($_GET['q'],
$block->pages); |
| 442 | 0 | } |
| 443 | | // When $block->visibility has a value of 0, the block is displayed
on |
| 444 | | // all pages except those listed in $block->pages. When set to 1,
it |
| 445 | | // is displayed only on those pages listed in $block->pages. |
| 446 | 0 | $page_match = !($block->visibility xor $page_match); |
| 447 | 0 | } |
| 448 | | else { |
| 449 | 0 | $page_match = drupal_eval($block->pages); |
| 450 | | } |
| 451 | 0 | } |
| 452 | | else { |
| 453 | 1740 | $page_match = TRUE; |
| 454 | | } |
| 455 | 1740 | $block->enabled = $enabled; |
| 456 | 1740 | $block->page_match = $page_match; |
| 457 | 1740 | $blocks[$block->region]["{$block->module}_{$block->delta}"] = $block; |
| 458 | 1740 | } |
| 459 | | |
| 460 | 1740 | return $blocks; |
| 461 | 0 | } |
| 462 | | |
| 463 | | /** |
| 464 | | * Render the content and subject for a set of blocks. |
| 465 | | * |
| 466 | | * @param $region_blocks |
| 467 | | * An array of block objects such as returned for one region by
_block_load_blocks(). |
| 468 | | * |
| 469 | | * @return |
| 470 | | * An array of visible blocks with subject and content rendered. |
| 471 | | */ |
| 472 | 2366 | function _block_render_blocks($region_blocks) { |
| 473 | 1740 | foreach ($region_blocks as $key => $block) { |
| 474 | | // Render the block content if it has not been created already. |
| 475 | 1740 | if (!isset($block->content)) { |
| 476 | | // Erase the block from the static array - we'll put it back if it
has content. |
| 477 | 1740 | unset($region_blocks[$key]); |
| 478 | 1740 | if ($block->enabled && $block->page_match) { |
| 479 | | // Try fetching the block from cache. Block caching is not
compatible with |
| 480 | | // node_access modules. We also preserve the submission of forms in
blocks, |
| 481 | | // by fetching from cache only if the request method is 'GET' (or
'HEAD'). |
| 482 | 1740 | if (!count(module_implements('node_grants')) &&
($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] ==
'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache =
cache_get($cid, 'cache_block'))) { |
| 483 | 0 | $array = $cache->data; |
| 484 | 0 | } |
| 485 | | else { |
| 486 | 1740 | $array = module_invoke($block->module, 'block', 'view',
$block->delta); |
| 487 | 1740 | if (isset($cid)) { |
| 488 | 0 | cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY); |
| 489 | 0 | } |
| 490 | | } |
| 491 | | |
| 492 | 1740 | if (isset($array) && is_array($array)) { |
| 493 | 1740 | foreach ($array as $k => $v) { |
| 494 | 1740 | $block->$k = $v; |
| 495 | 1740 | } |
| 496 | 1740 | } |
| 497 | 1740 | if (isset($block->content) && $block->content) { |
| 498 | | // Override default block title if a custom display title is
present. |
| 499 | 1740 | if ($block->title) { |
| 500 | | // Check plain here to allow module generated titles to keep
any markup. |
| 501 | 9 | $block->subject = $block->title == '<none>' ? '' :
check_plain($block->title); |
| 502 | 9 | } |
| 503 | 1740 | if (!isset($block->subject)) { |
| 504 | 1740 | $block->subject = ''; |
| 505 | 1740 | } |
| 506 | 1740 | $region_blocks["{$block->module}_{$block->delta}"] = $block; |
| 507 | 1740 | } |
| 508 | 1740 | } |
| 509 | 1740 | } |
| 510 | 1740 | } |
| 511 | 1740 | return $region_blocks; |
| 512 | 0 | } |
| 513 | | |
| 514 | | /** |
| 515 | | * Assemble the cache_id to use for a given block. |
| 516 | | * |
| 517 | | * The cache_id string reflects the viewing context for the current block |
| 518 | | * instance, obtained by concatenating the relevant context information |
| 519 | | * (user, page, ...) according to the block's cache settings (BLOCK_CACHE_* |
| 520 | | * constants). Two block instances can use the same cached content when |
| 521 | | * they share the same cache_id. |
| 522 | | * |
| 523 | | * Theme and language contexts are automatically differenciated. |
| 524 | | * |
| 525 | | * @param $block |
| 526 | | * @return |
| 527 | | * The string used as cache_id for the block. |
| 528 | | */ |
| 529 | 2366 | function _block_get_cache_id($block) { |
| 530 | 1670 | global $theme, $base_root, $user; |
| 531 | | |
| 532 | | // User 1 being out of the regular 'roles define permissions' schema, |
| 533 | | // it brings too many chances of having unwanted output get in the cache |
| 534 | | // and later be served to other users. We therefore exclude user 1 from |
| 535 | | // block caching. |
| 536 | 1670 | if (variable_get('block_cache', 0) && $block->cache != BLOCK_NO_CACHE &&
$user->uid != 1) { |
| 537 | 0 | $cid_parts = array(); |
| 538 | | |
| 539 | | // Start with common sub-patterns: block identification, theme,
language. |
| 540 | 0 | $cid_parts[] = $block->module; |
| 541 | 0 | $cid_parts[] = $block->delta; |
| 542 | 0 | $cid_parts[] = $theme; |
| 543 | 0 | if (module_exists('locale')) { |
| 544 | 0 | global $language; |
| 545 | 0 | $cid_parts[] = $language->language; |
| 546 | 0 | } |
| 547 | | |
| 548 | | // 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be
a |
| 549 | | // resource drag for sites with many users, so when a module is being |
| 550 | | // equivocal, we favor the less expensive 'PER_ROLE' pattern. |
| 551 | 0 | if ($block->cache & BLOCK_CACHE_PER_ROLE) { |
| 552 | 0 | $cid_parts[] = 'r.' . implode(',', array_keys($user->roles)); |
| 553 | 0 | } |
| 554 | 0 | elseif ($block->cache & BLOCK_CACHE_PER_USER) { |
| 555 | 0 | $cid_parts[] = "u.$user->uid"; |
| 556 | 0 | } |
| 557 | | |
| 558 | 0 | if ($block->cache & BLOCK_CACHE_PER_PAGE) { |
| 559 | 0 | $cid_parts[] = $base_root . request_uri(); |
| 560 | 0 | } |
| 561 | | |
| 562 | 0 | return implode(':', $cid_parts); |
| 563 | 0 | } |
| 564 | 1670 | } |
| 565 | 2366 | |