checkRequirements() && user_access('administer site configuration')) {
drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/reports/status'))), 'error');
}
$blocks = array();
if ($system_link = entity_load_multiple_by_properties('menu_link', array('link_path' => 'admin/config', 'module' => 'system'))) {
$system_link = reset($system_link);
$query = Drupal::entityQuery('menu_link')
->condition('link_path', 'admin/help', '<>')
->condition('menu_name', $system_link->menu_name)
->condition('plid', $system_link->id())
->condition('hidden', 0);
$result = $query->execute();
if (!empty($result)) {
$menu_links = menu_link_load_multiple($result);
foreach ($menu_links as $item) {
_menu_link_translate($item);
if (!$item['access']) {
continue;
}
// The link description, either derived from 'description' in hook_menu()
// or customized via menu module is used as title attribute.
if (!empty($item['localized_options']['attributes']['title'])) {
$item['description'] = $item['localized_options']['attributes']['title'];
unset($item['localized_options']['attributes']['title']);
}
$block = $item;
$block['content'] = '';
$block['content'] .= theme('admin_block_content', array('content' => system_admin_menu_block($item)));
if (!empty($block['content'])) {
$block['show'] = TRUE;
}
// Prepare for sorting as in function _menu_tree_check_access().
// The weight is offset so it is always positive, with a uniform 5-digits.
$blocks[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $block;
}
}
}
if ($blocks) {
ksort($blocks);
return theme('admin_page', array('blocks' => $blocks));
}
else {
return t('You do not have any administrative items.');
}
}
/**
* Provide a single block from the administration menu as a page.
*
* This function is often a destination for these blocks.
* For example, 'admin/structure/types' needs to have a destination to be valid
* in the Drupal menu system, but too much information there might be
* hidden, so we supply the contents of the block.
*
* @return
* The output HTML.
*/
function system_admin_menu_block_page() {
$item = menu_get_item();
if ($content = system_admin_menu_block($item)) {
$output = theme('admin_block_content', array('content' => $content));
}
else {
$output = t('You do not have any administrative items.');
}
return $output;
}
/**
* Menu callback; displays a listing of all themes.
*/
function system_themes_page() {
// Get current list of themes.
$themes = system_rebuild_theme_data();
uasort($themes, 'system_sort_modules_by_info_name');
$theme_default = config('system.theme')->get('default');
$theme_groups = array();
$admin_theme = config('system.theme')->get('admin');
foreach ($themes as &$theme) {
if (!empty($theme->info['hidden'])) {
continue;
}
$theme->is_default = ($theme->name == $theme_default);
// Identify theme screenshot.
$theme->screenshot = NULL;
// Create a list which includes the current theme and all its base themes.
if (isset($themes[$theme->name]->base_themes)) {
$theme_keys = array_keys($themes[$theme->name]->base_themes);
$theme_keys[] = $theme->name;
}
else {
$theme_keys = array($theme->name);
}
// Look for a screenshot in the current theme or in its closest ancestor.
foreach (array_reverse($theme_keys) as $theme_key) {
if (isset($themes[$theme_key]) && file_exists($themes[$theme_key]->info['screenshot'])) {
$theme->screenshot = array(
'uri' => $themes[$theme_key]->info['screenshot'],
'alt' => t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])),
'title' => t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])),
'attributes' => array('class' => array('screenshot')),
);
break;
}
}
if (empty($theme->status)) {
// Ensure this theme is compatible with this version of core.
// Require the 'content' region to make sure the main page
// content has a common place in all themes.
$theme->incompatible_core = !isset($theme->info['core']) || ($theme->info['core'] != DRUPAL_CORE_COMPATIBILITY) || (!isset($theme->info['regions']['content']));
$theme->incompatible_php = version_compare(phpversion(), $theme->info['php']) < 0;
// Confirmed that the base theme is available.
$theme->incompatible_base = (isset($theme->info['base theme']) && !isset($themes[$theme->info['base theme']]));
// Confirm that the theme engine is available.
$theme->incompatible_engine = (isset($theme->info['engine']) && !isset($theme->owner));
}
$query['token'] = drupal_get_token('system-theme-operation-link');
$theme->operations = array();
if (!empty($theme->status) || !$theme->incompatible_core && !$theme->incompatible_php && !$theme->incompatible_base && !$theme->incompatible_engine) {
// Create the operations links.
$query['theme'] = $theme->name;
if (drupal_theme_access($theme)) {
$theme->operations[] = array(
'title' => t('Settings'),
'href' => 'admin/appearance/settings/' . $theme->name,
'attributes' => array('title' => t('Settings for !theme theme', array('!theme' => $theme->info['name']))),
);
}
if (!empty($theme->status)) {
if (!$theme->is_default) {
if ($theme->name != $admin_theme) {
$theme->operations[] = array(
'title' => t('Disable'),
'href' => 'admin/appearance/disable',
'query' => $query,
'attributes' => array('title' => t('Disable !theme theme', array('!theme' => $theme->info['name']))),
);
}
$theme->operations[] = array(
'title' => t('Set default'),
'href' => 'admin/appearance/default',
'query' => $query,
'attributes' => array('title' => t('Set !theme as default theme', array('!theme' => $theme->info['name']))),
);
}
$admin_theme_options[$theme->name] = $theme->info['name'];
}
else {
$theme->operations[] = array(
'title' => t('Enable'),
'href' => 'admin/appearance/enable',
'query' => $query,
'attributes' => array('title' => t('Enable !theme theme', array('!theme' => $theme->info['name']))),
);
$theme->operations[] = array(
'title' => t('Enable and set default'),
'href' => 'admin/appearance/default',
'query' => $query,
'attributes' => array('title' => t('Enable !theme as default theme', array('!theme' => $theme->info['name']))),
);
}
}
// Add notes to default and administration theme.
$theme->notes = array();
$theme->classes = array();
if ($theme->is_default) {
$theme->classes[] = 'theme-default';
$theme->notes[] = t('default theme');
}
if ($theme->name == $admin_theme || ($theme->is_default && $admin_theme == '0')) {
$theme->classes[] = 'theme-admin';
$theme->notes[] = t('admin theme');
}
// Sort enabled and disabled themes into their own groups.
$theme_groups[$theme->status ? 'enabled' : 'disabled'][] = $theme;
}
// There are two possible theme groups.
$theme_group_titles = array(
'enabled' => format_plural(count($theme_groups['enabled']), 'Enabled theme', 'Enabled themes'),
);
if (!empty($theme_groups['disabled'])) {
$theme_group_titles['disabled'] = format_plural(count($theme_groups['disabled']), 'Disabled theme', 'Disabled themes');
}
uasort($theme_groups['enabled'], 'system_sort_themes');
drupal_alter('system_themes_page', $theme_groups);
$admin_form = drupal_get_form('system_themes_admin_form', $admin_theme_options);
return theme('system_themes_page', array('theme_groups' => $theme_groups, 'theme_group_titles' => $theme_group_titles)) . drupal_render($admin_form);
}
/**
* Form to select the administration theme.
*
* @ingroup forms
* @see system_themes_admin_form_submit()
*/
function system_themes_admin_form($form, &$form_state, $theme_options) {
// Administration theme settings.
$form['admin_theme'] = array(
'#type' => 'details',
'#title' => t('Administration theme'),
);
$form['admin_theme']['admin_theme'] = array(
'#type' => 'select',
'#options' => array(0 => t('Default theme')) + $theme_options,
'#title' => t('Administration theme'),
'#description' => t('Choose "Default theme" to always use the same theme as the rest of the site.'),
'#default_value' => config('system.theme')->get('admin'),
);
$form['admin_theme']['actions'] = array('#type' => 'actions');
$form['admin_theme']['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
return $form;
}
/**
* Process system_themes_admin_form form submissions.
*/
function system_themes_admin_form_submit($form, &$form_state) {
drupal_set_message(t('The configuration options have been saved.'));
config('system.theme')->set('admin', $form_state['values']['admin_theme'])->save();
}
/**
* Menu callback; Set the default theme.
*/
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])) {
// Enable the theme if it is currently disabled.
if (empty($themes[$theme]->status)) {
theme_enable(array($theme));
}
// Set the default theme.
config('system.theme')
->set('default', $theme)
->save();
// 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 = config('system.theme')->get('admin');
if ($admin_theme != 0 && $admin_theme != $theme) {
drupal_set_message(t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', array(
'%admin_theme' => $themes[$admin_theme]->info['name'],
'%selected_theme' => $themes[$theme]->info['name'],
)));
}
else {
drupal_set_message(t('%theme is now the default theme.', array('%theme' => $themes[$theme]->info['name'])));
}
}
else {
drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
}
drupal_goto('admin/appearance');
}
throw new AccessDeniedHttpException();
}
/**
* Form builder; display theme configuration for entire site and individual themes.
*
* @param $key
* A theme name.
* @return
* The form structure.
* @ingroup forms
* @see system_theme_settings_validate()
* @see system_theme_settings_submit()
*/
function system_theme_settings($form, &$form_state, $key = '') {
// Default settings are defined in theme_get_setting() in includes/theme.inc
if ($key) {
$var = 'theme_' . $key . '_settings';
$config_key = $key . '.settings';
$themes = list_themes();
$features = $themes[$key]->info['features'];
}
else {
$var = 'theme_settings';
$config_key = 'system.theme.global';
}
$form['var'] = array('#type' => 'hidden', '#value' => $var);
$form['config_key'] = array('#type' => 'hidden', '#value' => $config_key);
// Toggle settings
$toggles = array(
'logo' => t('Logo'),
'name' => t('Site name'),
'slogan' => t('Site slogan'),
'node_user_picture' => t('User pictures in posts'),
'comment_user_picture' => t('User pictures in comments'),
'comment_user_verification' => t('User verification status in comments'),
'favicon' => t('Shortcut icon'),
'main_menu' => t('Main menu'),
'secondary_menu' => t('Secondary menu'),
);
// Some features are not always available
$disabled = array();
if (!user_picture_enabled()) {
$disabled['toggle_node_user_picture'] = TRUE;
$disabled['toggle_comment_user_picture'] = TRUE;
}
if (!module_exists('comment')) {
$disabled['toggle_comment_user_picture'] = TRUE;
$disabled['toggle_comment_user_verification'] = TRUE;
}
$form['theme_settings'] = array(
'#type' => 'details',
'#title' => t('Toggle display'),
'#description' => t('Enable or disable the display of certain page elements.'),
);
foreach ($toggles as $name => $title) {
if ((!$key) || in_array($name, $features)) {
$form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('features.' . $name, $key));
// Disable checkboxes for features not supported in the current configuration.
if (isset($disabled['toggle_' . $name])) {
$form['theme_settings']['toggle_' . $name]['#disabled'] = TRUE;
}
}
}
if (!element_children($form['theme_settings'])) {
// If there is no element in the theme settings details then do not show
// it -- but keep it in the form if another module wants to alter.
$form['theme_settings']['#access'] = FALSE;
}
// Logo settings, only available when file.module is enabled.
if ((!$key) || in_array('logo', $features) && module_exists('file')) {
$form['logo'] = array(
'#type' => 'details',
'#title' => t('Logo image settings'),
'#attributes' => array('class' => array('theme-settings-bottom')),
'#states' => array(
// Hide the logo image settings fieldset when logo display is disabled.
'invisible' => array(
'input[name="toggle_logo"]' => array('checked' => FALSE),
),
),
);
$form['logo']['default_logo'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default logo supplied by the theme'),
'#default_value' => theme_get_setting('logo.use_default', $key),
'#tree' => FALSE,
);
$form['logo']['settings'] = array(
'#type' => 'container',
'#states' => array(
// Hide the logo settings when using the default logo.
'invisible' => array(
'input[name="default_logo"]' => array('checked' => TRUE),
),
),
);
$form['logo']['settings']['logo_path'] = array(
'#type' => 'textfield',
'#title' => t('Path to custom logo'),
'#default_value' => theme_get_setting('logo.path', $key),
);
$form['logo']['settings']['logo_upload'] = array(
'#type' => 'file',
'#title' => t('Upload logo image'),
'#maxlength' => 40,
'#description' => t("If you don't have direct file access to the server, use this field to upload your logo.")
);
}
if ((!$key) || in_array('favicon', $features) && module_exists('file')) {
$form['favicon'] = array(
'#type' => 'details',
'#title' => t('Shortcut icon settings'),
'#description' => t("Your shortcut icon, or 'favicon', is displayed in the address bar and bookmarks of most browsers."),
'#states' => array(
// Hide the shortcut icon settings fieldset when shortcut icon display
// is disabled.
'invisible' => array(
'input[name="toggle_favicon"]' => array('checked' => FALSE),
),
),
);
$form['favicon']['default_favicon'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default shortcut icon supplied by the theme'),
'#default_value' => theme_get_setting('favicon.use_default', $key),
);
$form['favicon']['settings'] = array(
'#type' => 'container',
'#states' => array(
// Hide the favicon settings when using the default favicon.
'invisible' => array(
'input[name="default_favicon"]' => array('checked' => TRUE),
),
),
);
$form['favicon']['settings']['favicon_path'] = array(
'#type' => 'textfield',
'#title' => t('Path to custom icon'),
'#default_value' => theme_get_setting('favicon.path', $key),
);
$form['favicon']['settings']['favicon_upload'] = array(
'#type' => 'file',
'#title' => t('Upload icon image'),
'#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.")
);
}
// Inject human-friendly values and form element descriptions for logo and
// favicon.
foreach (array('logo' => 'logo.png', 'favicon' => 'favicon.ico') as $type => $default) {
if (isset($form[$type]['settings'][$type . '_path'])) {
$element = &$form[$type]['settings'][$type . '_path'];
// If path is a public:// URI, display the path relative to the files
// directory; stream wrappers are not end-user friendly.
$original_path = $element['#default_value'];
$friendly_path = NULL;
if (file_uri_scheme($original_path) == 'public') {
$friendly_path = file_uri_target($original_path);
$element['#default_value'] = $friendly_path;
}
// Prepare local file path for description.
if ($original_path && isset($friendly_path)) {
$local_file = strtr($original_path, array('public:/' => variable_get('file_public_path', conf_path() . '/files')));
}
elseif ($key) {
$local_file = drupal_get_path('theme', $key) . '/' . $default;
}
else {
$local_file = path_to_theme() . '/' . $default;
}
$element['#description'] = t('Examples: @implicit-public-file
(for a file in the public filesystem), @explicit-file
, or @local-file
.', array(
'@implicit-public-file' => isset($friendly_path) ? $friendly_path : $default,
'@explicit-file' => file_uri_scheme($original_path) !== FALSE ? $original_path : 'public://' . $default,
'@local-file' => $local_file,
));
}
}
if ($key) {
// Call engine-specific settings.
$function = $themes[$key]->prefix . '_engine_settings';
if (function_exists($function)) {
$form['engine_specific'] = array(
'#type' => 'details',
'#title' => t('Theme-engine-specific settings'),
'#description' => t('These settings only exist for the themes based on the %engine theme engine.', array('%engine' => $themes[$key]->prefix)),
);
$function($form, $form_state);
}
// Create a list which includes the current theme and all its base themes.
if (isset($themes[$key]->base_themes)) {
$theme_keys = array_keys($themes[$key]->base_themes);
$theme_keys[] = $key;
}
else {
$theme_keys = array($key);
}
// Save the name of the current theme (if any), so that we can temporarily
// override the current theme and allow theme_get_setting() to work
// without having to pass the theme name to it.
$default_theme = !empty($GLOBALS['theme_key']) ? $GLOBALS['theme_key'] : NULL;
$GLOBALS['theme_key'] = $key;
// Process the theme and all its base themes.
foreach ($theme_keys as $theme) {
// Include the theme-settings.php file.
$filename = DRUPAL_ROOT . '/' . str_replace("/$theme.info.yml", '', $themes[$theme]->filename) . '/theme-settings.php';
if (file_exists($filename)) {
require_once $filename;
}
// Call theme-specific settings.
$function = $theme . '_form_system_theme_settings_alter';
if (function_exists($function)) {
$function($form, $form_state);
}
}
// Restore the original current theme.
if (isset($default_theme)) {
$GLOBALS['theme_key'] = $default_theme;
}
else {
unset($GLOBALS['theme_key']);
}
}
return system_config_form($form, $form_state);
}
/**
* Validator for the system_theme_settings() form.
*/
function system_theme_settings_validate($form, &$form_state) {
if (module_exists('file')) {
// Handle file uploads.
$validators = array('file_validate_is_image' => array());
// Check for a new uploaded logo.
$file = file_save_upload('logo_upload', $validators, FALSE, 0);
if (isset($file)) {
// File upload was attempted.
if ($file) {
// Put the temporary file in form_values so we can save it on submit.
$form_state['values']['logo_upload'] = $file;
}
else {
// File upload failed.
form_set_error('logo_upload', t('The logo could not be uploaded.'));
}
}
$validators = array('file_validate_extensions' => array('ico png gif jpg jpeg apng svg'));
// Check for a new uploaded favicon.
$file = file_save_upload('favicon_upload', $validators, FALSE, 0);
if (isset($file)) {
// File upload was attempted.
if ($file) {
// Put the temporary file in form_values so we can save it on submit.
$form_state['values']['favicon_upload'] = $file;
}
else {
// File upload failed.
form_set_error('favicon_upload', t('The favicon could not be uploaded.'));
}
}
// If the user provided a path for a logo or favicon file, make sure a file
// exists at that path.
if ($form_state['values']['logo_path']) {
$path = _system_theme_settings_validate_path($form_state['values']['logo_path']);
if (!$path) {
form_set_error('logo_path', t('The custom logo path is invalid.'));
}
}
if ($form_state['values']['favicon_path']) {
$path = _system_theme_settings_validate_path($form_state['values']['favicon_path']);
if (!$path) {
form_set_error('favicon_path', t('The custom favicon path is invalid.'));
}
}
}
}
/**
* Helper function for the system_theme_settings form.
*
* Attempts to validate normal system paths, paths relative to the public files
* directory, or stream wrapper URIs. If the given path is any of the above,
* returns a valid path or URI that the theme system can display.
*
* @param $path
* A path relative to the Drupal root or to the public files directory, or
* a stream wrapper URI.
* @return mixed
* A valid path that can be displayed through the theme system, or FALSE if
* the path could not be validated.
*/
function _system_theme_settings_validate_path($path) {
// Absolute local file paths are invalid.
if (drupal_realpath($path) == $path) {
return FALSE;
}
// A path relative to the Drupal root or a fully qualified URI is valid.
if (is_file($path)) {
return $path;
}
// Prepend 'public://' for relative file paths within public filesystem.
if (file_uri_scheme($path) === FALSE) {
$path = 'public://' . $path;
}
if (is_file($path)) {
return $path;
}
return FALSE;
}
/**
* Process system_theme_settings form submissions.
*/
function system_theme_settings_submit($form, &$form_state) {
$config = Drupal::config($form_state['values']['config_key']);
// Exclude unnecessary elements before saving.
form_state_values_clean($form_state);
$key = $form_state['values']['var'];
unset($form_state['values']['var']);
unset($form_state['values']['config_key']);
$values = $form_state['values'];
// If the user uploaded a new logo or favicon, save it to a permanent location
// and use it in place of the default theme-provided file.
if (module_exists('file')) {
if ($file = $values['logo_upload']) {
unset($values['logo_upload']);
$filename = file_unmanaged_copy($file->uri);
$values['default_logo'] = 0;
$values['logo_path'] = $filename;
$values['toggle_logo'] = 1;
}
if ($file = $values['favicon_upload']) {
unset($values['favicon_upload']);
$filename = file_unmanaged_copy($file->uri);
$values['default_favicon'] = 0;
$values['favicon_path'] = $filename;
$values['toggle_favicon'] = 1;
}
// If the user entered a path relative to the system files directory for
// a logo or favicon, store a public:// URI so the theme system can handle it.
if (!empty($values['logo_path'])) {
$values['logo_path'] = _system_theme_settings_validate_path($values['logo_path']);
}
if (!empty($values['favicon_path'])) {
$values['favicon_path'] = _system_theme_settings_validate_path($values['favicon_path']);
}
if (empty($values['default_favicon']) && !empty($values['favicon_path'])) {
$values['favicon_mimetype'] = file_get_mimetype($values['favicon_path']);
}
}
theme_settings_convert_to_config($values, $config)->save();
cache_invalidate_tags(array('content' => TRUE));
}
/**
* Recursively check compatibility.
*
* @param $incompatible
* An associative array which at the end of the check contains all
* incompatible files as the keys, their values being TRUE.
* @param $files
* The set of files that will be tested.
* @param $file
* The file at which the check starts.
* @return
* Returns TRUE if an incompatible file is found, NULL (no return value)
* otherwise.
*/
function _system_is_incompatible(&$incompatible, $files, $file) {
if (isset($incompatible[$file->name])) {
return TRUE;
}
// Recursively traverse required modules, looking for incompatible modules.
foreach ($file->requires as $requires) {
if (isset($files[$requires]) && _system_is_incompatible($incompatible, $files, $files[$requires])) {
$incompatible[$file->name] = TRUE;
return TRUE;
}
}
}
/**
* Form constructor for the module enable/disable interface.
*
* The list of modules gets populated by module.info.yml files, which contain
* each module's name, description, and information about which modules it
* requires.
* See drupal_parse_info_file() for information on module.info.yml descriptors.
*
* Dependency checking is performed to ensure that a module:
* - can not be enabled if there are disabled modules it requires.
* - can not be disabled if there are enabled modules which depend on it.
*
* @see system_menu()
* @see theme_system_modules()
* @see system_modules_submit()
*
* @ingroup forms
*/
function system_modules($form, $form_state = array()) {
// Get current list of modules.
$files = system_rebuild_module_data();
// Remove hidden modules from display list.
$visible_files = $files;
foreach ($visible_files as $filename => $file) {
if (!empty($file->info['hidden'])) {
unset($visible_files[$filename]);
}
}
uasort($visible_files, 'system_sort_modules_by_info_name');
// If the modules form was submitted, then system_modules_submit() runs first
// and if there are unfilled required modules, then $form_state['storage'] is
// filled, triggering a rebuild. In this case we need to display a
// confirmation form.
if (!empty($form_state['storage'])) {
// Contents of confirm form is injected here because already in form
// building function.
$confirm_form = new ModulesInstallConfirmForm();
return $confirm_form->buildForm($form, $form_state, $visible_files, $form_state['storage']);
}
// JS-only table filters.
$form['filters'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array('table-filter', 'js-show'),
),
);
$form['filters']['text'] = array(
'#type' => 'search',
'#title' => t('Search'),
'#size' => 30,
'#placeholder' => t('Enter module nameā¦'),
'#attributes' => array(
'class' => array('table-filter-text'),
'data-table' => '#system-modules',
'autocomplete' => 'off',
'title' => t('Enter a part of the module name or description to filter by.'),
),
);
$modules = array();
$form['modules'] = array('#tree' => TRUE);
// Used when checking if module implements a help page.
$help_arg = module_exists('help') ? drupal_help_arg() : FALSE;
// Used when displaying modules that are required by the installation profile.
require_once DRUPAL_ROOT . '/core/includes/install.inc';
$distribution_name = check_plain(drupal_install_profile_distribution_name());
// Iterate through each of the modules.
foreach ($visible_files as $filename => $module) {
$extra = array();
$extra['enabled'] = (bool) $module->status;
if (!empty($module->info['required'] )) {
$extra['disabled'] = TRUE;
$extra['required_by'][] = $distribution_name . (!empty($module->info['explanation']) ? ' ('. $module->info['explanation'] .')' : '');
}
// If this module requires other modules, add them to the array.
foreach ($module->requires as $requires => $v) {
if (!isset($files[$requires])) {
$extra['requires'][$requires] = t('@module (missing)', array('@module' => drupal_ucfirst($requires)));
$extra['disabled'] = TRUE;
}
// Only display visible modules.
elseif (isset($visible_files[$requires])) {
$requires_name = $files[$requires]->info['name'];
// Disable this module if it is incompatible with the dependency's version.
if ($incompatible_version = drupal_check_incompatibility($v, str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $files[$requires]->info['version']))) {
$extra['requires'][$requires] = t('@module (incompatible with version @version)', array(
'@module' => $requires_name . $incompatible_version,
'@version' => $files[$requires]->info['version'],
));
$extra['disabled'] = TRUE;
}
// Disable this module if the dependency is incompatible with this
// version of Drupal core.
elseif ($files[$requires]->info['core'] != DRUPAL_CORE_COMPATIBILITY) {
$extra['requires'][$requires] = t('@module (incompatible with this version of Drupal core)', array(
'@module' => $requires_name,
));
$extra['disabled'] = TRUE;
}
elseif ($files[$requires]->status) {
$extra['requires'][$requires] = t('@module', array('@module' => $requires_name));
}
else {
$extra['requires'][$requires] = t('@module (disabled)', array('@module' => $requires_name));
}
}
}
// Generate link for module's help page, if there is one.
if ($help_arg && $module->status && in_array($filename, module_implements('help'))) {
if (module_invoke($filename, 'help', "admin/help#$filename", $help_arg)) {
$extra['links']['help'] = array(
'#type' => 'link',
'#title' => t('Help'),
'#href' => "admin/help/$filename",
'#options' => array('attributes' => array('class' => array('module-link', 'module-link-help'), 'title' => t('Help'))),
);
}
}
// Generate link for module's permission, if the user has access to it.
if ($module->status && user_access('administer permissions') && in_array($filename, module_implements('permission'))) {
$extra['links']['permissions'] = array(
'#type' => 'link',
'#title' => t('Permissions'),
'#href' => 'admin/people/permissions',
'#options' => array('fragment' => 'module-' . $filename, 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => t('Configure permissions'))),
);
}
// Generate link for module's configuration page, if the module provides
// one.
if ($module->status && isset($module->info['configure'])) {
$configure_link = menu_get_item($module->info['configure']);
if ($configure_link['access']) {
$extra['links']['configure'] = array(
'#type' => 'link',
'#title' => t('Configure'),
'#href' => $configure_link['href'],
'#options' => array('attributes' => array('class' => array('module-link', 'module-link-configure'), 'title' => $configure_link['description'])),
);
}
}
// If this module is required by other modules, list those, and then make it
// impossible to disable this one.
foreach ($module->required_by as $required_by => $v) {
// Hidden modules are unset already.
if (isset($visible_files[$required_by])) {
if ($files[$required_by]->status == 1 && $module->status == 1) {
$extra['required_by'][] = t('@module', array('@module' => $files[$required_by]->info['name']));
$extra['disabled'] = TRUE;
}
else {
$extra['required_by'][] = t('@module (disabled)', array('@module' => $files[$required_by]->info['name']));
}
}
}
$form['modules'][$module->info['package']][$filename] = _system_modules_build_row($module->info, $extra);
}
// Add basic information to the details.
foreach (element_children($form['modules']) as $package) {
$form['modules'][$package] += array(
'#type' => 'details',
'#title' => t($package),
'#theme' => 'system_modules_details',
'#header' => array(
array('data' => t('Enabled'), 'class' => array('checkbox')),
array('data' => t('Name'), 'class' => array('name')),
array('data' => t('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)),
),
// Ensure that the "Core" package comes first.
'#weight' => $package == 'Core' ? -10 : NULL,
);
}
// Lastly, sort all packages by title.
uasort($form['modules'], 'element_sort_by_title');
$form['#attached']['library'][] = array('system', 'drupal.system.modules');
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
$form['#action'] = url('admin/modules/list/confirm');
return $form;
}
/**
* Array sorting callback; sorts modules or themes by their name.
*/
function system_sort_modules_by_info_name($a, $b) {
return strcasecmp($a->info['name'], $b->info['name']);
}
/**
* Array sorting callback; sorts modules or themes by their name.
*/
function system_sort_themes($a, $b) {
if ($a->is_default) {
return -1;
}
if ($b->is_default) {
return 1;
}
return strcasecmp($a->info['name'], $b->info['name']);
}
/**
* Build a table row for the system modules page.
*/
function _system_modules_build_row($info, $extra) {
// Add in the defaults.
$extra += array(
'requires' => array(),
'required_by' => array(),
'disabled' => FALSE,
'enabled' => FALSE,
'links' => array(),
);
$form = array(
'#tree' => TRUE,
);
// Set the basic properties.
$form['name'] = array(
'#markup' => $info['name'],
);
$form['description'] = array(
'#markup' => t($info['description']),
);
$form['version'] = array(
'#markup' => $info['version'],
);
$form['#requires'] = $extra['requires'];
$form['#required_by'] = $extra['required_by'];
// Check the compatibilities.
$compatible = TRUE;
$status_short = '';
$status_long = '';
// Check the core compatibility.
if (!isset($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) {
$compatible = FALSE;
$status_short .= t('Incompatible with this version of Drupal core.');
$status_long .= t('This version is not compatible with Drupal !core_version and should be replaced.', array('!core_version' => DRUPAL_CORE_COMPATIBILITY));
}
// Ensure this module is compatible with the currently installed version of PHP.
if (version_compare(phpversion(), $info['php']) < 0) {
$compatible = FALSE;
$status_short .= t('Incompatible with this version of PHP');
$php_required = $info['php'];
if (substr_count($info['php'], '.') < 2) {
$php_required .= '.*';
}
$status_long .= t('This module requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $php_required, '!php_version' => phpversion()));
}
// If this module is compatible, present a checkbox indicating
// this module may be installed. Otherwise, show a big red X.
if ($compatible) {
$form['enable'] = array(
'#type' => 'checkbox',
'#title' => t('Enable'),
'#default_value' => $extra['enabled'],
'#attributes' => array('role' => 'disabled'),
);
if ($extra['disabled']) {
$form['enable']['#disabled'] = TRUE;
}
}
else {
$form['enable'] = array(
'#markup' => theme('image', array('uri' => 'core/misc/watchdog-error.png', 'alt' => $status_short, 'title' => $status_short)),
);
$form['description']['#markup'] .= theme('system_modules_incompatible', array('message' => $status_long));
}
// Build operation links.
foreach (array('help', 'permissions', 'configure') as $key) {
$form['links'][$key] = (isset($extra['links'][$key]) ? $extra['links'][$key] : array());
}
return $form;
}
/**
* Submit callback; handles modules form submission.
*/
function system_modules_submit($form, &$form_state) {
include_once DRUPAL_ROOT . '/core/includes/install.inc';
// Builds list of modules.
$modules = array();
// If we're not coming from the confirmation form, build the list of modules.
if (empty($form_state['storage'])) {
// If we're not coming from the confirmation form, build the module list.
foreach ($form_state['values']['modules'] as $group_name => $group) {
foreach ($group as $module => $enabled) {
$modules[$module] = array('group' => $group_name, 'enabled' => $enabled['enable']);
}
}
}
else {
// If we are coming from the confirmation form, fetch
// the modules out of $form_state.
$modules = $form_state['storage']['modules'];
}
// Collect data for all modules to be able to determine dependencies.
$files = system_rebuild_module_data();
// Sorts modules by weight.
$sort = array();
foreach (array_keys($modules) as $module) {
$sort[$module] = $files[$module]->sort;
}
array_multisort($sort, $modules);
// Makes sure all required modules are set to be enabled.
$more_required = array();
$missing_modules = array();
foreach ($modules as $name => $module) {
if ($module['enabled']) {
// Checks that all dependencies are set to be enabled. Stores the ones
// that are not in $dependencies variable so that the user can be alerted
// in the confirmation form that more modules need to be enabled.
$dependencies = array();
foreach (array_keys($files[$name]->requires) as $required) {
if (empty($modules[$required]['enabled'])) {
if (isset($files[$required])) {
$dependencies[] = $files[$required]->info['name'];
$modules[$required]['enabled'] = TRUE;
}
else {
$missing_modules[$required]['depends'][] = $name;
$modules[$name]['enabled'] = FALSE;
}
}
}
// Stores additional modules that need to be enabled in $more_required.
if (!empty($dependencies)) {
$more_required[$name] = array(
'name' => $files[$name]->info['name'],
'requires' => $dependencies,
);
}
}
}
// Redirects to confirmation form if more modules need to be enabled.
if ((!empty($more_required) || !empty($missing_modules)) && !isset($form_state['values']['confirm'])) {
$form_state['storage'] = array(
'more_required' => $more_required,
'modules' => $modules,
'missing_modules' => $missing_modules,
);
$form_state['rebuild'] = TRUE;
return;
}
// Invokes hook_requirements('install'). If failures are detected, makes sure
// the dependent modules aren't installed either.
foreach ($modules as $name => $module) {
// Only invoke hook_requirements() on modules that are going to be installed.
if ($module['enabled'] && drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) {
if (!drupal_check_module($name)) {
$modules[$name]['enabled'] = FALSE;
foreach (array_keys($files[$name]->required_by) as $required_by) {
$modules[$required_by]['enabled'] = FALSE;
}
}
}
}
// Initializes array of actions.
$actions = array(
'enable' => array(),
'disable' => array(),
'install' => array(),
);
// Builds arrays of modules that need to be enabled, disabled, and installed.
foreach ($modules as $name => $module) {
if ($module['enabled']) {
if (drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) {
$actions['install'][] = $name;
$actions['enable'][] = $name;
}
elseif (!module_exists($name)) {
$actions['enable'][] = $name;
}
}
elseif (module_exists($name)) {
$actions['disable'][] = $name;
}
}
// Gets list of modules prior to install process, unsets $form_state['storage']
// so we don't get redirected back to the confirmation form.
$pre_install_list = Drupal::moduleHandler()->getModuleList();
unset($form_state['storage']);
// Reverse the 'enable' list, to order dependencies before dependents.
krsort($actions['enable']);
// Installs, enables, and disables modules.
module_enable($actions['enable'], FALSE);
module_disable($actions['disable'], FALSE);
// Gets module list after install process, flushes caches and displays a
// message if there are changes.
$post_install_list = Drupal::moduleHandler()->getModuleList();
if ($pre_install_list != $post_install_list) {
drupal_flush_all_caches();
drupal_set_message(t('The configuration options have been saved.'));
}
$form_state['redirect'] = 'admin/modules';
}
/**
* Uninstall functions
*/
/**
* Form constructor for the uninstalling disabled modules form.
*
* @see system_menu()
* @see system_modules_uninstall_validate()
* @see system_modules_uninstall_submit()
*
* @ingroup forms
*/
function system_modules_uninstall($form, $form_state = NULL) {
// Make sure the install API is available.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
// Display the confirm form if any modules have been submitted.
if (!empty($form_state['storage']['uninstall']) && $modules = array_filter($form_state['storage']['uninstall'])) {
// Contents of confirm form is injected here because already in form
// building function.
$confirm_form = new ModulesUninstallConfirmForm();
return $confirm_form->buildForm($form, $form_state, $modules);
}
// Get a list of disabled, installed modules.
$all_modules = system_rebuild_module_data();
$disabled_modules = array();
foreach ($all_modules as $name => $module) {
if (empty($module->status) && drupal_get_installed_schema_version($name) > SCHEMA_UNINSTALLED) {
$disabled_modules[$name] = $module;
}
}
// Only build the rest of the form if there are any modules available to
// uninstall.
if (!empty($disabled_modules)) {
$profile = drupal_get_profile();
uasort($disabled_modules, 'system_sort_modules_by_info_name');
$form['uninstall'] = array('#tree' => TRUE);
foreach ($disabled_modules as $module) {
$module_name = $module->info['name'] ? $module->info['name'] : $module->name;
$form['modules'][$module->name]['#module_name'] = $module_name;
$form['modules'][$module->name]['name']['#markup'] = $module_name;
$form['modules'][$module->name]['description']['#markup'] = t($module->info['description']);
$form['uninstall'][$module->name] = array(
'#type' => 'checkbox',
'#title' => t('Uninstall @module module', array('@module' => $module_name)),
'#title_display' => 'invisible',
);
// All modules which depend on this one must be uninstalled first, before
// we can allow this module to be uninstalled. (The installation profile
// is excluded from this list.)
foreach (array_keys($module->required_by) as $dependent) {
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
$dependent_name = isset($all_modules[$dependent]->info['name']) ? $all_modules[$dependent]->info['name'] : $dependent;
$form['modules'][$module->name]['#required_by'][] = $dependent_name;
$form['uninstall'][$module->name]['#disabled'] = TRUE;
}
}
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Uninstall'),
);
$form['#action'] = url('admin/modules/uninstall/confirm');
}
else {
$form['modules'] = array();
}
return $form;
}
/**
* Validates the submitted uninstall form.
*/
function system_modules_uninstall_validate($form, &$form_state) {
// Form submitted, but no modules selected.
if (!count(array_filter($form_state['values']['uninstall']))) {
drupal_set_message(t('No modules selected.'), 'error');
drupal_goto('admin/modules/uninstall');
}
}
/**
* Processes the submitted uninstall form.
*/
function system_modules_uninstall_submit($form, &$form_state) {
// Make sure the install API is available.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
if (!empty($form['#confirmed'])) {
// Call the uninstall routine for each selected module.
$modules = array_keys($form_state['values']['uninstall']);
module_uninstall($modules);
drupal_set_message(t('The selected modules have been uninstalled.'));
$form_state['redirect'] = 'admin/modules/uninstall';
}
else {
$form_state['storage'] = $form_state['values'];
$form_state['rebuild'] = TRUE;
}
}
/**
* Default page callback for batches.
*/
function system_batch_page() {
require_once DRUPAL_ROOT . '/core/includes/batch.inc';
$output = _batch_page();
if ($output === FALSE) {
throw new AccessDeniedHttpException();
}
elseif ($output instanceof Response) {
return $output;
}
elseif (isset($output)) {
// Force a page without blocks or messages to
// display a list of collected messages later.
drupal_set_page_content($output);
$page = element_info('page');
$page['#show_messages'] = FALSE;
return $page;
}
}
/**
* Returns HTML for an administrative block for display.
*
* @param $variables
* An associative array containing:
* - block: An array containing information about the block:
* - show: A Boolean whether to output the block. Defaults to FALSE.
* - title: The block's title.
* - content: (optional) Formatted content for the block.
* - description: (optional) Description of the block. Only output if
* 'content' is not set.
*
* @ingroup themeable
*/
function theme_admin_block($variables) {
$block = $variables['block'];
$output = '';
// Don't display the block if it has no content to display.
if (empty($block['show'])) {
return $output;
}
$output .= '
' . t('Status') . ' | ' . t('Component') . ' | ' . t('Details') . ' | '; $output .= '
---|---|---|
' . $severity['icon'] . ' | '; $output .= '' . $requirement['title'] . ' | '; $output .= '' . $requirement['value'];
if (!empty($requirement['description'])) {
$output .= ' ' . $requirement['description'] . ' ';
}
$output .= ' |