diff --git a/core/includes/install.inc b/core/includes/install.inc index db92987..42ec9ac 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -425,7 +425,6 @@ function drupal_install_system() { // Clear out module list and hook implementation statics. system_list_reset(); - module_list_reset(); module_implements_reset(); config_install_default_config('module', 'system'); diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 112e4f5..0091f03 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -1623,6 +1623,9 @@ function theme_menu_link(array $variables) { */ function theme_menu_local_task($variables) { $link = $variables['element']['#link']; + $link += array( + 'localized_options' => array(), + ); $link_text = $link['title']; if (!empty($variables['element']['#active'])) { @@ -1869,8 +1872,8 @@ function menu_local_tasks($level = 0) { $data = &drupal_static(__FUNCTION__); $root_path = &drupal_static(__FUNCTION__ . ':root_path', ''); $empty = array( - 'tabs' => array('count' => 0, 'output' => array()), - 'actions' => array('count' => 0, 'output' => array()), + 'tabs' => array(), + 'actions' => array(), 'root_path' => &$root_path, ); @@ -1922,8 +1925,7 @@ function menu_local_tasks($level = 0) { // Tab parenting may skip levels, so the number of parts in the path may not // equal the depth. Thus we use the $depth counter (offset by 1000 for ksort). $depth = 1001; - $actions['count'] = 0; - $actions['output'] = array(); + $actions = array(); while (isset($children[$path])) { $tabs_current = array(); $actions_current = array(); @@ -1960,6 +1962,7 @@ function menu_local_tasks($level = 0) { '#theme' => 'menu_local_task', '#link' => $link, '#active' => TRUE, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, ); $next_path = $item['path']; $tab_count++; @@ -1972,6 +1975,7 @@ function menu_local_tasks($level = 0) { $actions_current[] = array( '#theme' => 'menu_local_action', '#link' => $link, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, ); $action_count++; } @@ -1980,6 +1984,7 @@ function menu_local_tasks($level = 0) { $tabs_current[] = array( '#theme' => 'menu_local_task', '#link' => $link, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, ); $tab_count++; } @@ -1987,10 +1992,8 @@ function menu_local_tasks($level = 0) { } } $path = $next_path; - $tabs[$depth]['count'] = $tab_count; - $tabs[$depth]['output'] = $tabs_current; - $actions['count'] += $action_count; - $actions['output'] = array_merge($actions['output'], $actions_current); + $tabs[$depth] = $tabs_current; + $actions = array_merge($actions, $actions_current); $depth++; } $data['actions'] = $actions; @@ -2036,6 +2039,7 @@ function menu_local_tasks($level = 0) { '#theme' => 'menu_local_task', '#link' => $link, '#active' => TRUE, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, ); $next_path = $item['tab_parent']; if (isset($tasks[$next_path])) { @@ -2046,14 +2050,14 @@ function menu_local_tasks($level = 0) { $tabs_current[] = array( '#theme' => 'menu_local_task', '#link' => $link, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, ); } } } $path = $next_path; $parent = $next_parent; - $tabs[$depth]['count'] = $count; - $tabs[$depth]['output'] = $tabs_current; + $tabs[$depth] = $tabs_current; $depth--; } // Sort by depth. @@ -2075,7 +2079,7 @@ function menu_local_tasks($level = 0) { } // @todo If there are no tabs, then there still can be actions; for example, // when added via hook_menu_local_tasks_alter(). - elseif (!empty($data['actions']['output'])) { + elseif (!empty($data['actions'])) { return array('actions' => $data['actions']) + $empty; } return $empty; @@ -2188,7 +2192,7 @@ function menu_contextual_links($module, $parent_path, $args) { function menu_primary_local_tasks() { $links = menu_local_tasks(0); // Do not display single tabs. - return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : ''); + return count($links['tabs']) > 1 ? $links['tabs'] : ''; } /** @@ -2197,7 +2201,7 @@ function menu_primary_local_tasks() { function menu_secondary_local_tasks() { $links = menu_local_tasks(1); // Do not display single tabs. - return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : ''); + return count($links['tabs']) > 1 ? $links['tabs'] : ''; } /** @@ -2205,7 +2209,7 @@ function menu_secondary_local_tasks() { */ function menu_local_actions() { $links = menu_local_tasks(); - return $links['actions']['output']; + return $links['actions']; } /** @@ -3547,7 +3551,6 @@ function _menu_router_build($callbacks) { $item['to_arg_functions'] = empty($to_arg_functions) ? '' : serialize($to_arg_functions); $item += array( 'title' => '', - 'weight' => 0, 'type' => MENU_NORMAL_ITEM, 'module' => '', '_number_parts' => $number_parts, @@ -3555,6 +3558,9 @@ function _menu_router_build($callbacks) { '_fit' => $fit, ); $item += array( + // Default MENU_DEFAULT_LOCAL_TASKs to a weight of -10, so they appear as + // first tab by default. + 'weight' => ($item['type'] & MENU_DEFAULT_LOCAL_TASK) == MENU_DEFAULT_LOCAL_TASK ? -10 : 0, '_visible' => (bool) ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB), '_tab' => (bool) ($item['type'] & MENU_IS_LOCAL_TASK), ); diff --git a/core/includes/module.inc b/core/includes/module.inc index c1d99f2..285cdf2 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -34,7 +34,7 @@ function module_load_all($bootstrap = FALSE, $reset = FALSE) { // Unless $boostrap is NULL, load the requested set of modules. if (isset($bootstrap) && !$has_run) { - $type = $bootstrap ? 'bootstrap' : 'module_enabled'; + $type = $bootstrap ? 'bootstrap' : 'module'; foreach (module_list($type) as $module) { drupal_load('module', $module); } @@ -57,7 +57,7 @@ function module_load_all($bootstrap = FALSE, $reset = FALSE) { * * @param string $type * The type of list to return: - * - module_enabled: All enabled modules. + * - module: All enabled modules. * - bootstrap: All enabled modules required for bootstrap. * @param array $fixed_list * (optional) An array of module names to override the list of modules. This @@ -73,7 +73,7 @@ function module_load_all($bootstrap = FALSE, $reset = FALSE) { * * @see module_list_reset() */ -function module_list($type = 'module_enabled', array $fixed_list = NULL, $reset = FALSE) { +function module_list($type = 'module', array $fixed_list = NULL, $reset = FALSE) { // This static is only used for $fixed_list. It must not be a drupal_static(), // since any call to drupal_static_reset() in unit tests would cause an // attempt to retrieve the list of modules from the database (which does not @@ -120,13 +120,13 @@ function module_list_reset() { * * @param $type * The type of list to return: - * - module_enabled: All enabled modules. + * - module: All enabled modules. * - bootstrap: All enabled modules required for bootstrap. - * - theme: All themes. + * - theme: All enabled themes. * * @return * An associative array of modules or themes, keyed by name. For $type - * 'bootstrap' and 'module_enabled', the array values equal the keys. + * 'bootstrap' and 'module', the array values equal the keys. * For $type 'theme', the array values are objects representing the * respective database row, with the 'info' property already unserialized. * @@ -167,13 +167,13 @@ function system_list($type) { $lists['bootstrap'] = array_keys($bootstrap_list); } // Otherwise build the list for enabled modules and themes. - elseif (!isset($lists['module_enabled'])) { + elseif (!isset($lists['module'])) { if ($cached = cache('bootstrap')->get('system_list')) { $lists = $cached->data; } - else { + if (!isset($lists[$type])) { $lists = array( - 'module_enabled' => array(), + 'module' => array(), 'theme' => array(), 'filepaths' => array(), ); @@ -182,11 +182,11 @@ function system_list($type) { // Drupal installations, which might have modules installed in different // locations in the file system. The ordering here must also be // consistent with the one used in module_implements(). - $enabled_modules = config('system.module')->get('enabled'); + $enabled_modules = (array) config('system.module')->get('enabled'); $module_files = state()->get('system.module.files'); foreach ($enabled_modules as $name => $weight) { // Build a list of all enabled modules. - $lists['module_enabled'][$name] = $name; + $lists['module'][$name] = $name; // Build a list of filenames so drupal_get_filename can use it. $lists['filepaths'][] = array( 'type' => 'module', @@ -196,31 +196,27 @@ function system_list($type) { } // Build a list of themes. - $enabled_themes = config('system.theme')->get('enabled'); - // @todo Themes include all themes, including disabled/uninstalled. This - // system.theme.data state will go away entirely as soon as themes have - // a proper installation status. - // @see http://drupal.org/node/1067408 - $theme_data = state()->get('system.theme.data'); + $enabled_themes = (array) config('system.theme')->get('enabled'); + array_walk($enabled_themes, function (&$value, $key) { + $value = 'system.theme.data.' . $key; + }); + $theme_data = (array) state()->getMultiple($enabled_themes); + // @todo Remove me? if (empty($theme_data)) { - // @todo: system_list() may be called from _drupal_bootstrap_code() and + // system_list() may be called from _drupal_bootstrap_code() and // module_load_all(), in which case system.module is not loaded yet. // Prevent a filesystem scan in drupal_load() and include it directly. - // @see http://drupal.org/node/1067408 require_once DRUPAL_ROOT . '/core/modules/system/system.module'; $theme_data = system_rebuild_theme_data(); } foreach ($theme_data as $name => $theme) { - $theme->status = (int) isset($enabled_themes[$name]); $lists['theme'][$name] = $theme; // Build a list of filenames so drupal_get_filename can use it. - if (isset($enabled_themes[$name])) { - $lists['filepaths'][] = array( - 'type' => 'theme', - 'name' => $name, - 'filepath' => $theme->filename, - ); - } + $lists['filepaths'][] = array( + 'type' => 'theme', + 'name' => $name, + 'filepath' => $theme->filename, + ); } // @todo Move into list_themes(). Read info for a particular requested // theme from state instead. @@ -268,6 +264,7 @@ function system_list($type) { function system_list_reset() { drupal_static_reset('system_list'); drupal_static_reset('system_rebuild_module_data'); + drupal_static_reset('system_rebuild_theme_data'); drupal_static_reset('list_themes'); cache('bootstrap')->deleteMultiple(array('bootstrap_modules', 'system_list')); cache()->delete('system_info'); diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 3c4576a..5da4494 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -55,14 +55,44 @@ */ /** + * Loads a theme. + * + * @param string $name + * The name of a theme to load. + * + * @return + * The loaded theme object for $name, or FALSE if the passed $name does not + * exist or is not enabled. + */ +function theme_load($name) { + $themes = list_themes(); + if (isset($themes[$name]) && drupal_theme_access($themes[$name])) { + return $themes[$name]; + } + return FALSE; +} + +/** + * Menu title callback; Returns the sanitized human-readable name of a theme. + * + * @param $theme + * The theme object to return the title for. + * + * This needs to be a private function to avoid clashing with a possible + * theme_menu_title() theme function by Menu or a potential Menu Title module. + */ +function _theme_menu_title($theme) { + return check_plain($theme->info['name']); +} + +/** * Determines if a theme is available to use. * * @param $theme * Either the name of a theme or a full theme object. * * @return - * Boolean TRUE if the theme is enabled or is the site administration theme; - * FALSE otherwise. + * Boolean TRUE if the theme is enabled; FALSE otherwise. */ function drupal_theme_access($theme) { if (is_object($theme)) { @@ -70,6 +100,9 @@ function drupal_theme_access($theme) { } else { $themes = list_themes(); + if (!isset($themes[$theme])) { + return FALSE; + } return !empty($themes[$theme]->status); } } @@ -661,14 +694,14 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) { * declare this theme as their base theme. */ function list_themes($refresh = FALSE) { - $list = &drupal_static(__FUNCTION__, array()); + $list = &drupal_static(__FUNCTION__); if ($refresh) { - $list = array(); + $list = NULL; system_list_reset(); } - if (empty($list)) { + if (!isset($list)) { $list = array(); $themes = array(); // Extract from the database only when it is available. @@ -1407,29 +1440,136 @@ function theme_render_template($template_file, $variables) { /** * Enable a given list of themes. * - * @param $theme_list - * An array of theme names. + * @param array $theme_list + * An array of theme names to enable. + * @param bool $enable_dependencies + * If TRUE, dependencies will automatically be added and enabled in the + * correct order. This incurs a significant performance cost, so use FALSE + * if you know $theme_list is already complete and in the correct order. + * + * @todo D8: This is almost identical to module_enable() now. Only differences: + * - There is no required default .theme PHP file to load. + * - There is no schema to install. + * - System list, state, theme list, and static resets slightly differ. + * @todo hook_themes_installed(), hook_themes_enabled(), etc are not invoked in + * themes, since they are excluded from the hook system. */ -function theme_enable($theme_list) { - drupal_clear_css_cache(); +function theme_enable($theme_list, $enable_dependencies = TRUE) { + if ($enable_dependencies) { + // Get all theme data so we can find dependencies and sort. + $theme_data = system_rebuild_theme_data(); + // Create an associative array with weights as values. + $theme_list = array_flip(array_values($theme_list)); + + while (list($theme) = each($theme_list)) { + if (!isset($theme_data[$theme])) { + // This theme is not found in the filesystem, abort. + return FALSE; + } + if ($theme_data[$theme]->status) { + // Skip already enabled themes. + unset($theme_list[$theme]); + continue; + } + $theme_list[$theme] = $theme_data[$theme]->sort; + + // Add dependencies to the list, with a placeholder weight. + // The new themes will be processed as the while loop continues. + foreach (array_keys($theme_data[$theme]->requires) as $dependency) { + if (!isset($theme_list[$dependency])) { + $theme_list[$dependency] = 0; + } + } + } + + if (!$theme_list) { + // Nothing to do. All themes already enabled. + return TRUE; + } + + // Sort the theme list by pre-calculated weights. + arsort($theme_list); + $theme_list = array_keys($theme_list); + } + + // Required for schema version checks and constants. + include_once DRUPAL_ROOT . '/core/includes/install.inc'; + + $themes_installed = array(); + $themes_enabled = array(); + $schema_store = drupal_container()->get('keyvalue')->get('system.schema'); $theme_config = config('system.theme'); - $disabled_themes = config('system.theme.disabled'); + $disabled_config = config('system.theme.disabled'); foreach ($theme_list as $key) { - // The value is not used; the weight is ignored for themes currently. - $theme_config->set("enabled.$key", 0); - $disabled_themes->clear($key); - // Install default configuration of the theme. - config_install_default_config('theme', $key); + // Only process themes that are not already enabled. + $enabled = $theme_config->get("enabled.$key") !== NULL; + if (!$enabled) { + // The value is not used; the weight is ignored for themes currently. + $theme_config + ->set("enabled.$key", 0) + ->save(); + $disabled_config + ->clear($key) + ->save(); + + // Refresh the system list to include it. + system_list_reset(); + // Load the theme's code. + drupal_load('theme', $key); + // Refresh the schema to include it. + drupal_get_schema(NULL, TRUE); + // Update the theme registry to include it. + list_themes(TRUE); + drupal_theme_rebuild(); + + // Allow modules to react prior to the installation of a theme. + module_invoke_all('themes_preinstall', array($key)); + + // Now install the theme if necessary. + if (drupal_get_installed_schema_version($key, TRUE) == SCHEMA_UNINSTALLED) { + $version = SCHEMA_INSTALLED; + + // Install default configuration of the theme. + config_install_default_config('theme', $key); + + drupal_set_installed_schema_version($key, $version); + // Allow the theme to perform install tasks. + $function = $key . '_install'; + if (function_exists($function)) { + $function(); + } + // Record the fact that it was installed. + $themes_installed[] = $key; + watchdog('system', '%theme theme installed.', array('%theme' => $key), WATCHDOG_INFO); + } + + // Allow modules to react prior to the enabling of a theme. + module_invoke_all('themes_preenable', array($key)); + + // Enable the theme. + $function = $key . '_enable'; + if (function_exists($function)) { + $function(); + } + + // Record the fact that it was enabled. + $themes_enabled[] = $key; + watchdog('system', '%theme theme enabled.', array('%theme' => $key), WATCHDOG_INFO); + } } - $theme_config->save(); - $disabled_themes->save(); - list_themes(TRUE); - menu_router_rebuild(); - drupal_theme_rebuild(); + // If any themes were newly installed, invoke hook_themes_installed(). + if (!empty($themes_installed)) { + module_invoke_all('themes_installed', $themes_installed); + } - // Invoke hook_themes_enabled() after the themes have been enabled. - module_invoke_all('themes_enabled', $theme_list); + // If any themes were newly enabled, invoke hook_themes_enabled(). + if (!empty($themes_enabled)) { + module_invoke_all('themes_enabled', $themes_enabled); + } + + drupal_clear_css_cache(); + return TRUE; } /** @@ -1450,17 +1590,18 @@ function theme_disable($theme_list) { drupal_clear_css_cache(); $theme_config = config('system.theme'); - $disabled_themes = config('system.theme.disabled'); + $disabled_config = config('system.theme.disabled'); foreach ($theme_list as $key) { // The value is not used; the weight is ignored for themes currently. - $theme_config->clear("enabled.$key"); - $disabled_themes->set($key, 0); + $disabled_config + ->set($key, 0) + ->save(); + $theme_config + ->clear("enabled.$key") + ->save(); } - $theme_config->save(); - $disabled_themes->save(); list_themes(TRUE); - menu_router_rebuild(); drupal_theme_rebuild(); // Invoke hook_themes_disabled after the themes have been disabled. diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index 4b3e80c..6718e87 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -17,11 +17,6 @@ function _drupal_maintenance_theme() { global $theme, $theme_key, $conf; - // If $theme is already set, assume the others are set too, and do nothing. - if (isset($theme)) { - return; - } - require_once DRUPAL_ROOT . '/' . variable_get('path_inc', 'core/includes/path.inc'); require_once DRUPAL_ROOT . '/core/includes/theme.inc'; require_once DRUPAL_ROOT . '/core/includes/common.inc'; diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 869d4ee..b0a7947 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -45,7 +45,7 @@ public function registerBundles() { // @todo Remove the necessity of calling system_list() to find out which // bundles exist. See http://drupal.org/node/1331486 - $modules = array_keys(system_list('module_enabled')); + $modules = array_keys(system_list('module')); foreach ($modules as $module) { $camelized = ContainerBuilder::camelize($module); $class = "Drupal\\{$module}\\{$camelized}Bundle"; diff --git a/core/lib/Drupal/Core/ExceptionController.php b/core/lib/Drupal/Core/ExceptionController.php index cb448de..5d6e6f9 100644 --- a/core/lib/Drupal/Core/ExceptionController.php +++ b/core/lib/Drupal/Core/ExceptionController.php @@ -263,9 +263,10 @@ public function on500Html(FlattenException $exception, Request $request) { drupal_set_message(t('%type: !message in %function (line %line of %file).', $error), $class); } - drupal_set_title(t('Error')); // We fallback to a maintenance page at this point, because the page // generation itself can generate errors. + drupal_maintenance_theme(); + drupal_set_title(t('Error')); $output = theme('maintenance_page', array('content' => t('The website encountered an unexpected error. Please try again later.'))); $response = new Response($output, 500); diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc index 2a17a55..c233ee3 100644 --- a/core/modules/block/block.admin.inc +++ b/core/modules/block/block.admin.inc @@ -33,6 +33,9 @@ function block_admin_display($theme = NULL) { // If theme is not specifically set, rehash for the current theme. $theme = $theme_key; } + elseif (is_object($theme)) { + $theme = $theme->name; + } // Fetch and sort blocks. $blocks = block_admin_display_prepare_blocks($theme); diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 2978146..ced66f4 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -62,11 +62,21 @@ function block_help($path, $arg) { case 'admin/structure/block/add': return '

' . t('Use this page to create a new custom block.') . '

'; } - if ($arg[0] == 'admin' && $arg[1] == 'structure' && $arg['2'] == 'block' && (empty($arg[3]) || $arg[3] == 'list')) { - $demo_theme = !empty($arg[4]) ? $arg[4] : variable_get('theme_default', 'stark'); - $themes = list_themes(); + + if ($arg[0] === 'admin' && $arg[1] === 'structure' && $arg['2'] === 'block' && (empty($arg[3]) || $arg[3] === 'list')) { $output = '

' . 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. 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 Save blocks button at the bottom of the page. Click the configure link next to each block to configure its specific title and visibility settings.') . '

