of course) * 1) Generate a simple sidebar. Useful if you just want an extra sidebar, or * for regions with a single block * * * 2) Generate blocks one by one for a region. Useful for including code between * blocks e.g. to lay them out in a horizontal table. * * * * * * 3) Total control over layout of individual blocks within a region. * *

* * * * Note that flexiblock is integrated into wgSmarty which makes it even simpler * to use: example 3 above becomes * {foreach from=$blocks.2 item=block} *

{$block.subject}

* {$block.content} * {/foreach} */ /** * Implementation of hook_help(). */ function flexiblock_help( $section ) { switch ( $section ) { case 'admin/help#flexiblock': return t( '

Blocks are the boxes visible in the sidebar(s) of your web site. These are usually generated automatically by modules (e.g. recent forum topics), but you can also create your own blocks.

The sidebar each block appears in depends on both which theme you are using (some are left-only, some right, some both), and on the settings in block management.

The block management screen lets you specify the vertical sort-order of the blocks within a sidebar. You do this by assigning a weight to each block. Lighter blocks (smaller weight) "float up" towards the top of the sidebar. Heavier ones "sink down" towards the bottom of it.

A block\'s visibility depends on:

Administrator defined blocks

An administrator defined block contains content supplied by you (as opposed to being generated automatically by a module). Each admin-defined block consists of a title, a description, and a body which can be as long as you wish. The Drupal engine will render the content of the block.

' ); case 'admin/block': return t( '

Themes that support flexiblock use the regions in the \'location\' column. Legacy themes use the settings in the \'Sidebar\' column. If you are having problems with flexiblock, the debug page might help.

', array( '%debug' => url( 'admin/block/debug' ) ) ); } } /** * Implementation of hook_perm(). */ function flexiblock_perm() { return array( 'administer blocks', 'administer block regions' ); } /** * Implementation of hook_menu(). */ function flexiblock_menu( $may_cache ) { $items = array(); if ( $may_cache ) { $items[] = array( 'path' => 'admin/block', 'title' => t( 'blocks' ), 'access' => user_access( 'administer blocks' ), 'callback' => 'flexiblock_admin' ); $items[] = array( 'path' => 'admin/block/debug', 'title' => t( 'debug' ), 'access' => user_access( 'administer blocks' ), 'callback' => 'flexiblock_admin_debug', 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'admin/settings/regions', 'title' => t( 'regions' ), 'access' => user_access( 'administer block regions' ), 'callback' => 'flexiblock_regions' ); $items[] = array( 'path' => 'admin/settings/regions/list', 'title' => t( 'list' ), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10 ); foreach ( list_themes() as $key => $theme ) { if ( $theme->status ) { if ( $key == variable_get( 'theme_default', 'bluemarine' ) ) { $items[] = array( 'path' => 'admin/settings/regions/list/' . $key, 'title' => t( '\'%key\' settings', array( '%key' => $key ) ), 'access' => user_access( 'administer block regions' ), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10 ); } else { $items[] = array( 'path' => 'admin/settings/regions/list/' . $key, 'title' => t( '\'%key\' settings', array( '%key' => $key ) ), 'access' => user_access( 'administer block regions' ), 'type' => MENU_LOCAL_TASK ); } $items[] = array( 'path' => 'admin/settings/regions/list/' . $key . '/add', 'title' => t( 'add region to \'' . $key . '\'' ), 'access' => user_access( 'administer block regions' ), 'callback' => 'flexiblock_regions_add', 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'admin/settings/regions/list/' . $key . '/edit', 'title' => t( 'edit region' ), 'access' => user_access( 'administer block regions' ), 'callback' => 'flexiblock_regions_edit', 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'admin/settings/regions/list/' . $key . '/delete', 'title' => t( 'delete region' ), 'access' => user_access( 'administer block regions' ), 'callback' => 'flexiblock_regions_delete', 'type' => MENU_CALLBACK ); } } } return $items; } /** * Menu callback; displays the flexiblock admin overview page. */ function flexiblock_admin() { $edit = $_POST['edit']; $op = $_POST['op']; if ( $op == t( 'Save blocks' ) ) { drupal_set_message( flexiblock_admin_save( 'blocks', $edit ) ); cache_clear_all(); drupal_goto( $_GET['q'] ); } print theme( 'page', flexiblock_admin_display() ); } /** * Prepare the main block administration form. */ function flexiblock_admin_display() { global $theme_key, $custom_theme; // If non-default theme configuration has been selected, set the custom theme. $custom_theme = variable_get( 'theme_default', 'bluemarine' ); if ( arg( 3 ) ) $custom_theme = arg( 3 ); init_theme(); $blocks = _block_rehash(); $block_regions = system_region_list( $theme_key ); $block_regions['flexi'] = 'flexible region'; $mapping = _flexiblock_get_mapping( $theme_key ); $throttle = module_exist( 'throttle' ); $form['#action'] = arg( 3 ) ? url( 'admin/block/list/' . $theme_key ) : url( 'admin/block' ); $form['#method'] = 'post'; $form['#tree'] = true; $select_mapping = array(); $select_mapping['-1'] = 'None'; foreach( _flexiblock_get_regions( $theme_key ) as $key => $region ) { $select_mapping[$key] = $region; } foreach ( $blocks as $block ) { $delete = ''; if ( $block['module'] == 'block' ) $delete = l( t( 'delete' ), 'admin/block/delete/' . $block['delta'] ); $form[$block['module']][$block['delta']]['info'] = array( '#type' => 'markup', '#value' => $block['info'] ); $form[$block['module']][$block['delta']]['status'] = array( '#type' => 'checkbox', '#default_value' => $block['status'] ); $form[$block['module']][$block['delta']]['theme'] = array( '#type' => 'hidden', '#value' => $theme_key ); $form[$block['module']][$block['delta']]['weight'] = array( '#type' => 'weight', '#default_value' => $block['weight'] ); $form[$block['module']][$block['delta']]['region'] = array( '#type' => 'select', '#default_value' => isset( $block['region'] ) ? $block['region'] : system_default_region(), '#options' => $block_regions ); if ( $throttle ) $form[$block['module']][$block['delta']]['throttle'] = array( '#type' => 'checkbox', '#default_value' => $block['throttle'] ); $_mapping = !isset( $mapping[$block['module'] . '_' . $block['delta']] ) ? -1 : $mapping[$block['module'] . '_' . $block['delta']]; $form[$block['module']][$block['delta']]['flexi_region'] = array( '#type' => 'select', '#default_value' => $_mapping, '#options' => $select_mapping ); $form[$block['module']][$block['delta']]['configure'] = array( '#type' => 'markup', '#value' => l( t( 'configure' ), 'admin/block/configure/' . $block['module'] . '/' . $block['delta'] ) ); if ( $block['module'] == 'block' ) $form[$block['module']][$block['delta']]['delete'] = array( '#type' => 'markup', '#value' => l( t( 'delete' ), 'admin/block/delete/' . $block['delta'] ) ); } $form['submit'] = array( '#type' => 'submit', '#value' => t( 'Save blocks' ) ); return drupal_get_form( 'flexiblock_admin_display', $form ); } function theme_flexiblock_admin_display( $form ) { global $theme_key; $throttle = module_exist( 'throttle' ); $_colspan = $throttle ? 8 : 7 ; $block_regions = system_region_list( $theme_key ); // Highlight regions on page, to provide visual reference. foreach ( $block_regions as $key => $value ) { drupal_set_content( $key, '
' . $value . '
' ); } $regions = array(); $disabled = array(); foreach ( element_children( $form ) as $module ) { // Don't take form control structures if ( is_array( $form[$module] ) ) { foreach ( $form[$module] as $delta => $element ) { // Only take form elements that are blocks if ( is_array( $form[$module][$delta]['info'] ) ) { $block = $form[$module][$delta]; $row = array( array( 'data' => form_render( $block['info'] ), 'class' => 'block' ), form_render( $block['status'] ) . form_render( $block['theme'] ), form_render( $block['weight'] ), form_render( $block['region'] ), form_render( $block['flexi_region'] ) ); if ( $throttle ) $row[] = form_render( $block['throttle'] ); $row[] = form_render( $block['configure'] ); $row[] = $block['delete'] ? form_render( $block['delete'] ) : ''; if ( $block['region']['#value'] == 'flexi' ) { $flexi[$block['flexi_region']['#default_value']][] = $row; } else { if ( $block['status']['#default_value'] ) { $regions[$block['region']['#default_value']][] = $row; } else if ( $block['region']['#default_value'] <= 1 ) { $disabled[] = $row; } } } } } } $rows = array(); if ( count( $regions ) ) { foreach ( $regions as $region => $row ) { $region_title = t( '%region', array( '%region' => ucfirst( $block_regions[$region] ) ) ); $rows[] = array( array( 'data' => $region_title, 'class' => 'region', 'colspan' => $_colspan ) ); $rows = array_merge( $rows, $row ); } } if ( count( $flexi ) ) { $flexi_regions = _flexiblock_get_regions( $theme_key ); ksort( $flexi ); foreach ( $flexi as $region => $_flexi ) { $rows[] = array( array( 'data' => t( 'Flexiblock location: ' ) . $flexi_regions[$region], 'class' => 'region', 'colspan' => $_colspan ) ); $rows = array_merge( $rows, $_flexi ); } } if ( count( $disabled ) ) { $rows[] = array( array( 'data' => t( 'Disabled' ), 'class' => 'region', 'colspan' => $_colspan ) ); $rows = array_merge( $rows, $disabled ); } $header = array( t( 'Block' ), t( 'Enabled' ), t( 'Weight' ), t( 'Placement' ) ); if ( $throttle ) $header[] = t( 'Throttle' ); $header[] = t( 'Location' ); $header[] = array( 'data' => t( 'Operations' ), 'colspan' => 2 ); $output = theme( 'table', $header, $rows, array( 'id' => 'blocks' ) ); $output .= form_render( $form['submit'] ); return $output; } function flexiblock_regions() { $edit = $_POST['edit']; $op = $_POST['op']; if ( $op == t( 'Add region' ) ) { drupal_set_message( flexiblock_admin_save( 'regions_add', $edit ) ); } elseif ( $op == t( 'Update region' ) ) { drupal_set_message( flexiblock_admin_save( 'regions_update', $edit ) ); } elseif ( $op == t( 'Delete region' ) ) { drupal_set_message( flexiblock_admin_save( 'regions_delete', $edit ) ); } if ( in_array( $op, array( t( 'Add region' ), t( 'Update region' ), t( 'Delete region' ) ) ) ) { cache_clear_all(); drupal_goto( $_GET['q'] ); } print theme( 'page', flexiblock_regions_display() ); } function flexiblock_regions_display() { global $theme_key; _init_selected_theme(); $regions = _flexiblock_get_regions( $theme_key ); $form['#action'] = arg( 4 ) ? url( 'admin/settings/regions/list/' . $theme_key ) : url( 'admin/settings/regions' ); $form['#method'] = 'post'; $form['#tree'] = true; foreach( $regions as $key => $value ) { $form['regions'][$key]['name'] = array( '#type' => 'markup', '#value' => $value ); $form['regions'][$key]['edit'] = array( '#type' => 'markup', '#value' => l( t( 'edit' ), 'admin/settings/regions/list/' . $theme_key . '/edit/' . $key ) ); $form['regions'][$key]['delete'] = array( '#type' => 'markup', '#value' => l( t( 'delete' ), 'admin/settings/regions/list/' . $theme_key . '/delete/' . $key ) ); } return drupal_get_form( 'flexiblock_regions_display', $form ); } function theme_flexiblock_regions_display( $form ) { global $theme_key; $header = array(); $header[] = t( 'Region' ); $header[] = array( 'data' => t( 'Operations' ), 'colspan' => 2 ); $rows = array(); $row = array(); $rows = array(); foreach( $form['regions'] as $delta => $region ) { if ( !is_array( $region['name'] ) ) continue; $row = array( form_render( $region['name'] ) ); $row[] = form_render( $region['edit'] ); $row[] = form_render( $region['delete'] ); $rows[] = $row; } $output = theme( 'table', $header, $rows, array( 'id' => 'regions' ) ); $output .= '
'; $output .= l( t( 'add region' ), 'admin/settings/regions/list/' . $theme_key . '/add' ); return $output; } function flexiblock_regions_add() { global $theme_key; _init_selected_theme(); $form['#action'] = arg( 4 ) ? url( 'admin/settings/regions/list/' . $theme_key ) : url( 'admin/settings/regions' ); $form['#method'] = 'post'; $form['#tree'] = true; $form['region_name'] = array( '#type' => 'textfield', '#title' => t( 'Region name' ), '#description' => t( 'Specify the name of the new region' ), '#size' => 25, '#maxlength' => 100, '#required' => false ); $form['submit'] = array( '#type' => 'submit', '#value' => t( 'Add region' ) ); return drupal_get_form( 'flexiblock_regions_add', $form ); } function theme_flexiblock_regions_add( $form ) { $output = form_render( $form['region_name'] ); $output .= form_render( $form['submit'] ); return $output; } function flexiblock_regions_edit() { global $theme_key; _init_selected_theme(); if ( !is_numeric( arg( 6 ) ) || ( arg( 6 ) < 0 ) ) return t( 'Wrong region-index.' ); $regions = _flexiblock_get_regions( $theme_key ); if ( !isset( $regions[arg( 6 )] ) ) return t( 'Could not find this region.' ); $form['#action'] = arg( 4 ) ? url( 'admin/settings/regions/list/' . $theme_key ) : url( 'admin/settings/regions' ); $form['#method'] = 'post'; $form['#tree'] = true; $form['rid'] = array( '#type' => 'hidden', '#value' => arg( 6 ) ); $form['region_name'] = array( '#type' => 'textfield', '#title' => t( 'Region name' ), '#description' => t( 'Specify the new name of this region' ), '#size' => 25, '#maxlength' => 100, '#value' => $regions[arg( 6 )], '#required' => false ); $form['submit'] = array( '#type' => 'submit', '#value' => t( 'Update region' ) ); return drupal_get_form( 'flexiblock_regions_edit', $form ); } function theme_flexiblock_regions_edit( $form ) { if ( !isset( $form['#action'] ) ) return $form; $output = form_render( $form['region_name'] ); $output .= form_render( $form['rid'] ); $output .= form_render( $form['submit'] ); return $output; } function flexiblock_regions_delete() { global $theme_key; _init_selected_theme(); if ( !is_numeric( arg( 6 ) ) || ( arg( 6 ) < 0 ) ) return t( 'Wrong region-index.' ); $regions = _flexiblock_get_regions( $theme_key ); if ( !isset( $regions[arg( 6 )] ) ) return t( 'Could not find this region.' ); $action = ( variable_get( 'theme_default', 'bluemarine' ) != arg( 4 ) ) ? 'admin/settings/regions/list/' . $theme_key : 'admin/settings/regions'; $form['#action'] = url( $action ); $form['rid'] = array( '#type' => 'hidden', '#value' => arg( 6 ) ); return confirm_form( '_flexiblock_regions_delete_regions', $form, t( 'Are you sure you want to delete this region?' ), $action, '', t( 'Delete region' ), t( 'Cancel' ) ); } function flexiblock_admin_save( $area, $edit ) { if ( $area == 'blocks' ) { return _flexiblock_save_blocks( $edit ); } elseif ( substr( $area, 0, 7 ) == 'regions' ) { return _flexiblock_save_regions( $edit, substr( $area, 8 ) ); } } function _flexiblock_save_blocks( $edit ) { $mapping = array(); foreach ( $edit as $module => $blocks ) { foreach ( $blocks as $delta => $block ) { db_query( "UPDATE {blocks} SET status = %d, weight = %d, region = '%s', throttle = %d " . "WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $block['status'], $block['weight'], $block['region'], $block['throttle'], $module, $delta, $block['theme'] ); // build up flexiblock mapping if ( $block['region'] == 'flexi' && $block['flexi_region'] > -1 ) { $mapping["{$module}_$delta"] = $block['flexi_region']; } } } // allow mapping by theme global $theme_key, $custom_theme; // If non-default theme configuration has been selected, set the custom theme. $custom_theme = variable_get( 'theme_default', 'bluemarine' ); if ( arg( 3 ) ) $custom_theme = arg( 3 ); init_theme(); _flexiblock_set_mapping( $theme_key, $mapping ); return t( 'The flexiblock settings have been updated.' ); } function _flexiblock_get_regions( $theme ) { return variable_get( 'flexiblock_regions_' . $theme, array() ); } function _flexiblock_save_regions( $edit, $type ) { switch ( $type ) { case 'add': return _flexiblock_regions_add_regions( $edit ); break; case 'update': return _flexiblock_regions_update_regions( $edit ); break; case 'delete': return _flexiblock_regions_delete_regions( $edit ); break; } // switch return t( 'Unrecognized action-type.' ); } function _flexiblock_regions_add_regions( $edit ) { global $theme_key; _init_selected_theme(); // check if name is empty if ( empty( $edit['region_name'] ) ) { form_set_error( 'region_name', t( 'Please insert a name if you want to define a new region.' ) ); return ; } $regions = _flexiblock_get_regions( $theme_key ); // check if name already defined if ( in_array( $edit['region_name'], $regions ) ) { form_set_error( 'region_name', t( 'Region name "' . $edit['region_name'] . '" already defined for this theme.' ) ); return ; } // store the new region $regions[] = $edit['region_name']; variable_set( 'flexiblock_regions_' . $theme_key, $regions ); return t( 'added new region' ); } function _flexiblock_regions_update_regions( $edit ) { global $theme_key; _init_selected_theme(); // check if name is empty if ( empty( $edit['region_name'] ) ) { form_set_error( 'region_name', t( 'Please insert a name for this region.' ) ); return ; } $regions = _flexiblock_get_regions( $theme_key ); // name hasn't changed if ( $edit['region_name'] == $regions[$edit['rid']] ) { return t( 'Nothing to update.' ); } // check if name already defined if ( in_array( $edit['region_name'], $regions ) ) { form_set_error( 'region_name', t( 'Region name "' . $edit['region_name'] . '" already defined for this theme.' ) ); return ; } // save the new name $regions[$edit['rid']] = $edit['region_name']; variable_set( 'flexiblock_regions_' . $theme_key, $regions ); return t( 'updated region' ); } function _flexiblock_regions_delete_regions( $edit ) { global $theme_key; _init_selected_theme(); $regions = _flexiblock_get_regions( $theme_key ); unset( $regions[$edit['rid']] ); variable_set( 'flexiblock_regions_' . $theme_key, $regions ); drupal_set_message( t( 'The region has been removed.' ) ); cache_clear_all(); } /** * Display information to help debugging. */ function flexiblock_admin_debug() { ob_start(); echo "\nDefault mapping\n"; print_r( variable_get( 'flexiblock_mapping', array() ) ); echo "\nCurrent mapping\n"; print_r( _flexiblock_get_mapping() ); echo "\nFlexiblock block list\n"; print_r( theme_flexiblock_blocks() ); echo "\nLegacy block list\n"; print_r( block_list( 'all' ) ); $content = '
' . htmlspecialchars( ob_get_clean() ) . '
'; print theme( 'page', $content ); } // PRIVATE FUNCTIONS ******************************************************************* function _flexiblock_get_mapping( $theme = false ) { if ( !$theme ) { // REVISIT is there a proper API to do this? $theme = $GLOBALS['theme']; } $mapping = variable_get( 'flexiblock_mapping', array() ); if ( isset( $mapping['themes'][$theme] ) ) { $mapping = variable_get( 'flexiblock_mapping_' . $theme, array() ); } else { $theme = false; } $mapping['theme'] = $theme; return $mapping; } // save block mapping for a theme // for the default mapping, set $theme to 'default' // to clear a mapping (not for default!) omit $mapping or set to FALSE function _flexiblock_set_mapping( $theme, $mapping = false ) { // TODO look at this and the calling code so it deals // with empty mappings as intended if ( $mapping !== false ) { if ( $theme == 'default' ) { // get individually mapped themes and add to default mapping $default = _flexiblock_get_mapping( 'default' ); $mapping['themes'] = $default['themes']; variable_set( 'flexiblock_mapping', $mapping ); } else { variable_set( 'flexiblock_mapping_' . $theme, $mapping ); // add to array of individually mapped themes $default = _flexiblock_get_mapping( 'default' ); $default['themes'][$theme] = true; variable_set( 'flexiblock_mapping', $default ); } } elseif ( $theme != 'default' ) // cannot delete default mapping { // clear mapping for theme variable_clear( 'flexiblock_mapping_' . $theme ); // remove from array of individually mapped themes $default = _flexiblock_get_mapping( 'default' ); if ( isset( $default['themes'][$theme] ) ) { unset( $default['themes'][$theme] ); } variable_set( 'flexiblock_mapping', $default ); } } // THEME FUNCTIONS ******************************************************************* // generate the html for the blocks in a region, returning an array with each element // containing a block, including the html generated by the block. // The calling function can then assemble the elements into a table or whatever. // blocks and their output, sorted by region, are cached to avoid // expensive function theme_flexiblock_blocks( $region = false ) { static $blocks, $regions; // run all flexiblock blocks if ( !isset( $blocks ) ) { $regions = array(); // get all the blocks $blocks = block_list( 'flexi', array( 'flexi' => 99 ) ); $mapping = _flexiblock_get_mapping(); foreach ( $blocks as $key => $block ) { if ( isset( $mapping[$key] ) ) { $_region = $mapping[$key]; } else { $_region = 0; } $regions[$_region][$key] = ( array )$blocks[$key]; } // TODO sort by weight } if ( $region === false ) { // return the whole array of blocks return $regions; } else { // return the blocks for the requested region if ( isset( $regions[$region] ) ) { return $regions[$region]; } else { return array(); } } } // generate the html for a region. This is simply the html for each block concatenated. // Themes should use theme_flexiblock_blocks as that offers more flexibility, but does // require the theme to iterate over the blocks function theme_flexiblock_html( $region = 0 ) { $blocks = theme_flexiblock_blocks( $region ); $output = ''; foreach ( $blocks as $block ) { $output .= theme( 'block', ( object )$block ); } echo $output; } // generate the HTML for a block function theme_flexiblock_block( $block ) { return theme( 'block', ( object )$block ); } function _init_selected_theme( $arg = 4 ) { global $theme_key, $custom_theme; // If non-default theme configuration has been selected, set the custom theme. $custom_theme = variable_get( 'theme_default', 'bluemarine' ); if ( arg( $arg ) ) // admin/settings/regions/list/xxx $custom_theme = arg( $arg ); init_theme(); }