' . t('This list of sections is searched for matching paths from top down. The section with the first matching path is thereby used for switching the theme. Therefore you should move more specific above general path configurations. Sections can be rearranged via drag and drop. Node specific themes are not shown in this list, but take precedence above this general configuration.') . '
'; } } /** * Implementation of hook_perm(). * * Since the access to our new custom pages will be granted based on * special permissions, we need to define what those permissions are here. * This ensures that they are available to enable on the user role * administration pages. */ function sections_perm() { return array('administer sections', 'assign node theme'); } /** * Implementation of hook_menu(). */ function sections_menu() { $access = array('administer sections'); $items['admin/build/sections'] = array( 'title' => 'Sections', 'description' => 'Define sections of your site and apply themes to them.', 'page callback' => 'drupal_get_form', 'page arguments' => array('sections_admin_display_form'), 'access arguments' => $access, 'file' => 'sections.admin.inc', 'type' => MENU_NORMAL_ITEM ); $items['admin/build/sections/list'] = array( 'title' => 'List', 'page callback' => 'drupal_get_form', 'page arguments' => array('sections_admin_display_form'), 'access arguments' => $access, 'weight' => -10, 'file' => 'sections.admin.inc', 'type' => MENU_DEFAULT_LOCAL_TASK ); $items['admin/build/sections/add'] = array( 'title' => 'Add section', 'page callback' => 'drupal_get_form', 'page arguments' => array('sections_admin_settings_form'), 'access arguments' => $access, 'weight' => -9, 'file' => 'sections.admin.inc', 'type' => MENU_LOCAL_TASK ); $items['admin/build/sections/edit/%section'] = array( 'title' => 'Edit section', 'page callback' => 'drupal_get_form', 'page arguments' => array('sections_admin_settings_form', 4), 'access arguments' => $access, 'file' => 'sections.admin.inc', 'type' => MENU_CALLBACK ); $items['admin/build/sections/delete/%section'] = array( 'title' => 'Delete section', 'page callback' => 'drupal_get_form', 'page arguments' => array('sections_delete_form', 4), 'access arguments' => $access, 'file' => 'sections.admin.inc', 'type' => MENU_CALLBACK ); $items['admin/build/sections/debug'] = array( 'title' => 'Debug', 'page callback' => 'drupal_get_form', 'page arguments' => array('sections_admin_debug_form'), 'access arguments' => $access, 'weight' => -8, 'file' => 'sections.admin.inc', 'type' => MENU_LOCAL_TASK ); return $items; } /** * Implementation of hook_form_alter(). */ function sections_form_alter(&$form, $form_state, $form_id) { // Add theme selection option to node forms. if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id && user_access('assign node theme')) { $node = $form['#node']; $form['sections'] = array( '#type' => 'fieldset', '#title' => t('Theme configuration'), '#collapsible' => TRUE, '#collapsed' => !$node->sections['theme'], '#tree' => TRUE, '#weight' => 30, '#description' => t('This setting allows you to create a section per node. A node section will get the highest weight and take precedence about all other inheriting sections.') ); $form['sections']['theme'] = array( '#type' => 'select', '#title' => t('Select theme'), '#default_value' => $node->sections['theme'], '#options' => _sections_theme_select(), '#description' => t('Select the theme you want to use for this node. Disabled themes are not used until they are enabled on themes page.', array('@url' => url('admin/build/themes'))) ); } // Disable core Administration theme. if ($form_id == 'system_admin_theme_settings') { // TODO: If other modules like theme_settings add form items, these items are not disabled. $form['admin_theme']['#disabled'] = TRUE; $form['node_admin_theme']['#disabled'] = TRUE; drupal_set_message(t('The configuration options have been disabled for compatibility reasons with the sections module. Configure the administration theme via sections.', array('@sections-admin' => url('admin/build/sections'))), 'warning', FALSE); } } /** * Implementation of hook_nodeapi(). * * Manages section information for nodes. */ function sections_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { switch ($op) { case 'delete': // Node has been deleted. Remove node theme reference. db_query('DELETE FROM {sections_nodes} WHERE nid = %d', $node->nid); break; case 'insert': // Save new node with configured theme setting. if (!empty($node->sections['theme'])) { db_query("INSERT INTO {sections_nodes} (nid, theme) VALUES (%d, '%s')", $node->nid, $node->sections['theme']); } break; case 'load': $node->sections['theme'] = db_result(db_query("SELECT theme FROM {sections_nodes} WHERE nid = %d", $node->nid)); break; case 'update': $theme = db_result(db_query("SELECT theme FROM {sections_nodes} WHERE nid = %d", $node->nid)); // Update existing node theme setting. if ($theme && !empty($node->sections['theme'])) { db_query("UPDATE {sections_nodes} SET theme = '%s' WHERE nid = %d", $node->sections['theme'], $node->nid); } // Insert new node theme setting, if node already exists. elseif (!empty($node->sections['theme'])) { db_query("INSERT INTO {sections_nodes} (nid, theme) VALUES (%d, '%s')", $node->nid, $node->sections['theme']); } // Node theme has been disabled. Remove from sections_nodes table. elseif ($theme && empty($node->sections['theme'])) { db_query('DELETE FROM {sections_nodes} WHERE nid = %d', $node->nid); } break; case 'view': // TODO: Only switch the theme if the node is viewed as page and not in teaser mode. // If node specific theme is configured, switch to node theme. if (!empty($node->sections['theme'])) { _sections_switch_theme($node->sections['theme']); } break; } } /** * Implementation of hook_theme() */ function sections_theme() { return array( 'sections_admin_display_form' => array( 'file' => 'sections.admin.inc', 'arguments' => array('form' => NULL), ), ); } /** * Implementation of hook_init(). */ function sections_init() { if ($section = _sections_in_section()) { _sections_switch_theme($section->theme); } } /** * Menu helper function to verify if section exists. */ function section_load($section) { return db_fetch_object(db_query("SELECT * FROM {sections_data} WHERE sid = %d", $section)); } /** * Loads the options for the themes select form element. */ function _sections_theme_select() { $options = array(); $options[0] = '<'. t('System default') .'>'; foreach (list_themes() as $key => $theme) { $options[$theme->name] = t('@name (@status)', array('@name' => $theme->info['name'], '@status' => ($theme->status ? t('Enabled') : t('Disabled')))); } return $options; } /** * Change the current theme to a custom theme. * * @param $sections_theme * The theme_key of the custom theme that should be used. */ function _sections_switch_theme($section_theme = NULL) { global $theme; if (!empty($section_theme)) { // Only switch to custom theme if theme is active, to prohibit a destroyed site. foreach (list_themes() as $key => $theme_object) { if ($theme_object->status == 1 && $theme_object->name == $section_theme) { global $custom_theme; $custom_theme = $section_theme; // REMARK: If a theme has already been initialized, this init_theme() does // not change the theme to a different one for static caching reasons. init_theme(); // DEBUG messages for easier self analysis which theme has won the theme switch challenge. if (variable_get('sections_debug', FALSE)) { if ($theme == $section_theme) { drupal_set_message(t('DEBUG_THEME_SWITCH: Successfully changed the current active theme to "@theme".', array('@theme' => $theme)), 'status'); } else { // TODO: Investigate if overriding works in future Drupal versions. drupal_set_message(t('DEBUG_THEME_SWITCH: Theme switch to "@theme" has failed for unknown reasons. Sections module cannot solve this problem themself. You need to investigate this bug in your modules. The functioninit_theme()
may have been executed by other code outside the sections module. A typical reason may be the function theme()
that is used by t()
if a %
placeholder is inside a translatable string. The theme()
function automatically initializes the theme system and cannot overridden by modules for some reasons.', array('@theme' => $theme)), 'error');
}
}
}
elseif ($theme_object->status == 0 && $theme_object->name == $section_theme) {
// DEBUG message for easier self analysis which theme has won the theme switch challenge.
if (variable_get('sections_debug', FALSE)) {
drupal_set_message(t('DEBUG_THEME_SWITCH: Theme switch has been failed. Theme "@theme" is disabled!', array('@theme' => $custom_theme)), 'warning');
}
}
}
}
}
/**
* An API for modules that want to know about sections.
*
* This API is a function that lets you find out about settings.
*
* @param $section
* Optional $setting a string containing the section you what to test against.
* @return
* Depends on the $section parameter:
* - If you do not provide $section, it will return the section object, if found.
* - If you provide $section, it will return TRUE if you are in that section.
* - Otherwise it will return FALSE.
*/
function _sections_in_section($section = NULL) {
global $user;
if (is_string($section)) {
// Caller wants to know if she's in the section she provided.
if ($section == _sections_in_section()) {
return TRUE;
}
}
else {
// Caller wants to know in which section she is.
$rids = array_keys($user->roles);
$res = _sections_path_cache_get($rids);
foreach ($res as $sid => $row) {
if ($row->visibility < 2) {
$path = drupal_get_path_alias($_GET['q']);
// Compare with the internal and path alias (if any).
$page_match = drupal_match_path($path, $row->path);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $row->path);
}
// When $row->visibility has a value of 0, the block is displayed on
// all pages except those listed in $row->path. When set to 1, it
// is displayed only on those pages listed in $row->path. Prevent
// the admin theme switching on block admin pages.
if ($page_match = !($row->visibility xor $page_match) && !(drupal_match_path($path, "admin/build/block\nadmin/build/block/list\nadmin/build/block/list/*"))) {
if (variable_get('sections_debug', FALSE)) {
// DEBUG message for easier self analysis which theme has been matched.
// Never use % placeholder or init_theme get's executed and theme switch fails.
drupal_set_message(t('DEBUG_MATCH_DETECT: Found section #@sid for path "@path" with theme "@theme".', array('@theme' => $row->theme, '@path' => $row->path, '@sid' => $row->sid)), 'status', FALSE);
}
return $row;
}
}
else {
if (drupal_eval($row->path)) {
if (variable_get('sections_debug', FALSE)) {
// DEBUG message for easier self analysis which theme has been evaluated.
// Never use % placeholder or init_theme get's executed and theme switch fails.
drupal_set_message(t('DEBUG_EVAL_DETECT: Found section #@sid for path "@path" with theme "@theme".', array('@theme' => $row->theme, '@path' => $row->path, '@sid' => $row->sid)), 'status', FALSE);
}
return $row;
}
}
}
}
// No section has been found, return FALSE.
return FALSE;
}
/**
* An internal caching function that statically caches the path based sections.
*
* @param $rids
* Array of role id's, the current user belongs too.
* @param $reset
* Manually resets the sections path cache for the current user roles.
* @return
* Cached path sections data.
*/
function _sections_path_cache_get($rids, $reset = FALSE) {
static $sections = array();
// Create a key to cache the sections path data by user roles.
$rids_key = implode('_', $rids);
if (!isset($sections[$rids_key]) || $reset) {
$sections[$rids_key] = array();
// Collect sections path data from database and statically cache the data by rids.
$result = db_query(db_rewrite_sql("SELECT DISTINCT s.* FROM {sections_data} s LEFT JOIN {sections_roles} r ON s.sid = r.sid WHERE s.status = 1 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY s.weight", 's', 'sid'), $rids);
while ($row = db_fetch_object($result)) {
$sections[$rids_key][$row->sid] = $row;
}
}
// Return cached path sections data.
return $sections[$rids_key];
}
/**
* Implementation of hook_preprocess().
*/
function sections_preprocess(&$variables, $hook) {
// Are we in a section?
if ($section = _sections_in_section()) {
// Clean up the section names for template file names.
$filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
$name_clean = preg_replace($filter, '-', drupal_strtolower($section->name));
// Add some section information to all preprocess hooks.
$variables['section'] = array(
'sid' => $section->sid,
'theme' => $section->theme,
'name_clean' => $name_clean,
);
switch ($hook) {
case 'page':
// Add template suggestions for page templates.
$variables['template_files'][] = 'page-sections';
$variables['template_files'][] = 'page-sections-'. $section->sid;
$variables['template_files'][] = 'page-sections-'. $name_clean;
break;
case 'node':
// Add template suggestions for node templates.
$variables['template_files'][] = 'node-sections';
$variables['template_files'][] = 'node-sections-'. $section->sid;
$variables['template_files'][] = 'node-sections-'. $name_clean;
break;
case 'block':
// Add template suggestions for block templates.
$variables['template_files'][] = 'block-sections';
$variables['template_files'][] = 'block-sections-'. $section->sid;
$variables['template_files'][] = 'block-sections-'. $name_clean;
break;
}
}
}