'; - $output .= '

' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '

'; + if (!empty($arg[4])) { + if (drupal_theme_access($arg[4])) { + $demo_theme = $arg[4]; + } + } + else { + $demo_theme = variable_get('theme_default', 'stark'); + } + if (isset($demo_theme)) { + $themes = list_themes(); + $output .= '

' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '

'; + } return $output; } } @@ -103,12 +113,10 @@ function block_permission() { * Implements hook_menu(). */ function block_menu() { - $default_theme = variable_get('theme_default', 'stark'); $items['admin/structure/block'] = array( 'title' => 'Blocks', 'description' => 'Configure what block content appears in your site\'s sidebars and other regions.', 'page callback' => 'block_admin_display', - 'page arguments' => array($default_theme), 'access arguments' => array('administer blocks'), 'file' => 'block.admin.inc', ); @@ -141,39 +149,94 @@ function block_menu() { 'type' => MENU_LOCAL_ACTION, 'file' => 'block.admin.inc', ); - foreach (list_themes() as $key => $theme) { - $items['admin/structure/block/list/' . $key] = array( - 'title' => check_plain($theme->info['name']), - 'page arguments' => array($key), - 'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, - 'weight' => $key == $default_theme ? -10 : 0, - 'access callback' => '_block_themes_access', - 'access arguments' => array($key), - 'file' => 'block.admin.inc', - ); - if ($key != $default_theme) { - $items['admin/structure/block/list/' . $key . '/add'] = array( - 'title' => 'Add block', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('block_add_block_form'), - 'access arguments' => array('administer blocks'), - 'type' => MENU_LOCAL_ACTION, - 'file' => 'block.admin.inc', + + $items['admin/structure/block/list/default'] = array( + 'title' => 'Default theme blocks', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['admin/structure/block/list/%theme'] = array( + 'title' => 'Theme blocks', + 'title callback' => '_theme_menu_title', + 'title arguments' => array(4), + 'page callback' => 'block_admin_display', + 'page arguments' => array(4), + 'type' => MENU_LOCAL_TASK, + 'access callback' => '_block_themes_access', + 'access arguments' => array(4), + 'file' => 'block.admin.inc', + ); + $items['admin/structure/block/list/%theme/add'] = array( + 'title' => 'Add block', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('block_add_block_form'), + 'access arguments' => array('administer blocks'), + 'type' => MENU_LOCAL_ACTION, + 'file' => 'block.admin.inc', + ); + $items['admin/structure/block/demo/%theme'] = array( + 'title' => 'Theme block region demo', + 'title callback' => '_theme_menu_title', + 'title arguments' => array(4), + 'page callback' => 'block_admin_demo', + 'page arguments' => array(4), + 'type' => MENU_CALLBACK, + 'access callback' => '_block_themes_access', + 'access arguments' => array(4), + 'theme callback' => '_block_custom_theme', + 'theme arguments' => array(4), + 'file' => 'block.admin.inc', + ); + return $items; +} + +/** + * Implements hook_menu_local_tasks_alter(). + */ +function block_menu_local_tasks_alter(&$data, $router_item, $root_path) { + if ($root_path == 'admin/structure/block' || strpos($root_path, 'admin/structure/block/list') === 0) { + // Replace the tab title of the default local task with the name of the + // default theme. + $themes = list_themes(); + $default_theme = variable_get('theme_default', 'stark'); + foreach ($data['tabs'][0] as $i => &$tab) { + if (isset($tab['#link']['path'])) { + if ($tab['#link']['path'] == 'admin/structure/block/list/default') { + $tab['#link']['title'] = $themes[$default_theme]->info['name']; + } + elseif ($tab['#link']['path'] == 'admin/structure/block/list/%') { + $selected_theme_index = $i; + } + } + } + + // Expand the dynamic %theme argument into a tab for each theme. + $selected_theme = isset($router_item['original_map'][4]) ? $router_item['original_map'][4] : NULL; + foreach ($themes as $theme) { + // The default theme is always exposed as default local task already. + if ($theme->name === $default_theme) { + continue; + } + // If the current page shows the interface for a selected theme, then the + // menu router item with the %theme argument will expose the selected + // theme already; do not duplicate that tab, but ensure it appears in a + // consistent order when switching between tabs. + if ($theme->name === $selected_theme) { + $data['tabs'][0][] = $data['tabs'][0][$selected_theme_index]; + unset($data['tabs'][0][$selected_theme_index]); + continue; + } + $data['tabs'][0][] = array( + '#theme' => 'menu_local_task', + '#link' => array( + 'title' => $theme->info['name'], + 'href' => 'admin/structure/block/list/' . $theme->name, + ), + '#active' => $theme->name === $selected_theme, + '#weight' => $theme->name === $default_theme ? -10 : 0, ); } - $items['admin/structure/block/demo/' . $key] = array( - 'title' => check_plain($theme->info['name']), - 'page callback' => 'block_admin_demo', - 'page arguments' => array($key), - 'type' => MENU_CALLBACK, - 'access callback' => '_block_themes_access', - 'access arguments' => array($key), - 'theme callback' => '_block_custom_theme', - 'theme arguments' => array($key), - 'file' => 'block.admin.inc', - ); } - return $items; } /** @@ -208,7 +271,9 @@ function _block_themes_access($theme) { 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; + if (isset($theme->name)) { + return $theme->name; + } } /** @@ -273,7 +338,7 @@ function block_page_build(&$page) { $all_regions = system_region_list($theme); $item = menu_get_item(); - if ($item['path'] != 'admin/structure/block/demo/' . $theme) { + if ($item['path'] != 'admin/structure/block/demo/%') { // Load all region content assigned via blocks. foreach (array_keys($all_regions) as $region) { // Assign blocks to region. @@ -293,8 +358,7 @@ function block_page_build(&$page) { } else { // Append region description if we are rendering the regions demo page. - $item = menu_get_item(); - if ($item['path'] == 'admin/structure/block/demo/' . $theme) { + if ($item['path'] == 'admin/structure/block/demo/%') { $visible_regions = array_keys(system_region_list($theme, REGIONS_VISIBLE)); foreach ($visible_regions as $region) { $description = '
' . $all_regions[$region] . '
'; @@ -412,6 +476,10 @@ function _block_rehash($theme = NULL) { } $regions = system_region_list($theme); + if (is_object($theme)) { + $theme = $theme->name; + } + // These are the blocks the function will return. $blocks = array(); // These are the blocks defined by code and modified by the database. diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php index c3a220f..ddee5dc 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php @@ -37,9 +37,9 @@ function testAdminTheme() { $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer themes')); $this->drupalLogin($admin_user); - // Ensure that access to block admin page is denied when theme is disabled. + // Ensure the block admin page cannot be accessed for a disabled theme. $this->drupalGet('admin/structure/block/list/bartik'); - $this->assertResponse(403); + $this->assertResponse(404); // Enable admin theme and confirm that tab is accessible. theme_enable(array('bartik')); diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php index af5acb9..2bf01ed 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php @@ -65,7 +65,7 @@ function testBlockNotInHiddenRegion() { $theme = 'block_test_theme'; theme_enable(array($theme)); variable_set('theme_default', $theme); - menu_router_rebuild(); + menu_cache_clear_all(); // Ensure that "block_test_theme" is set as the default theme. $this->drupalGet('admin/structure/block'); diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index f365491..9b9006f 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -209,7 +209,7 @@ function forum_menu_local_tasks_alter(&$data, $router_item, $root_path) { ); } } - $data['actions']['output'] = array_merge($data['actions']['output'], $links); + $data['actions'] = array_merge($data['actions'], $links); } } } diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 2dd1b57..b693e29 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -2062,7 +2062,7 @@ function node_menu_local_tasks_alter(&$data, $router_item, $root_path) { if ($root_path == 'admin/content') { $item = menu_get_item('node/add'); if ($item['access']) { - $data['actions']['output'][] = array( + $data['actions'][] = array( '#theme' => 'menu_local_action', '#link' => $item, ); diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php index 54eeab4..2bee0f6 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php @@ -122,6 +122,7 @@ function testShortcutLinkDelete() { */ function testNoShortcutLink() { // Change to a theme that displays shortcuts. + theme_enable(array('seven')); variable_set('theme_default', 'seven'); $this->drupalGet('page-that-does-not-exist'); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index b31d8a0..c0f156e 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -811,11 +811,6 @@ protected function prepareEnvironment() { unset($GLOBALS['theme_key']); unset($GLOBALS['theme']); - // Re-initialize the theme to ensure that tests do not see an inconsistent - // behavior when calling functions that would initialize the theme if it has - // not been initialized yet. - drupal_theme_initialize(); - // Log fatal errors. ini_set('log_errors', 1); ini_set('error_log', $this->public_files_directory . '/error.log'); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php index 98ed71d..79f7f77 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php @@ -66,6 +66,11 @@ protected function setUp() { return FALSE; } + // Re-initialize the theme to ensure that tests do not see an inconsistent + // behavior when calling functions that would initialize the theme if it has + // not been initialized yet. + drupal_theme_initialize(); + // Set user agent to be consistent with WebTestBase. $_SERVER['HTTP_USER_AGENT'] = $this->databasePrefix; diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 400d885..de45b78 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -720,6 +720,11 @@ protected function setUp() { $this->rebuildContainer(); } + // Re-initialize the theme to ensure that tests do not see an inconsistent + // behavior when calling functions that would initialize the theme if it has + // not been initialized yet. + drupal_theme_initialize(); + // Reset/rebuild all data structures after enabling the modules. $this->resetAll(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php b/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php index 69dee9c..8f8bdd5 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php @@ -35,8 +35,8 @@ public static function getInfo() { function testBatchProgressPageTheme() { // Make sure that the page which starts the batch (an administrative page) // is using a different theme than would normally be used by the batch API. + theme_enable(array('bartik', 'seven')); variable_set('theme_default', 'bartik'); - theme_enable(array('seven')); variable_set('admin_theme', 'seven'); // Log in as an administrator who can see the administrative theme. $admin_user = $this->drupalCreateUser(array('view the administration theme')); diff --git a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php index 3d0188d..e675843 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php @@ -206,7 +206,7 @@ function testAdministrationTheme() { $this->assertRaw('core/themes/stark', t('Site default theme used on the add content page.')); // Reset to the default theme settings. - variable_set('theme_default', 'bartik'); + variable_set('theme_default', 'stark'); $edit = array( 'admin_theme' => '0', 'node_admin_theme' => FALSE, @@ -214,10 +214,10 @@ function testAdministrationTheme() { $this->drupalPost('admin/appearance', $edit, t('Save configuration')); $this->drupalGet('admin'); - $this->assertRaw('core/themes/bartik', t('Site default theme used on administration page.')); + $this->assertRaw('core/themes/stark', t('Site default theme used on administration page.')); $this->drupalGet('node/add'); - $this->assertRaw('core/themes/bartik', t('Site default theme used on the add content page.')); + $this->assertRaw('core/themes/stark', t('Site default theme used on the add content page.')); } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php index 484d00b..f4660aa 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php @@ -141,18 +141,20 @@ function testTemplateOverride() { * Test the list_themes() function. */ function testListThemes() { + theme_enable(array('test_subtheme')); $themes = list_themes(); // Check if drupal_theme_access() retrieves enabled themes properly from list_themes(). $this->assertTrue(drupal_theme_access('test_theme'), t('Enabled theme detected')); - // Check if list_themes() returns disabled themes. - $this->assertTrue(array_key_exists('test_basetheme', $themes), t('Disabled theme detected')); + // Check for base theme and subtheme lists. $base_theme_list = array('test_basetheme' => 'Theme test base theme'); $sub_theme_list = array('test_subtheme' => 'Theme test subtheme'); $this->assertIdentical($themes['test_basetheme']->sub_themes, $sub_theme_list, t('Base theme\'s object includes list of subthemes.')); $this->assertIdentical($themes['test_subtheme']->base_themes, $base_theme_list, t('Subtheme\'s object includes list of base themes.')); + // Check for theme engine in subtheme. $this->assertIdentical($themes['test_subtheme']->engine, 'phptemplate', t('Subtheme\'s object includes the theme engine.')); + // Check for theme engine prefix. $this->assertIdentical($themes['test_basetheme']->prefix, 'phptemplate', t('Base theme\'s object includes the theme engine prefix.')); $this->assertIdentical($themes['test_subtheme']->prefix, 'phptemplate', t('Subtheme\'s object includes the theme engine prefix.')); @@ -162,6 +164,7 @@ function testListThemes() { * Test the theme_get_setting() function. */ function testThemeGetSetting() { + theme_enable(array('test_subtheme')); $GLOBALS['theme_key'] = 'test_theme'; $this->assertIdentical(theme_get_setting('theme_test_setting'), 'default value', t('theme_get_setting() uses the default theme automatically.')); $this->assertNotEqual(theme_get_setting('subtheme_override', 'test_basetheme'), theme_get_setting('subtheme_override', 'test_subtheme'), t('Base theme\'s default settings values can be overridden by subtheme.')); diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index c55289c..403dd82 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -118,8 +118,9 @@ function system_themes_page() { uasort($themes, 'system_sort_modules_by_info_name'); $theme_default = variable_get('theme_default', 'stark'); - $theme_groups = array(); + $theme_groups = array('enabled' => array(), 'disabled' => array()); $admin_theme = variable_get('admin_theme', 0); + $admin_theme_options = array(); foreach ($themes as &$theme) { if (!empty($theme->info['hidden'])) { @@ -280,12 +281,10 @@ function system_themes_admin_form_submit($form, &$form_state) { function system_theme_enable() { if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) { $theme = $_REQUEST['theme']; - // Get current list of themes. - $themes = list_themes(); - // Check if the specified theme is one recognized by the system. - if (!empty($themes[$theme])) { + if (drupal_get_path('theme', $theme)) { theme_enable(array($theme)); + $themes = list_themes(); drupal_set_message(t('The %theme theme has been enabled.', array('%theme' => $themes[$theme]->info['name']))); } else { @@ -330,26 +329,17 @@ function system_theme_disable() { function system_theme_default() { if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) { $theme = $_REQUEST['theme']; - // Get current list of themes. - $themes = list_themes(); - // Check if the specified theme is one recognized by the system. - if (!empty($themes[$theme])) { + if (drupal_get_path('theme', $theme)) { + $themes = list_themes(); // Enable the theme if it is currently disabled. - if (empty($themes[$theme]->status)) { - theme_enable(array($theme)); + if (!isset($themes[$theme])) { + theme_enable(array($theme)); + $themes = list_themes(); } // Set the default theme. variable_set('theme_default', $theme); - // Rebuild the menu. This duplicates the menu_router_rebuild() in - // theme_enable(). However, modules must know the current default theme in - // order to use this information in hook_menu() or hook_menu_alter() - // implementations, and doing the variable_set() before the theme_enable() - // could result in a race condition where the theme is default but not - // enabled. - menu_router_rebuild(); - // The status message depends on whether an admin theme is currently in use: // a value of 0 means the admin theme is set to be the default theme. $admin_theme = variable_get('admin_theme', 0); @@ -374,14 +364,17 @@ function system_theme_default() { /** * Form builder; display theme configuration for entire site and individual themes. * - * @param $key - * A theme name. + * @param $theme + * (optional) A theme object. + * * @return * The form structure. + * * @ingroup forms * @see system_theme_settings_submit() */ -function system_theme_settings($form, &$form_state, $key = '') { +function system_theme_settings($form, &$form_state, $theme = NULL) { + $key = !empty($theme) ? $theme->name : ''; // Default settings are defined in theme_get_setting() in includes/theme.inc if ($key) { $var = 'theme_' . $key . '_settings'; diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 0f6d668..b598e83 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -1084,17 +1084,10 @@ function hook_menu_link_delete($link) { * * @param $data * An associative array containing: - * - actions: An associative array containing: - * - count: The amount of actions determined by the menu system, which can - * be ignored. - * - output: A list of of actions, each one being an associative array - * as described above. - * - tabs: An indexed array (list) of tab levels (up to 2 levels), each - * containing an associative array: - * - count: The amount of tabs determined by the menu system. This value - * does not need to be altered if there is more than one tab. - * - output: A list of of tabs, each one being an associative array as - * described above. + * - actions: A list of of actions, each one being an associative array + * as described above. + * - tabs: A list of (up to 2) tab levels that contain a list of of tabs, each + * one being an associative array as described above. * @param $router_item * The menu system router item of the page. * @param $root_path @@ -1102,7 +1095,7 @@ function hook_menu_link_delete($link) { */ function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) { // Add an action linking to node/add to all pages. - $data['actions']['output'][] = array( + $data['actions'][] = array( '#theme' => 'menu_local_task', '#link' => array( 'title' => t('Add new content'), @@ -1116,7 +1109,7 @@ function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) { ); // Add a tab linking to node/add to all pages. - $data['tabs'][0]['output'][] = array( + $data['tabs'][0][] = array( '#theme' => 'menu_local_task', '#link' => array( 'title' => t('Example tab'), diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 255c669..e158642 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -690,23 +690,21 @@ function system_menu() { 'file' => 'system.admin.inc', 'weight' => 20, ); - // Theme configuration subtabs. $items['admin/appearance/settings/global'] = array( 'title' => 'Global settings', 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -1, + 'weight' => -10, + ); + $items['admin/appearance/settings/%theme'] = array( + 'title' => 'Theme settings', + 'title callback' => '_theme_menu_title', + 'title arguments' => array(3), + 'page arguments' => array('system_theme_settings', 3), + 'access callback' => '_system_themes_access', + 'access arguments' => array(3), + 'type' => MENU_LOCAL_TASK, + 'file' => 'system.admin.inc', ); - - foreach (list_themes() as $key => $theme) { - $items['admin/appearance/settings/' . $theme->name] = array( - 'title' => $theme->info['name'], - 'page arguments' => array('system_theme_settings', $theme->name), - 'type' => MENU_LOCAL_TASK, - 'access callback' => '_system_themes_access', - 'access arguments' => array($key), - 'file' => 'system.admin.inc', - ); - } // Modules. $items['admin/modules'] = array( @@ -1079,6 +1077,41 @@ function system_menu() { } /** + * Implements hook_menu_local_tasks_alter(). + */ +function system_menu_local_tasks_alter(&$data, $router_item, $root_path) { + if ($root_path === 'admin/appearance/settings' || $root_path === 'admin/appearance/settings/%') { + // Expand the dynamic %theme argument into a tab for each theme. + foreach ($data['tabs'][1] as $i => $tab) { + if (isset($tab['#link']['path']) && $tab['#link']['path'] == 'admin/appearance/settings/%') { + $selected_theme_index = $i; + break; + } + } + $themes = list_themes(); + $selected_theme = isset($router_item['original_map'][3]) ? $router_item['original_map'][3] : NULL; + foreach ($themes as $theme) { + // If the current page shows the interface for a selected theme, then the + // menu router item with the %theme argument will expose the selected + // theme already; do not duplicate that tab, but ensure it appears in a + // consistent order when switching between tabs. + if ($theme->name === $selected_theme) { + $data['tabs'][1][] = $data['tabs'][1][$selected_theme_index]; + unset($data['tabs'][1][$selected_theme_index]); + continue; + } + $data['tabs'][1][] = array( + '#theme' => 'menu_local_task', + '#link' => array( + 'title' => $theme->info['name'], + 'href' => 'admin/appearance/settings/' . $theme->name, + ), + ); + } + } +} + +/** * Page callback; Execute cron tasks. * * @see system_cron_access(). @@ -2684,6 +2717,7 @@ function system_get_info($type, $name = NULL) { } } else { + // @todo Migrate theme info to ModuleInfo implementation. $list = system_list($type); foreach ($list as $shortname => $item) { if (!empty($item->status)) { @@ -2709,6 +2743,8 @@ function system_get_info($type, $name = NULL) { * returned. * * @see Drupal\Core\Utility\ModuleInfo + * + * @todo Merge this helper entirely into system_get_info()? */ function system_get_module_info($property) { static $info; @@ -2921,6 +2957,9 @@ function _system_rebuild_theme_data() { if (!empty($themes[$key]->info['base theme'])) { $sub_themes[] = $key; + // Add the defined base theme as dependency to the theme, in order to + // re-use the dependency graph resolution of _module_build_dependencies(). + $themes[$key]->info['dependencies'][] = $themes[$key]->info['base theme']; } if ($themes[$key]->info['engine'] == 'theme') { $filename = dirname($themes[$key]->uri) . '/' . $themes[$key]->name . '.theme'; @@ -2985,30 +3024,36 @@ function _system_rebuild_theme_data() { * Array of all available themes and their data. */ function system_rebuild_theme_data() { - $themes = _system_rebuild_theme_data(); - ksort($themes); - // @todo This function has no business in determining/setting the status of - // a theme, but various other functions expect it to return themes with a - // $status property. system_list() stores the return value of this function - // in state, and ensures to set/override the $status property for each theme - // based on the current config. Remove this code when themes have a proper - // installation status. - // @see http://drupal.org/node/1067408 - $enabled_themes = config('system.theme')->get('enabled'); - $files = array(); - foreach ($themes as $name => $theme) { - $theme->status = (int) isset($enabled_themes[$name]); - $files[$name] = $theme->filename; - } - // Replace last known theme data state. - // @todo Obsolete with proper installation status for themes. - state()->set('system.theme.data', $themes); - - // Store filenames to allow system_list() and drupal_get_filename() to - // retrieve them without having to rebuild or scan the filesystem. - state()->set('system.theme.files', $files); + $cache = &drupal_static(__FUNCTION__); + // Only rebuild once per request. $themes and $cache cannot be combined into + // one variable, because $cache is reset by reference from system_list_reset() + // during a rebuild. + if (!isset($cache)) { + $themes = _system_rebuild_theme_data(); + $files = array(); + ksort($themes); + // Add name, status, and schema version. + $enabled_themes = (array) config('system.theme')->get('enabled'); + $disabled_themes = (array) config('system.theme.disabled')->get(); + $all_themes = $enabled_themes + $disabled_themes; + foreach ($themes as $name => $theme) { + $theme->name = $name; + $theme->weight = isset($all_themes[$name]) ? $all_themes[$name] : 0; + $theme->status = (int) isset($enabled_themes[$name]); + $theme->schema_version = SCHEMA_UNINSTALLED; + $files[$name] = $theme->filename; + + // Replace last known theme data state. + state()->set('system.theme.data.' . $name, $theme); + } + $themes = _module_build_dependencies($themes); + $cache = $themes; - return $themes; + // Store filenames to allow system_list() and drupal_get_filename() to + // retrieve them without having to rebuild or scan the filesystem. + state()->set('system.theme.files', $files); + } + return $cache; } /** @@ -3066,25 +3111,26 @@ function _system_default_theme_features() { /** * Get a list of available regions from a specified theme. * - * @param $theme_key - * The name of a theme. + * @param $theme + * A theme object, or the name of a theme. * @param $show * Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden * regions. * @return * An array of regions in the form $region['name'] = 'description'. */ -function system_region_list($theme_key, $show = REGIONS_ALL) { - $themes = list_themes(); - if (!isset($themes[$theme_key])) { - return array(); +function system_region_list($theme, $show = REGIONS_ALL) { + if (!is_object($theme)) { + $themes = list_themes(); + if (!isset($themes[$theme])) { + return array(); + } + $theme = $themes[$theme]; } - $list = array(); - $info = $themes[$theme_key]->info; // If requested, suppress hidden regions. See block_admin_display_form(). - foreach ($info['regions'] as $name => $label) { - if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) { + foreach ($theme->info['regions'] as $name => $label) { + if ($show == REGIONS_ALL || !isset($theme->info['regions_hidden']) || !in_array($name, $theme->info['regions_hidden'])) { $list[$name] = t($label); } } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php index b226970..6ab0e74 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php @@ -25,8 +25,8 @@ function setUp() { // Make sure we are using distinct default and administrative themes for // the duration of these tests. + theme_enable(array('bartik', 'seven')); variable_set('theme_default', 'bartik'); - theme_enable(array('seven')); variable_set('admin_theme', 'seven'); // Create and log in as a user who has permission to add and edit taxonomy diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install index 4eeb8d6..270c1f4 100644 --- a/core/profiles/standard/standard.install +++ b/core/profiles/standard/standard.install @@ -415,9 +415,6 @@ function standard_install() { ); shortcut_set_save($shortcut_set); - // Update the menu router information. - menu_router_rebuild(); - // Enable the admin theme. theme_enable(array('seven')); variable_set('admin_theme', 'seven');