summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/block/block.admin.inc11
-rw-r--r--modules/block/block.module22
-rw-r--r--modules/menu/menu.api.php7
-rw-r--r--modules/node/node.module13
-rw-r--r--modules/simpletest/tests/menu.test78
-rw-r--r--modules/simpletest/tests/menu_test.module64
-rw-r--r--modules/system/system.admin.inc2
-rw-r--r--modules/system/system.install23
-rw-r--r--modules/system/system.module14
9 files changed, 213 insertions, 21 deletions
diff --git a/modules/block/block.admin.inc b/modules/block/block.admin.inc
index 455b48b38..a1e65457d 100644
--- a/modules/block/block.admin.inc
+++ b/modules/block/block.admin.inc
@@ -10,11 +10,6 @@
* Menu callback for admin/structure/block.
*/
function block_admin_display($theme = NULL) {
- global $custom_theme;
-
- // If non-default theme configuration has been selected, set the custom theme.
- $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland');
-
// Fetch and sort blocks.
$blocks = _block_rehash();
usort($blocks, '_block_compare');
@@ -26,14 +21,10 @@ function block_admin_display($theme = NULL) {
* Generate main blocks administration form.
*/
function block_admin_display_form($form, &$form_state, $blocks, $theme = NULL) {
- global $theme_key, $custom_theme;
+ global $theme_key;
drupal_add_css(drupal_get_path('module', 'block') . '/block.css', array('preprocess' => FALSE));
- // If non-default theme configuration has been selected, set the custom theme.
- $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland');
- drupal_theme_initialize();
-
$block_regions = system_region_list($theme_key, REGIONS_VISIBLE) + array(BLOCK_REGION_NONE => '<' . t('none') . '>');
// Weights range from -delta to +delta, so delta should be at least half
diff --git a/modules/block/block.module b/modules/block/block.module
index 887366387..66aed9651 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -76,6 +76,7 @@ function block_menu() {
'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
'page callback' => 'block_admin_display',
'access arguments' => array('administer blocks'),
+ 'theme callback' => '_block_custom_theme',
'file' => 'block.admin.inc',
);
$items['admin/structure/block/list'] = array(
@@ -123,6 +124,8 @@ function block_menu() {
'weight' => $key == $default ? -10 : 0,
'access callback' => '_block_themes_access',
'access arguments' => array($theme),
+ 'theme callback' => '_block_custom_theme',
+ 'theme arguments' => array($key),
'file' => 'block.admin.inc',
);
}
@@ -133,8 +136,23 @@ function block_menu() {
* Menu item access callback - only admin or enabled themes can be accessed.
*/
function _block_themes_access($theme) {
- $admin_theme = variable_get('admin_theme');
- return user_access('administer blocks') && ($theme->status || ($admin_theme && ($theme->name == $admin_theme)));
+ return user_access('administer blocks') && drupal_theme_access($theme);
+}
+
+/**
+ * Theme callback for the block configuration pages.
+ *
+ * @param $theme
+ * The theme whose blocks are being configured. If not set, the default theme
+ * is assumed.
+ * @return
+ * The theme that should be used for the block configuration page, or NULL
+ * to indicate that the default theme should be used.
+ */
+function _block_custom_theme($theme = NULL) {
+ // We return exactly what was passed in, to guarantee that the page will
+ // always be displayed using the theme whose blocks are being configured.
+ return $theme;
}
/**
diff --git a/modules/menu/menu.api.php b/modules/menu/menu.api.php
index 99fcb8e20..d64f9b34c 100644
--- a/modules/menu/menu.api.php
+++ b/modules/menu/menu.api.php
@@ -40,6 +40,13 @@
* user_access() unless a value is inherited from a parent menu item.
* - "access arguments": An array of arguments to pass to the access callback
* function. Integer values pass the corresponding URL component.
+ * - "theme callback": Optional. A function returning the machine-readable
+ * name of the theme that will be used to render the page. If the function
+ * returns nothing, the main site theme will be used. If no function is
+ * provided, the main site theme will also be used, unless a value is
+ * inherited from a parent menu item.
+ * - "theme arguments": An array of arguments to pass to the theme callback
+ * function. Integer values pass the corresponding URL component.
* - "file": A file that will be included before the callbacks are accessed;
* this allows callback functions to be in separate files. The file should
* be relative to the implementing module's directory unless otherwise
diff --git a/modules/node/node.module b/modules/node/node.module
index ba3dba855..b826cc4e4 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1652,6 +1652,7 @@ function node_menu() {
'access callback' => '_node_add_access',
'weight' => 1,
'menu_name' => 'management',
+ 'theme callback' => '_node_custom_theme',
'file' => 'node.pages.inc',
);
$items['rss.xml'] = array(
@@ -1713,6 +1714,7 @@ function node_menu() {
'page arguments' => array(1),
'access callback' => 'node_access',
'access arguments' => array('update', 1),
+ 'theme callback' => '_node_custom_theme',
'weight' => 1,
'type' => MENU_LOCAL_TASK,
'file' => 'node.pages.inc',
@@ -1777,6 +1779,17 @@ function node_page_title($node) {
}
/**
+ * Theme callback for creating and editing nodes.
+ */
+function _node_custom_theme() {
+ // Use the administration theme if the site is configured to use it for
+ // nodes.
+ if (variable_get('node_admin_theme')) {
+ return variable_get('admin_theme');
+ }
+}
+
+/**
* Implement hook_init().
*/
function node_init() {
diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test
index 26443f74e..d8ac5a882 100644
--- a/modules/simpletest/tests/menu.test
+++ b/modules/simpletest/tests/menu.test
@@ -18,6 +18,10 @@ class MenuIncTestCase extends DrupalWebTestCase {
function setUp() {
// Enable dummy module that implements hook_menu.
parent::setUp('menu_test');
+ // Make the tests below more robust by explicitly setting the default theme
+ // and administrative theme that they expect.
+ variable_set('theme_default', 'garland');
+ variable_set('admin_theme', 'seven');
}
/**
@@ -30,6 +34,80 @@ class MenuIncTestCase extends DrupalWebTestCase {
}
/**
+ * Test the theme callback when it is set to use an administrative theme.
+ */
+ function testThemeCallbackAdministrative() {
+ $this->drupalGet('menu-test/theme-callback/use-admin-theme');
+ $this->assertText('Requested theme: seven. Actual theme: seven.', t('The administrative theme can be correctly set in a theme callback.'));
+ $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
+ }
+
+ /**
+ * Test that the theme callback is properly inherited.
+ */
+ function testThemeCallbackInheritance() {
+ $this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance');
+ $this->assertText('Requested theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', t('Theme callback inheritance correctly uses the administrative theme.'));
+ $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
+ }
+
+ /**
+ * Test the theme callback when the site is in maintenance mode.
+ */
+ function testThemeCallbackMaintenanceMode() {
+ variable_set('maintenance_mode', TRUE);
+
+ // For a regular user, the fact that the site is in maintenance mode means
+ // we expect the theme callback system to be bypassed entirely.
+ $this->drupalGet('menu-test/theme-callback/use-admin-theme');
+ $this->assertRaw('minnelli/minnelli.css', t("The maintenance theme's CSS appears on the page."));
+
+ // An administrator, however, should continue to see the requested theme.
+ $admin_user = $this->drupalCreateUser(array('access site in maintenance mode'));
+ $this->drupalLogin($admin_user);
+ $this->drupalGet('menu-test/theme-callback/use-admin-theme');
+ $this->assertText('Requested theme: seven. Actual theme: seven.', t('The theme callback system is correctly triggered for an administrator when the site is in maintenance mode.'));
+ $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
+ }
+
+ /**
+ * Test the theme callback when it is set to use an optional theme.
+ */
+ function testThemeCallbackOptionalTheme() {
+ // Request a theme that is not enabled.
+ $this->drupalGet('menu-test/theme-callback/use-stark-theme');
+ $this->assertText('Requested theme: stark. Actual theme: garland.', t('The theme callback system falls back on the default theme when a theme that is not enabled is requested.'));
+ $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
+
+ // Now enable the theme and request it again.
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $this->drupalLogin($admin_user);
+ $this->drupalPost('admin/appearance', array('status[stark]' => 1), t('Save configuration'));
+ $this->drupalLogout();
+ $this->drupalGet('menu-test/theme-callback/use-stark-theme');
+ $this->assertText('Requested theme: stark. Actual theme: stark.', t('The theme callback system uses an optional theme once it has been enabled.'));
+ $this->assertRaw('stark/layout.css', t("The optional theme's CSS appears on the page."));
+ }
+
+ /**
+ * Test the theme callback when it is set to use a theme that does not exist.
+ */
+ function testThemeCallbackFakeTheme() {
+ $this->drupalGet('menu-test/theme-callback/use-fake-theme');
+ $this->assertText('Requested theme: fake_theme. Actual theme: garland.', t('The theme callback system falls back on the default theme when a theme that does not exist is requested.'));
+ $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
+ }
+
+ /**
+ * Test the theme callback when no theme is requested.
+ */
+ function testThemeCallbackNoThemeRequested() {
+ $this->drupalGet('menu-test/theme-callback/no-theme-requested');
+ $this->assertText('Requested theme: NONE. Actual theme: garland.', t('The theme callback system falls back on the default theme when no theme is requested.'));
+ $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
+ }
+
+ /**
* Tests for menu_link_maintain().
*/
function testMenuLinkMaintain() {
diff --git a/modules/simpletest/tests/menu_test.module b/modules/simpletest/tests/menu_test.module
index 15ecea71a..ae8235a9f 100644
--- a/modules/simpletest/tests/menu_test.module
+++ b/modules/simpletest/tests/menu_test.module
@@ -44,6 +44,20 @@ function menu_test_menu() {
'title' => 'Unattached subchild router',
'page callback' => 'node_page_default',
);
+ // Theme callback tests.
+ $items['menu-test/theme-callback/%'] = array(
+ 'title' => 'Page that displays different themes',
+ 'page callback' => 'menu_test_theme_page_callback',
+ 'access arguments' => array('access content'),
+ 'theme callback' => 'menu_test_theme_callback',
+ 'theme arguments' => array(2),
+ );
+ $items['menu-test/theme-callback/%/inheritance'] = array(
+ 'title' => 'Page that tests theme callback inheritance.',
+ 'page callback' => 'menu_test_theme_page_callback',
+ 'page arguments' => array(TRUE),
+ 'access arguments' => array('access content'),
+ );
return $items;
}
@@ -58,6 +72,56 @@ function menu_test_callback() {
}
/**
+ * Page callback to use when testing the theme callback functionality.
+ *
+ * @param $inherited
+ * An optional boolean to set to TRUE when the requested page is intended to
+ * inherit the theme of its parent.
+ * @return
+ * A string describing the requested custom theme and actual theme being used
+ * for the current page request.
+ */
+function menu_test_theme_page_callback($inherited = FALSE) {
+ global $theme_key;
+ // Initialize the theme system so that $theme_key will be populated.
+ drupal_theme_initialize();
+ // Now check both the requested custom theme and the actual theme being used.
+ $custom_theme = menu_get_custom_theme();
+ $requested_theme = empty($custom_theme) ? 'NONE' : $custom_theme;
+ $output = "Requested theme: $requested_theme. Actual theme: $theme_key.";
+ if ($inherited) {
+ $output .= ' Theme callback inheritance is being tested.';
+ }
+ return $output;
+}
+
+/**
+ * Theme callback to use when testing the theme callback functionality.
+ *
+ * @param $argument
+ * The argument passed in from the URL.
+ * @return
+ * The name of the custom theme to request for the current page.
+ */
+function menu_test_theme_callback($argument) {
+ // Test using the variable administrative theme.
+ if ($argument == 'use-admin-theme') {
+ return variable_get('admin_theme');
+ }
+ // Test using a theme that exists, but may or may not be enabled.
+ elseif ($argument == 'use-stark-theme') {
+ return 'stark';
+ }
+ // Test using a theme that does not exist.
+ elseif ($argument == 'use-fake-theme') {
+ return 'fake_theme';
+ }
+ // For any other value of the URL argument, do not return anything. This
+ // allows us to test that returning nothing from a theme callback function
+ // causes the page to correctly fall back on using the main site theme.
+}
+
+/**
* Helper function for the testMenuName() test. Used to change the menu_name
* parameter of a menu.
*
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index a3a230df9..24f0b888d 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -233,7 +233,7 @@ function system_themes_form() {
);
$options[$theme->name] = $theme->info['name'];
- if (!empty($theme->status) || $theme->name == variable_get('admin_theme', 0)) {
+ if (drupal_theme_access($theme)) {
$form[$theme->name]['operations'] = array('#markup' => l(t('configure'), 'admin/appearance/settings/' . $theme->name) );
}
else {
diff --git a/modules/system/system.install b/modules/system/system.install
index 2acc05d5a..aeedcf972 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -955,6 +955,20 @@ function system_schema() {
'not null' => TRUE,
'default' => '',
),
+ 'theme_callback' => array(
+ 'description' => 'A function which returns the name of the theme that will be used to render this page. If left empty, the default theme will be used.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'theme_arguments' => array(
+ 'description' => 'A serialized array of arguments for the theme callback.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
'type' => array(
'description' => 'Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.',
'type' => 'int',
@@ -2549,6 +2563,15 @@ function system_update_7038() {
}
/**
+ * Adds fields to the {menu_router} table to allow custom themes to be set per
+ * page.
+ */
+function system_update_7039() {
+ db_add_field('menu_router', 'theme_callback', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
+ db_add_field('menu_router', 'theme_arguments', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
+}
+
+/**
* @} End of "defgroup updates-6.x-to-7.x"
* The next series of updates should start at 8000.
*/
diff --git a/modules/system/system.module b/modules/system/system.module
index 56695e220..688eeca83 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -509,6 +509,8 @@ function system_menu() {
'page callback' => 'system_main_admin_page',
'weight' => 9,
'menu_name' => 'management',
+ 'theme callback' => 'variable_get',
+ 'theme arguments' => array('admin_theme'),
'file' => 'system.admin.inc',
);
$items['admin/compact'] = array(
@@ -1309,7 +1311,7 @@ function blocked_ip_load($iid) {
* Menu item access callback - only admin or enabled themes can be accessed.
*/
function _system_themes_access($theme) {
- return user_access('administer site configuration') && ($theme->status || $theme->name == variable_get('admin_theme', 0));
+ return user_access('administer site configuration') && drupal_theme_access($theme);
}
/**
@@ -1423,14 +1425,10 @@ function _system_filetransfer_backend_form_common() {
* Implement hook_init().
*/
function system_init() {
- // Use the administrative theme if the user is looking at a page in the admin/* path.
+ // Add the CSS for this module.
if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
- global $custom_theme;
- $custom_theme = variable_get('admin_theme', 0);
drupal_add_css(drupal_get_path('module', 'system') . '/admin.css', array('weight' => CSS_SYSTEM));
}
-
- // Add the CSS for this module.
drupal_add_css(drupal_get_path('module', 'system') . '/defaults.css', array('weight' => CSS_SYSTEM));
drupal_add_css(drupal_get_path('module', 'system') . '/system.css', array('weight' => CSS_SYSTEM));
drupal_add_css(drupal_get_path('module', 'system') . '/system-menus.css', array('weight' => CSS_SYSTEM));
@@ -1665,7 +1663,7 @@ function system_admin_menu_block($item) {
$default_task = NULL;
$has_subitems = FALSE;
$result = db_query("
- SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, m.path, m.weight as router_weight, ml.*
+ SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, m.description, m.path, m.weight as router_weight, ml.*
FROM {menu_router} m
LEFT JOIN {menu_links} ml ON m.path = ml.router_path
WHERE (ml.plid = :plid AND ml.menu_name = :name AND hidden = 0) OR (m.tab_parent = :path AND m.type IN (:local_task, :default_task))", array(':plid' => $item['mlid'], ':name' => $item['menu_name'], ':path' => $item['path'], ':local_task' => MENU_LOCAL_TASK, ':default_task' => MENU_DEFAULT_LOCAL_TASK), array('fetch' => PDO::FETCH_ASSOC));
@@ -2353,7 +2351,7 @@ function system_get_module_admin_tasks($module) {
if (empty($items)) {
$result = db_query("
- SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, ml.*
+ SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, ml.*
FROM {menu_links} ml INNER JOIN {menu_router} m ON ml.router_path = m.path WHERE ml.link_path LIKE 'admin/%' AND hidden >= 0 AND module = 'system' AND m.number_parts > 2", array(), array('fetch' => PDO::FETCH_ASSOC));
foreach ($result as $item) {
_menu_link_translate($item);