admin_menu.inc in Administration menu 8.3
Same filename and directory in other branches
Menu builder functions for Administration menu.
File
admin_menu.incView source
<?php
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* @file
* Menu builder functions for Administration menu.
*/
/**
* Build the full administration menu tree from static and expanded dynamic items.
*
* @param $menu_name The menu name to use as base for the tree.
*/
function admin_menu_tree($menu_name) {
// Get placeholder expansion arguments from hook_admin_menu_map()
// implementations.
module_load_include('inc', 'admin_menu', 'admin_menu.map');
$expand_map = module_invoke_all('admin_menu_map');
// Allow modules to alter the expansion map.
drupal_alter('admin_menu_map', $expand_map);
$new_map = [];
foreach ($expand_map as $path => $data) {
// Convert named placeholders to anonymous placeholders, since the menu
// system stores paths using anonymous placeholders.
$replacements = array_fill_keys(array_keys($data['arguments'][0]), '%');
$data['parent'] = strtr($data['parent'], $replacements);
$new_map[strtr($path, $replacements)] = $data;
}
$expand_map = $new_map;
unset($new_map);
// Retrieve dynamic menu link tree for the expansion mappings.
// @todo Skip entire processing if initial $expand_map is empty and directly
// return $tree?
if (!empty($expand_map)) {
$tree_dynamic = admin_menu_tree_dynamic($expand_map);
}
else {
$tree_dynamic = [];
}
// Merge local tasks with static menu tree.
$tree = menu_tree_all_data($menu_name);
admin_menu_merge_tree($tree, $tree_dynamic, []);
return $tree;
}
/**
* Load menu link trees for router paths containing dynamic arguments.
*
* @param $expand_map
* An array containing menu router path placeholder expansion argument
* mappings.
*
* @return
* An associative array whose keys are the parent paths of the menu router
* paths given in $expand_map as well as the parent paths of any child link
* deeper down the tree. The parent paths are used in admin_menu_merge_tree()
* to check whether anything needs to be merged.
*
* @see hook_admin_menu_map()
*/
function admin_menu_tree_dynamic(array $expand_map) {
$p_columns = [];
for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
$p_columns[] = 'p' . $i;
}
// Fetch p* columns for all router paths to expand.
$router_paths = array_keys($expand_map);
// TODO: Drupal Rector Notice: Please delete the following comment after you've made any necessary changes.
// You will need to use `\Drupal\core\Database\Database::getConnection()` if you do not yet have access to the container here.
$plids = \Drupal::database()
->select('menu_links', 'ml')
->fields('ml', $p_columns)
->condition('router_path', $router_paths)
->execute()
->fetchAll(PDO::FETCH_ASSOC);
// Unlikely, but possible.
if (empty($plids)) {
return [];
}
// Use queried plid columns to query sub-trees for the router paths.
// TODO: Drupal Rector Notice: Please delete the following comment after you've made any necessary changes.
// You will need to use `\Drupal\core\Database\Database::getConnection()` if you do not yet have access to the container here.
$query = \Drupal::database()
->select('menu_links', 'ml');
$query
->join('menu_router', 'm', 'ml.router_path = m.path');
$query
->fields('ml')
->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), drupal_schema_fields_sql('menu_links')));
// The retrieved menu link trees have to be ordered by depth, so parents
// always come before their children for the storage logic below.
foreach ($p_columns as $column) {
$query
->orderBy($column, 'ASC');
}
$db_or = db_or();
foreach ($plids as $path_plids) {
$db_and = db_and();
// plids with value 0 may be ignored.
foreach (array_filter($path_plids) as $column => $plid) {
$db_and
->condition($column, $plid);
}
$db_or
->condition($db_and);
}
$query
->condition($db_or);
$result = $query
->execute()
->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
// Store dynamic links grouped by parent path for later merging and assign
// placeholder expansion arguments.
$tree_dynamic = [];
foreach ($result as $link) {
// If contained in $expand_map, then this is a (first) parent, and we need
// to store by the defined 'parent' path for later merging, as well as
// provide the expansion map arguments to apply to the dynamic tree.
if (isset($expand_map[$link['path']])) {
$parent_path = $expand_map[$link['path']]['parent'];
$link['expand_map'] = $expand_map[$link['path']]['arguments'];
}
else {
$parent_path = $result[$link['plid']]['path'];
}
$tree_dynamic[$parent_path][] = $link;
}
return $tree_dynamic;
}
/**
* Walk through the entire menu tree and merge in expanded dynamic menu links.
*
* @param &$tree
* A menu tree structure as returned by menu_tree_all_data().
* @param $tree_dynamic
* A dynamic menu tree structure as returned by admin_menu_tree_dynamic().
* @param $expand_map
* An array containing menu router path placeholder expansion argument
* mappings.
*
* @see hook_admin_menu_map()
* @see admin_menu_tree_dynamic()
* @see menu_tree_all_data()
*/
function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_map) {
foreach ($tree as $key => $data) {
$path = $data['link']['router_path'];
// Recurse into regular menu tree.
if ($tree[$key]['below']) {
admin_menu_merge_tree($tree[$key]['below'], $tree_dynamic, $expand_map);
}
// Nothing to merge, if this parent path is not in our dynamic tree.
if (!isset($tree_dynamic[$path])) {
continue;
}
// Add expanded dynamic items.
foreach ($tree_dynamic[$path] as $link) {
// If the dynamic item has custom placeholder expansion parameters set,
// use them, otherwise keep current.
if (isset($link['expand_map'])) {
// If there are currently no expansion parameters, we may use the new
// set immediately.
if (empty($expand_map)) {
$current_expand_map = $link['expand_map'];
}
else {
// Otherwise we need to filter out elements that differ from the
// current set, i.e. that are not in the same path.
$current_expand_map = [];
foreach ($expand_map as $arguments) {
foreach ($arguments as $placeholder => $value) {
foreach ($link['expand_map'] as $new_arguments) {
// Skip the new argument if it doesn't contain the current
// replacement placeholders or if their values differ.
if (!isset($new_arguments[$placeholder]) || $new_arguments[$placeholder] != $value) {
continue;
}
$current_expand_map[] = $new_arguments;
}
}
}
}
}
else {
$current_expand_map = $expand_map;
}
// Skip dynamic items without expansion parameters.
if (empty($current_expand_map)) {
continue;
}
// Expand anonymous to named placeholders.
// @see _menu_load_objects()
$path_args = explode('/', $link['path']);
$load_functions = unserialize($link['load_functions']);
if (is_array($load_functions)) {
foreach ($load_functions as $index => $function) {
if ($function) {
if (is_array($function)) {
list($function, ) = each($function);
}
// Add the loader function name minus "_load".
$placeholder = '%' . substr($function, 0, -5);
$path_args[$index] = $placeholder;
}
}
}
$path_dynamic = implode('/', $path_args);
// Create new menu items using expansion arguments.
foreach ($current_expand_map as $arguments) {
// Create the cartesian product for all arguments and create new
// menu items for each generated combination thereof.
foreach (admin_menu_expand_args($arguments) as $replacements) {
$newpath = strtr($path_dynamic, $replacements);
// Skip this item, if any placeholder could not be replaced.
// Faster than trying to invoke _menu_translate().
if (strpos($newpath, '%') !== FALSE) {
continue;
}
$map = explode('/', $newpath);
$item = admin_menu_translate($link, $map);
// Skip this item, if the current user does not have access.
if (empty($item)) {
continue;
}
// Build subtree using current replacement arguments.
$new_expand_map = [];
foreach ($replacements as $placeholder => $value) {
$new_expand_map[$placeholder] = [
$value,
];
}
admin_menu_merge_tree($item, $tree_dynamic, [
$new_expand_map,
]);
$tree[$key]['below'] += $item;
}
}
}
// Sort new subtree items.
ksort($tree[$key]['below']);
}
}
/**
* Translate an expanded router item into a menu link suitable for rendering.
*
* @param $router_item
* A menu router item.
* @param $map
* A path map with placeholders replaced.
*/
function admin_menu_translate($router_item, $map) {
_menu_translate($router_item, $map, TRUE);
// Run through hook_translated_menu_link_alter() to add devel information,
// if configured.
$router_item['menu_name'] = 'management';
// @todo Invoke as usual like _menu_link_translate().
admin_menu_translated_menu_link_alter($router_item, NULL);
if ($router_item['access']) {
// Override mlid to make this item unique; since these items are expanded
// from dynamic items, the mlid is always the same, so each item would
// replace any other.
// @todo Doing this instead leads to plenty of duplicate links below
// admin/structure/menu; likely a hidden recursion problem.
// $router_item['mlid'] = $router_item['href'] . $router_item['mlid'];
$router_item['mlid'] = $router_item['href'];
// Turn menu callbacks into regular menu items to make them visible.
if ($router_item['type'] == MENU_CALLBACK) {
$router_item['type'] = MENU_NORMAL_ITEM;
}
// @see _menu_tree_check_access()
$key = 50000 + $router_item['weight'] . ' ' . $router_item['title'] . ' ' . $router_item['mlid'];
return [
$key => [
'link' => $router_item,
'below' => [],
],
];
}
return [];
}
/**
* Create the cartesian product of multiple varying sized argument arrays.
*
* @param $arguments
* A two dimensional array of arguments.
*
* @see hook_admin_menu_map()
*/
function admin_menu_expand_args($arguments) {
$replacements = [];
// Initialize line cursors, move out array keys (placeholders) and assign
// numeric keys instead.
$i = 0;
$placeholders = [];
$new_arguments = [];
foreach ($arguments as $placeholder => $values) {
// Skip empty arguments.
if (empty($values)) {
continue;
}
$cursor[$i] = 0;
$placeholders[$i] = $placeholder;
$new_arguments[$i] = $values;
$i++;
}
$arguments = $new_arguments;
unset($new_arguments);
if ($rows = count($arguments)) {
do {
// Collect current argument from each row.
$row = [];
for ($i = 0; $i < $rows; ++$i) {
$row[$placeholders[$i]] = $arguments[$i][$cursor[$i]];
}
$replacements[] = $row;
// Increment cursor position.
$j = $rows - 1;
$cursor[$j]++;
while (!array_key_exists($cursor[$j], $arguments[$j])) {
// No more arguments left: reset cursor, go to next line and increment
// that cursor instead. Repeat until argument found or out of rows.
$cursor[$j] = 0;
if (--$j < 0) {
// We're done.
break 2;
}
$cursor[$j]++;
}
} while (1);
}
return $replacements;
}
/**
* Build the administration menu as renderable menu links.
*
* @param $tree
* A data structure representing the administration menu tree as returned from
* menu_tree_all_data().
*
* @return
* The complete administration menu, suitable for theme_admin_menu_links().
*
* @see theme_admin_menu_links()
* @see admin_menu_menu_alter()
*/
function admin_menu_links_menu($tree) {
$links = [];
foreach ($tree as $data) {
// Skip items that are inaccessible, invisible, or link to their parent.
// (MENU_DEFAULT_LOCAL_TASK), and MENU_CALLBACK-alike items that should only
// appear in the breadcrumb.
if (!$data['link']['access'] || $data['link']['type'] & MENU_LINKS_TO_PARENT || $data['link']['type'] == MENU_VISIBLE_IN_BREADCRUMB || $data['link']['hidden'] == 1) {
continue;
}
// Hide 'Administer' and make child links appear on this level.
// @todo Make this configurable.
if ($data['link']['router_path'] == 'admin') {
if ($data['below']) {
$links = array_merge($links, admin_menu_links_menu($data['below']));
}
continue;
}
// Omit alias lookups.
$data['link']['localized_options']['alias'] = TRUE;
// Remove description to prevent mouseover tooltip clashes.
unset($data['link']['localized_options']['attributes']['title']);
// Make action links (typically "Add ...") appear first in dropdowns.
// They might appear first already, but only as long as there is no link
// that comes alphabetically first (e.g., a node type with label "Ad").
if ($data['link']['type'] & MENU_IS_LOCAL_ACTION) {
$data['link']['weight'] -= 1000;
}
$links[$data['link']['href']] = [
'#title' => $data['link']['title'],
'#href' => $data['link']['href'],
'#options' => $data['link']['localized_options'],
'#weight' => $data['link']['weight'],
];
// Recurse to add any child links.
$children = [];
if ($data['below']) {
$children = admin_menu_links_menu($data['below']);
$links[$data['link']['href']] += $children;
}
// Handle links pointing to category/overview pages.
if ($data['link']['page_callback'] == 'system_admin_menu_block_page' || $data['link']['page_callback'] == 'system_admin_config_page') {
// Apply a marker for others to consume.
$links[$data['link']['href']]['#is_category'] = TRUE;
// Automatically hide empty categories.
// Check for empty children first for performance. Only when non-empty
// (typically 'admin/config'), check whether children are accessible.
if (empty($children) || !element_get_visible_children($children)) {
$links[$data['link']['href']]['#access'] = FALSE;
}
}
}
return $links;
}
/**
* Build icon menu links; mostly containing maintenance helpers.
*
* @see theme_admin_menu_links()
*/
function admin_menu_links_icon() {
$destination = \Drupal::service('redirect.destination')
->getAsArray();
$links = [
'#theme' => 'admin_menu_links',
'#wrapper_attributes' => [
'id' => 'admin-menu-icon',
],
'#weight' => -100,
];
$links['icon'] = [
'#title' => theme('admin_menu_icon'),
'#attributes' => [
'class' => [
'admin-menu-icon',
],
],
'#href' => '<front>',
'#options' => [
'html' => TRUE,
],
];
// Add link to manually run cron.
$links['icon']['cron'] = [
'#title' => t('Run cron'),
'#weight' => 50,
'#access' => user_access('administer site configuration'),
'#href' => 'admin/reports/status/run-cron',
'#options' => [
'query' => $destination,
],
];
// Add link to run update.php.
$links['icon']['update'] = [
'#title' => t('Run updates'),
'#weight' => 50,
// @see update_access_allowed()
'#access' => $GLOBALS['user']->uid == 1 || !empty($GLOBALS['update_free_access']) || user_access('administer software updates'),
'#href' => base_path() . 'update.php',
'#options' => [
'external' => TRUE,
],
];
// Add link to drupal.org.
$links['icon']['drupal.org'] = [
'#title' => 'Drupal.org',
'#weight' => 100,
'#access' => user_access('display drupal links'),
'#href' => 'http://drupal.org',
];
// Add links to project issue queues.
foreach (module_list() as $module) {
$info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info.yml');
if (!isset($info['project']) || isset($links['icon']['drupal.org'][$info['project']])) {
continue;
}
$links['icon']['drupal.org'][$info['project']] = [
'#title' => t('@project issue queue', [
'@project' => $info['name'],
]),
'#weight' => $info['project'] == 'drupal' ? -10 : 0,
'#href' => 'http://drupal.org/project/issues/' . $info['project'],
'#options' => [
'query' => [
'version' => isset($info['core']) ? $info['core'] : 'All',
],
],
];
}
// Add items to flush caches.
$links['icon']['flush-cache'] = [
'#title' => t('Flush all caches'),
'#weight' => 20,
'#access' => user_access('flush caches'),
'#href' => 'admin_menu/flush-cache',
'#options' => [
'query' => $destination + [
'token' => drupal_get_token('admin_menu/flush-cache'),
],
],
];
$caches = module_invoke_all('admin_menu_cache_info');
foreach ($caches as $name => $cache) {
$links['icon']['flush-cache'][$name] = [
'#title' => $cache['title'],
'#href' => 'admin_menu/flush-cache/' . $name,
'#options' => [
'query' => $destination + [
'token' => drupal_get_token('admin_menu/flush-cache/' . $name),
],
],
];
}
// Add Devel module menu links.
if (module_exists('devel')) {
$devel_tree = menu_build_tree('devel');
$devel_links = admin_menu_links_menu($devel_tree);
if (element_get_visible_children($devel_links)) {
$links['icon']['devel'] = [
'#title' => t('Development'),
'#weight' => 30,
] + $devel_links;
}
}
return $links;
}
/**
* Builds the account links.
*
* @see theme_admin_menu_links()
*/
function admin_menu_links_account() {
$links = [
'#theme' => 'admin_menu_links',
'#wrapper_attributes' => [
'id' => 'admin-menu-account',
],
'#weight' => 100,
];
$links['account'] = [
'#title' => user_format_name($GLOBALS['user']),
'#weight' => -99,
'#attributes' => [
'class' => [
'admin-menu-action',
'admin-menu-account',
],
],
'#href' => 'user/' . $GLOBALS['user']->uid,
];
$links['logout'] = [
'#title' => t('Log out'),
'#weight' => -100,
'#attributes' => [
'class' => [
'admin-menu-action',
],
],
'#href' => 'user/logout',
];
// Add Devel module switch user links.
if (!module_exists('masquerade')) {
$switch_links = module_invoke('devel', 'switch_user_list');
if (!empty($switch_links) && count($switch_links) > 1) {
foreach ($switch_links as $uid => $link) {
$links['account'][$uid] = [
'#title' => $link['title'],
'#description' => $link['attributes']['title'],
'#href' => $link['href'],
'#options' => [
'query' => $link['query'],
'html' => !empty($link['html']),
],
];
}
}
}
return $links;
}
/**
* Builds user counter.
*
* @see theme_admin_menu_links()
*/
function admin_menu_links_users() {
$links = [
'#theme' => 'admin_menu_links',
'#wrapper_attributes' => [
'id' => 'admin-menu-users',
],
'#weight' => 150,
];
// Add link to show current authenticated/anonymous users.
$links['user-counter'] = [
'#title' => admin_menu_get_user_count(),
'#description' => t('Current anonymous / authenticated users'),
'#weight' => -90,
'#attributes' => [
'class' => [
'admin-menu-action',
'admin-menu-users',
],
],
'#href' => user_access('administer users') ? 'admin/people/people' : 'user',
];
return $links;
}
/**
* Build search widget.
*
* @see theme_admin_menu_links()
*/
function admin_menu_links_search() {
$links = [
'#theme' => 'admin_menu_links',
'#wrapper_attributes' => [
'id' => 'admin-menu-search',
],
'#weight' => 180,
];
$links['search'] = [
'#type' => 'textfield',
'#title' => t('Search'),
'#title_display' => 'attribute',
'#attributes' => [
'placeholder' => t('Search'),
'class' => [
'admin-menu-search',
],
],
];
return $links;
}
/**
* Form builder function for module settings.
*/
function admin_menu_admin_settings_form($form, &$form_state) {
$form['admin_menu_margin_top'] = [
'#type' => 'checkbox',
'#title' => t('Adjust top margin'),
'#default_value' => variable_get('admin_menu_margin_top', 1),
'#description' => t('Shifts the site output down by approximately 20 pixels from the top of the viewport. If disabled, absolute- or fixed-positioned page elements may be covered by the administration menu.'),
];
$form['admin_menu_position_fixed'] = [
'#type' => 'checkbox',
'#title' => t('Keep menu at top of page'),
'#default_value' => variable_get('admin_menu_position_fixed', 1),
'#description' => t('Displays the administration menu always at the top of the browser viewport (even when scrolling the page).'),
];
// @todo Re-confirm this with latest browser versions.
$form['admin_menu_position_fixed']['#description'] .= '<br /><strong>' . t('In some browsers, this setting may result in a malformed page, an invisible cursor, non-selectable elements in forms, or other issues.') . '</strong>';
$form['advanced'] = [
'#type' => 'vertical_tabs',
'#title' => t('Advanced settings'),
];
$form['plugins'] = [
'#type' => 'details',
'#title' => t('Plugins'),
'#group' => 'advanced',
];
$form['plugins']['admin_menu_components'] = [
'#type' => 'checkboxes',
'#title' => t('Enabled components'),
'#options' => [
'admin_menu.icon' => t('Icon menu'),
'admin_menu.menu' => t('Administration menu'),
'admin_menu.search' => t('Search bar'),
'admin_menu.users' => t('User counts'),
'admin_menu.account' => t('Account links'),
],
];
$form['plugins']['admin_menu_components']['#default_value'] = array_keys(array_filter(variable_get('admin_menu_components', $form['plugins']['admin_menu_components']['#options'])));
$process = element_info_property('checkboxes', '#process', []);
$form['plugins']['admin_menu_components']['#process'] = array_merge([
'admin_menu_settings_process_components',
], $process);
$form['#attached']['js'][] = drupal_get_path('module', 'admin_menu') . '/admin_menu.admin.js';
$form['tweaks'] = [
'#type' => 'details',
'#title' => t('System tweaks'),
'#group' => 'advanced',
];
$form['tweaks']['admin_menu_tweak_modules'] = [
'#type' => 'checkbox',
'#title' => t('Collapse module groups on the <a href="!modules-url">%modules</a> page', [
'%modules' => t('Modules'),
'!modules-url' => url('admin/modules'),
]),
'#default_value' => variable_get('admin_menu_tweak_modules', 0),
];
if (module_exists('util')) {
$form['tweaks']['admin_menu_tweak_modules']['#description'] .= '<br /><strong>' . t('If the Utility module was installed for this purpose, it can be safely disabled and uninstalled.') . '</strong>';
}
$form['tweaks']['admin_menu_tweak_permissions'] = [
'#type' => 'checkbox',
'#title' => t('Collapse module groups on the <a href="@permissions-url">%permissions</a> page', [
'%permissions' => t('Permissions'),
'@permissions-url' => url('admin/people/permissions'),
]),
'#default_value' => variable_get('admin_menu_tweak_permissions', 0),
];
$form['tweaks']['admin_menu_tweak_tabs'] = [
'#type' => 'checkbox',
'#title' => t('Move local tasks into menu'),
'#default_value' => variable_get('admin_menu_tweak_tabs', 0),
'#description' => t('Moves the tabs on all pages into the administration menu. Only possible for themes using the CSS classes <code>tabs primary</code> and <code>tabs secondary</code>.'),
];
$form['performance'] = [
'#type' => 'details',
'#title' => t('Performance'),
'#group' => 'advanced',
];
$form['performance']['admin_menu_cache_client'] = [
'#type' => 'checkbox',
'#title' => t('Cache menu in client-side browser'),
'#default_value' => variable_get('admin_menu_cache_client', 1),
];
return system_settings_form($form);
}
/**
* #process callback for component plugin form element in admin_menu_theme_settings().
*/
function admin_menu_settings_process_components($element) {
// Assign 'rel' attributes to all options to achieve a live preview.
// Unfortunately, #states relies on wrapping .form-wrapper classes, so it
// cannot be used here.
foreach ($element['#options'] as $key => $label) {
if (!isset($element[$key]['#attributes']['rel'])) {
$id = preg_replace('/[^a-z]/', '-', $key);
$element[$key]['#attributes']['rel'] = '#' . $id;
}
}
return $element;
}
/**
* Form validation handler for admin_menu_theme_settings().
*/
function admin_menu_theme_settings_validate(&$form, &$form_state) {
// Change the configured components to Boolean values.
foreach ($form_state['values']['admin_menu_components'] as &$enabled) {
$enabled = (bool) $enabled;
}
}
/**
* Implementation of hook_form_FORM_ID_alter().
*
* Extends Devel module with Administration menu developer settings.
*/
function _admin_menu_form_devel_admin_settings_alter(&$form, $form_state) {
// Shift system_settings_form buttons.
$weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0;
$form['buttons']['#weight'] = $weight + 1;
$form['admin_menu'] = [
'#type' => 'fieldset',
'#title' => t('Administration menu settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
];
$display_options = [
'mid',
'weight',
'pid',
];
$display_options = [
0 => t('None'),
'mlid' => t('Menu link ID'),
'weight' => t('Weight'),
'plid' => t('Parent link ID'),
];
$form['admin_menu']['admin_menu_display'] = [
'#type' => 'radios',
'#title' => t('Display additional data for each menu item'),
'#default_value' => variable_get('admin_menu_display', 0),
'#options' => $display_options,
'#description' => t('Display the selected items next to each menu item link.'),
];
$form['admin_menu']['admin_menu_show_all'] = [
'#type' => 'checkbox',
'#title' => t('Display all menu items'),
'#default_value' => variable_get('admin_menu_show_all', 0),
'#description' => t('If enabled, all menu items are displayed regardless of your site permissions. <em>Note: Do not enable on a production site.</em>'),
];
}
/**
* Flush all caches or a specific one.
*
* @param $name
* (optional) Name of cache to flush.
*/
function admin_menu_flush_cache($name = NULL) {
// @todo Update for built-in token handling; http://drupal.org/node/755584
$token = drupal_container()
->get('request')->query
->get('token');
if (!isset($token) || !drupal_valid_token($token, current_path())) {
throw new AccessDeniedHttpException();
}
if (isset($name)) {
$caches = module_invoke_all('admin_menu_cache_info');
if (!isset($caches[$name])) {
throw new NotFoundHttpException();
}
}
else {
$caches[$name] = [
'title' => t('Every'),
'callback' => 'drupal_flush_all_caches',
];
}
// Pass the cache to flush forward to the callback.
$function = $caches[$name]['callback'];
$function($name);
\Drupal::messenger()
->addStatus(t('!title cache cleared.', [
'!title' => $caches[$name]['title'],
]));
// The JavaScript injects a destination request parameter pointing to the
// originating page, so the user is redirected back to that page. Without
// destination parameter, the redirect ends on the front page.
drupal_goto();
}
/**
* Implements hook_admin_menu_cache_info().
*/
function admin_menu_admin_menu_cache_info() {
$caches['admin_menu'] = [
'title' => t('Administration menu'),
'callback' => '_admin_menu_flush_cache',
];
return $caches;
}
/**
* Implements hook_admin_menu_cache_info() on behalf of System module.
*/
function system_admin_menu_cache_info() {
$caches = [
'assets' => t('CSS and JavaScript'),
'bootstrap' => t('Bootstrap and configuration'),
'cache' => t('Page and else'),
'menu' => t('Menu'),
'theme' => t('Theme registry'),
];
foreach ($caches as $name => $cache) {
$caches[$name] = [
'title' => $cache,
'callback' => '_admin_menu_flush_cache',
];
}
return $caches;
}
/**
* Implements hook_admin_menu_cache_info() on behalf of Update module.
*/
function update_admin_menu_cache_info() {
$caches['update'] = [
'title' => t('Update data'),
'callback' => '_update_cache_clear',
];
return $caches;
}
/**
* Flush all caches or a specific one.
*
* @param $name
* (optional) Name of cache to flush.
*
* @see system_admin_menu_cache_info()
*/
function _admin_menu_flush_cache($name = NULL) {
switch ($name) {
case 'admin_menu':
admin_menu_cache_flush();
break;
case 'menu':
menu_router_rebuild();
break;
case 'bootstrap':
cache('bootstrap')
->deleteAll();
cache('config')
->deleteAll();
break;
case 'cache':
// @see drupal_flush_all_caches()
foreach (module_invoke_all('cache_flush') as $bin) {
cache($bin)
->deleteAll();
}
break;
case 'assets':
// Change query-strings on css/js files to enforce reload for all users.
_drupal_flush_css_js();
drupal_clear_css_cache();
drupal_clear_js_cache();
// Clear the page cache, since cached HTML pages might link to old CSS and
// JS aggregates.
cache('page')
->deleteAll();
break;
case 'theme':
system_rebuild_theme_data();
drupal_theme_rebuild();
break;
}
}
/**
* Preprocesses variables for theme_admin_menu_icon().
*/
function template_preprocess_admin_menu_icon(&$variables) {
// Image source might have been passed in as theme variable.
if (!isset($variables['src'])) {
if (theme_get_setting('toggle_favicon')) {
$variables['src'] = theme_get_setting('favicon');
}
else {
$variables['src'] = base_path() . 'misc/favicon.ico';
}
}
// Strip the protocol without delimiters for transient HTTP/HTTPS support.
// Since the menu is cached on the server-side and client-side, the cached
// version might contain a HTTP link, whereas the actual page is on HTTPS.
// Relative paths will work fine, but theme_get_setting() returns an
// absolute URI.
$variables['src'] = preg_replace('@^https?:@', '', $variables['src']);
$variables['src'] = check_plain($variables['src']);
$variables['alt'] = t('Home');
}
/**
* Renders an icon to display in the administration menu.
*
* @ingroup themeable
*/
function theme_admin_menu_icon($variables) {
return '<img class="admin-menu-icon" src="' . $variables['src'] . '" width="16" height="16" alt="' . $variables['alt'] . '" />';
}
Functions
Name | Description |
---|---|
admin_menu_admin_menu_cache_info | Implements hook_admin_menu_cache_info(). |
admin_menu_admin_settings_form | Form builder function for module settings. |
admin_menu_expand_args | Create the cartesian product of multiple varying sized argument arrays. |
admin_menu_flush_cache | Flush all caches or a specific one. |
admin_menu_links_account | Builds the account links. |
admin_menu_links_icon | Build icon menu links; mostly containing maintenance helpers. |
admin_menu_links_menu | Build the administration menu as renderable menu links. |
admin_menu_links_search | Build search widget. |
admin_menu_links_users | Builds user counter. |
admin_menu_merge_tree | Walk through the entire menu tree and merge in expanded dynamic menu links. |
admin_menu_settings_process_components | #process callback for component plugin form element in admin_menu_theme_settings(). |
admin_menu_theme_settings_validate | Form validation handler for admin_menu_theme_settings(). |
admin_menu_translate | Translate an expanded router item into a menu link suitable for rendering. |
admin_menu_tree | Build the full administration menu tree from static and expanded dynamic items. |
admin_menu_tree_dynamic | Load menu link trees for router paths containing dynamic arguments. |
system_admin_menu_cache_info | Implements hook_admin_menu_cache_info() on behalf of System module. |
template_preprocess_admin_menu_icon | Preprocesses variables for theme_admin_menu_icon(). |
theme_admin_menu_icon | Renders an icon to display in the administration menu. |
update_admin_menu_cache_info | Implements hook_admin_menu_cache_info() on behalf of Update module. |
_admin_menu_flush_cache | Flush all caches or a specific one. |
_admin_menu_form_devel_admin_settings_alter | Implementation of hook_form_FORM_ID_alter(). |