Newer
Older
Dries Buytaert
committed
<?php
/**
* @file
* Admin page callbacks for the system module.
*/
use Symfony\Component\HttpFoundation\JsonResponse;
Larry Garfield
committed
use Symfony\Component\HttpFoundation\Response;
Dries Buytaert
committed
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
Angie Byron
committed
use Drupal\Core\Datetime\DrupalDateTime;
Larry Garfield
committed
Dries Buytaert
committed
/**
* Menu callback; Provide the administration overview page.
*/
function system_admin_config_page() {
// Check for status report errors.
if (system_status(TRUE) && user_access('administer site configuration')) {
drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))), 'error');
}
$blocks = array();
if ($admin = db_query("SELECT menu_name, mlid FROM {menu_links} WHERE link_path = 'admin/config' AND module = 'system'")->fetchAssoc()) {
$result = db_query("
SELECT m.*, ml.*
FROM {menu_links} ml
INNER JOIN {menu_router} m ON ml.router_path = m.path
Angie Byron
committed
WHERE ml.link_path <> 'admin/help' AND menu_name = :menu_name AND ml.plid = :mlid AND hidden = 0", $admin, array('fetch' => PDO::FETCH_ASSOC));
Dries Buytaert
committed
foreach ($result 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.
Dries Buytaert
committed
if (!empty($item['localized_options']['attributes']['title'])) {
$item['description'] = $item['localized_options']['attributes']['title'];
unset($item['localized_options']['attributes']['title']);
Dries Buytaert
committed
}
$block = $item;
$block['content'] = '';
Dries Buytaert
committed
$block['content'] .= theme('admin_block_content', array('content' => system_admin_menu_block($item)));
if (!empty($block['content'])) {
$block['show'] = TRUE;
}
Dries Buytaert
committed
// 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);
Dries Buytaert
committed
return theme('admin_page', array('blocks' => $blocks));
Dries Buytaert
committed
}
else {
return t('You do not have any administrative items.');
}
}
Dries Buytaert
committed
/**
* Provide a single block from the administration menu as a page.
Dries Buytaert
committed
*
Dries Buytaert
committed
* This function is often a destination for these blocks.
Dries Buytaert
committed
* For example, 'admin/structure/types' needs to have a destination to be valid
Dries Buytaert
committed
* 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.
Dries Buytaert
committed
*/
function system_admin_menu_block_page() {
$item = menu_get_item();
Dries Buytaert
committed
if ($content = system_admin_menu_block($item)) {
Dries Buytaert
committed
$output = theme('admin_block_content', array('content' => $content));
Dries Buytaert
committed
}
else {
$output = t('You do not have any administrative items.');
}
Dries Buytaert
committed
return $output;
}
* Menu callback; prints a listing of admin tasks, organized by module.
function system_admin_index() {
Angie Byron
committed
$module_info = system_get_info('module');
foreach ($module_info as $module => $info) {
Dries Buytaert
committed
$module_info[$module] = new stdClass();
$module_info[$module]->info = $info;
}
uasort($module_info, 'system_sort_modules_by_info_name');
$menu_items = array();
Angie Byron
committed
foreach ($module_info as $module => $info) {
// Only display a section if there are any available tasks.
if ($admin_tasks = system_get_module_admin_tasks($module, $info->info)) {
// Sort links by title.
uasort($admin_tasks, 'drupal_sort_title');
// Move 'Configure permissions' links to the bottom of each section.
$permission_key = "admin/people/permissions#module-$module";
if (isset($admin_tasks[$permission_key])) {
$permission_task = $admin_tasks[$permission_key];
unset($admin_tasks[$permission_key]);
$admin_tasks[$permission_key] = $permission_task;
$menu_items[$info->info['name']] = array($info->info['description'], $admin_tasks);
return theme('system_admin_index', array('menu_items' => $menu_items));
Dries Buytaert
committed
/**
* Menu callback; displays a listing of all themes.
*/
function system_themes_page() {
// Get current list of themes.
Dries Buytaert
committed
$themes = system_rebuild_theme_data();
uasort($themes, 'system_sort_modules_by_info_name');
Dries Buytaert
committed
Dries Buytaert
committed
$theme_default = variable_get('theme_default', 'stark');
Dries Buytaert
committed
$theme_groups = array();
catch
committed
$admin_theme = config('system.theme')->get('admin');
Dries Buytaert
committed
foreach ($themes as &$theme) {
if (!empty($theme->info['hidden'])) {
continue;
}
Dries Buytaert
committed
$theme->is_default = ($theme->name == $theme_default);
Dries Buytaert
committed
// Identify theme screenshot.
$theme->screenshot = NULL;
Angie Byron
committed
// 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;
Angie Byron
committed
}
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'])) {
Dries Buytaert
committed
$theme->screenshot = array(
'uri' => $themes[$theme_key]->info['screenshot'],
Dries Buytaert
committed
'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;
}
}
Gábor Hojtsy
committed
Dries Buytaert
committed
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));
Gábor Hojtsy
committed
}
Dries Buytaert
committed
$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) {
Dries Buytaert
committed
// 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']))),
);
Dries Buytaert
committed
if (!empty($theme->status)) {
if (!$theme->is_default) {
Dries Buytaert
committed
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']))),
);
}
Dries Buytaert
committed
$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']))),
);
}
Dries Buytaert
committed
$admin_theme_options[$theme->name] = $theme->info['name'];
Dries Buytaert
committed
}
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']))),
);
Dries Buytaert
committed
// 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');
}
Dries Buytaert
committed
if ($theme->name == $admin_theme || ($theme->is_default && $admin_theme == '0')) {
$theme->classes[] = 'theme-admin';
$theme->notes[] = t('admin theme');
}
Dries Buytaert
committed
// Sort enabled and disabled themes into their own groups.
$theme_groups[$theme->status ? 'enabled' : 'disabled'][] = $theme;
Dries Buytaert
committed
// 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');
Angie Byron
committed
}
Dries Buytaert
committed
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',
Dries Buytaert
committed
'#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.'),
catch
committed
'#default_value' => config('system.theme')->get('admin'),
);
Dries Buytaert
committed
$form['admin_theme']['actions'] = array('#type' => 'actions');
$form['admin_theme']['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
return $form;
}
/**
Dries Buytaert
committed
* Process system_themes_admin_form form submissions.
*/
Dries Buytaert
committed
function system_themes_admin_form_submit($form, &$form_state) {
drupal_set_message(t('The configuration options have been saved.'));
catch
committed
config('system.theme')->set('admin', $form_state['values']['admin_theme'])->save();
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Menu callback; Enables a theme.
*/
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();
Dries Buytaert
committed
// Check if the specified theme is one recognized by the system.
if (!empty($themes[$theme])) {
theme_enable(array($theme));
drupal_set_message(t('The %theme theme has been enabled.', array('%theme' => $themes[$theme]->info['name'])));
}
else {
drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
Dries Buytaert
committed
drupal_goto('admin/appearance');
Dries Buytaert
committed
throw new AccessDeniedHttpException();
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Menu callback; Disables a theme.
*/
function system_theme_disable() {
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();
Dries Buytaert
committed
// Check if the specified theme is one recognized by the system.
if (!empty($themes[$theme])) {
Dries Buytaert
committed
// Do not disable the default or admin theme.
catch
committed
if ($theme == variable_get('theme_default', 'stark') || $theme == config('system.theme')->get('admin')) {
Dries Buytaert
committed
drupal_set_message(t('%theme is the default theme and cannot be disabled.', array('%theme' => $themes[$theme]->info['name'])), 'error');
}
else {
theme_disable(array($theme));
drupal_set_message(t('The %theme theme has been disabled.', array('%theme' => $themes[$theme]->info['name'])));
Dries Buytaert
committed
else {
drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
Dries Buytaert
committed
drupal_goto('admin/appearance');
Dries Buytaert
committed
throw new AccessDeniedHttpException();
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* 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();
Dries Buytaert
committed
// 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.
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();
Dries Buytaert
committed
// 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.
catch
committed
$admin_theme = config('system.theme')->get('admin');
Dries Buytaert
committed
if ($admin_theme != 0 && $admin_theme != $theme) {
Dries Buytaert
committed
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');
}
Dries Buytaert
committed
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
Gábor Hojtsy
committed
* @see system_theme_settings_submit()
function system_theme_settings($form, &$form_state, $key = '') {
Dries Buytaert
committed
// Default settings are defined in theme_get_setting() in includes/theme.inc
if ($key) {
Dries Buytaert
committed
$var = 'theme_' . $key . '_settings';
$themes = list_themes();
$features = $themes[$key]->info['features'];
}
else {
$var = 'theme_settings';
}
$form['var'] = array('#type' => 'hidden', '#value' => $var);
// Toggle settings
$toggles = array(
Dries Buytaert
committed
'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;
}
Dries Buytaert
committed
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)) {
Dries Buytaert
committed
$form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('toggle_' . $name, $key));
Gábor Hojtsy
committed
// Disable checkboxes for features not supported in the current configuration.
if (isset($disabled['toggle_' . $name])) {
$form['theme_settings']['toggle_' . $name]['#disabled'] = TRUE;
}
}
}
Angie Byron
committed
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;
}
Angie Byron
committed
// 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')),
Angie Byron
committed
$form['logo']['default_logo'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default logo supplied by the theme'),
Dries Buytaert
committed
'#default_value' => theme_get_setting('default_logo', $key),
'#tree' => FALSE,
);
Dries Buytaert
committed
$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),
Dries Buytaert
committed
);
$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.")
);
}
Angie Byron
committed
if ((!$key) || in_array('favicon', $features) && module_exists('file')) {
$form['favicon'] = array(
'#type' => 'details',
'#title' => t('Shortcut icon settings'),
Angie Byron
committed
'#description' => t("Your shortcut icon, or 'favicon', is displayed in the address bar and bookmarks of most browsers."),
);
$form['favicon']['default_favicon'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default shortcut icon supplied by the theme'),
Dries Buytaert
committed
'#default_value' => theme_get_setting('default_favicon', $key),
Dries Buytaert
committed
$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),
Dries Buytaert
committed
$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.")
);
}
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
// 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: <code>@implicit-public-file</code> (for a file in the public filesystem), <code>@explicit-file</code>, or <code>@local-file</code>.', 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) {
Gábor Hojtsy
committed
// Call engine-specific settings.
$function = $themes[$key]->prefix . '_engine_settings';
if (function_exists($function)) {
Dries Buytaert
committed
$form['engine_specific'] = array(
'#type' => 'details',
Dries Buytaert
committed
'#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);
Gábor Hojtsy
committed
}
Dries Buytaert
committed
// 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;
Gábor Hojtsy
committed
}
Dries Buytaert
committed
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", '', $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);
Dries Buytaert
committed
// Restore the original current theme.
Dries Buytaert
committed
if (isset($default_theme)) {
Dries Buytaert
committed
$GLOBALS['theme_key'] = $default_theme;
}
else {
unset($GLOBALS['theme_key']);
}
Dries Buytaert
committed
$form = system_settings_form($form);
// We don't want to call system_settings_form_submit(), so change #submit.
Dries Buytaert
committed
array_pop($form['#submit']);
$form['#submit'][] = 'system_theme_settings_submit';
Angie Byron
committed
$form['#validate'][] = 'system_theme_settings_validate';
return $form;
}
Angie Byron
committed
/**
* Validator for the system_theme_settings() form.
*/
function system_theme_settings_validate($form, &$form_state) {
Angie Byron
committed
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);
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.'));
}
Angie Byron
committed
}
Angie Byron
committed
$validators = array('file_validate_extensions' => array('ico png gif jpg jpeg apng svg'));
Angie Byron
committed
// Check for a new uploaded favicon.
$file = file_save_upload('favicon_upload', $validators);
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.'));
}
Angie Byron
committed
}
Angie Byron
committed
// 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.'));
}
Angie Byron
committed
}
Angie Byron
committed
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.'));
}
Angie Byron
committed
}
}
}
/**
* 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)) {
Angie Byron
committed
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;
Angie Byron
committed
}
return FALSE;
}
/**
* Process system_theme_settings form submissions.
*/
function system_theme_settings_submit($form, &$form_state) {
// Exclude unnecessary elements before saving.
form_state_values_clean($form_state);
$values = $form_state['values'];
Angie Byron
committed
// Extract the name of the theme from the submitted form values, then
// remove it from the array so that it is not saved as part of the variable.
$key = $values['var'];
unset($values['var']);
Angie Byron
committed
// 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.
Angie Byron
committed
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;
}
Angie Byron
committed
Angie Byron
committed
// 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']);
}
Angie Byron
committed
Angie Byron
committed
if (empty($values['default_favicon']) && !empty($values['favicon_path'])) {
$values['favicon_mimetype'] = file_get_mimetype($values['favicon_path']);
}
}
variable_set($key, $values);
drupal_set_message(t('The configuration options have been saved.'));
cache_invalidate_tags(array('content' => TRUE));
Dries Buytaert
committed
/**
* Recursively check compatibility.
*
* @param $incompatible
Dries Buytaert
committed
* 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
Dries Buytaert
committed
* Returns TRUE if an incompatible file is found, NULL (no return value)
* otherwise.
Dries Buytaert
committed
*/
function _system_is_incompatible(&$incompatible, $files, $file) {
if (isset($incompatible[$file->name])) {
return TRUE;
}
Dries Buytaert
committed
// Recursively traverse required modules, looking for incompatible modules.
foreach ($file->requires as $requires) {
if (isset($files[$requires]) && _system_is_incompatible($incompatible, $files, $files[$requires])) {
Dries Buytaert
committed
$incompatible[$file->name] = TRUE;
return TRUE;
}
}
}
/**
* Menu callback; provides module enable/disable interface.
*
Dries Buytaert
committed
* The list of modules gets populated by module.info 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 descriptors.
Dries Buytaert
committed
* 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.
* @param $form_state
* An associative array containing the current state of the form.
Dries Buytaert
committed
*
* @return
* The form array.
*
* @ingroup forms
Gábor Hojtsy
committed
* @see theme_system_modules()
* @see system_modules_submit()
function system_modules($form, $form_state = array()) {
// Get current list of modules.
Angie Byron
committed
$files = system_rebuild_module_data();
// Remove hidden modules from display list.
Angie Byron
committed
$visible_files = $files;
foreach ($visible_files as $filename => $file) {
Angie Byron
committed
if (!empty($file->info['hidden'])) {
Angie Byron
committed
unset($visible_files[$filename]);
}
}
Angie Byron
committed
uasort($visible_files, 'system_sort_modules_by_info_name');
Dries Buytaert
committed
// If the modules form was submitted, then system_modules_submit() runs first
// and if there are unfilled required modules, then $form_state['storage'] is
Dries Buytaert
committed
// filled, triggering a rebuild. In this case we need to display a
// confirmation form.
if (!empty($form_state['storage'])) {
Angie Byron
committed
return system_modules_confirm_form($visible_files, $form_state['storage']);
Dries Buytaert
committed
$modules = array();
$form['modules'] = array('#tree' => TRUE);
Dries Buytaert
committed
Dries Buytaert
committed
// Used when checking if module implements a help page.
$help_arg = module_exists('help') ? drupal_help_arg() : FALSE;
Jennifer Hodgdon
committed
// Used when displaying modules that are required by the installation profile.
Nate Lampton
committed
require_once DRUPAL_ROOT . '/core/includes/install.inc';
Angie Byron
committed
$distribution_name = check_plain(drupal_install_profile_distribution_name());
// Iterate through each of the modules.
Angie Byron
committed
foreach ($visible_files as $filename => $module) {
$extra = array();
$extra['enabled'] = (bool) $module->status;
Angie Byron
committed
if (!empty($module->info['required'] )) {
$extra['disabled'] = TRUE;
Angie Byron
committed
$extra['required_by'][] = $distribution_name . (!empty($module->info['explanation']) ? ' ('. $module->info['explanation'] .')' : '');
Angie Byron
committed
}
Dries Buytaert
committed
// 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 (<span class="admin-missing">missing</span>)', array('@module' => drupal_ucfirst($requires)));
Dries Buytaert
committed
$extra['disabled'] = TRUE;
}
Angie Byron
committed
// Only display visible modules.
elseif (isset($visible_files[$requires])) {
Dries Buytaert
committed
$requires_name = $files[$requires]->info['name'];
catch
committed
// Disable this module if it is incompatible with the dependency's version.
Angie Byron
committed
if ($incompatible_version = drupal_check_incompatibility($v, str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $files[$requires]->info['version']))) {
$extra['requires'][$requires] = t('@module (<span class="admin-missing">incompatible with</span> version @version)', array(
'@module' => $requires_name . $incompatible_version,
'@version' => $files[$requires]->info['version'],
));
$extra['disabled'] = TRUE;
catch
committed
// 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 (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array(
'@module' => $requires_name,
));
$extra['disabled'] = TRUE;
}
Angie Byron
committed
elseif ($files[$requires]->status) {
$extra['requires'][$requires] = t('@module', array('@module' => $requires_name));
Angie Byron
committed
}
else {
$extra['requires'][$requires] = t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $requires_name));
}
// Generate link for module's help page, if there is one.
Dries Buytaert
committed
if ($help_arg && $module->status && in_array($filename, module_implements('help'))) {
if (module_invoke($filename, 'help', "admin/help#$filename", $help_arg)) {
Dries Buytaert
committed
$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'))),
);
Dries Buytaert
committed
// 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'),
Angie Byron
committed
'#href' => 'admin/people/permissions',
Dries Buytaert
committed
'#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'])),
);
}
}
Dries Buytaert
committed
// 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.
Angie Byron
committed
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 {
Dries Buytaert
committed
$extra['required_by'][] = t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $files[$required_by]->info['name']));
$form['modules'][$module->info['package']][$filename] = _system_modules_build_row($module->info, $extra);
Angie Byron
committed
// Add basic information to the details.
foreach (element_children($form['modules']) as $package) {
$form['modules'][$package] += array(
'#type' => 'details',
'#title' => t($package),
'#collapsible' => TRUE,
'#theme' => 'system_modules_details',
'#header' => array(
array('data' => t('<span class="element-invisible">Enabled</span>'), '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');
Dries Buytaert
committed
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
Angie Byron
committed
$form['#action'] = url('admin/modules/list/confirm');
return $form;
}
/**
Gábor Hojtsy
committed
* 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']);
}
Dries Buytaert
committed
/**
* 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(
Dries Buytaert
committed
'requires' => array(),
'required_by' => array(),
'disabled' => FALSE,
'enabled' => FALSE,
Dries Buytaert
committed
'links' => array(),
);
$form = array(
'#tree' => TRUE,
);
// Set the basic properties.
$form['name'] = array(
Angie Byron
committed
'#markup' => $info['name'],
);
$form['description'] = array(
'#markup' => t($info['description']),
);
$form['version'] = array(
'#markup' => $info['version'],
);
Dries Buytaert
committed
$form['#requires'] = $extra['requires'];
$form['#required_by'] = $extra['required_by'];
// Check the compatibilities.
$compatible = TRUE;
$status_short = '';
$status_long = '';
// Check the core compatibility.
Dries Buytaert
committed
if (!isset($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) {