You are here

admin_toolbar_links_access_filter.module in Admin Toolbar 8.2

This module don't show menu links that you don't have access permission for.

File

admin_toolbar_links_access_filter/admin_toolbar_links_access_filter.module
View source
<?php

/**
 * @file
 * This module don't show menu links that you don't have access permission for.
 */
use Drupal\Core\Session\AccountInterface;
use Drupal\user\Entity\Role;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Drupal\Core\Routing\RouteMatchInterface;

/**
 * Implements hook_help().
 */
function admin_toolbar_links_access_filter_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help.
    case 'help.page.admin_toolbar_links_access_filter':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Admin Toolbar Links Access Filter module provides a workaround for the common problem that users with <em>Use the administration pages and help</em> permission see menu links they done not have access permission for.') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_preprocess_menu().
 *
 * Hides links from admin menu, if user doesn't have access rights.
 */
function admin_toolbar_links_access_filter_preprocess_menu(&$variables) {
  if (empty($variables['items'])) {

    // Additional empty check to prevent exotic situations, where the preprocess
    // function is entered even without items.
    // @see https://www.drupal.org/node/2833885
    return;
  }

  // Ensure that menu_name exists.
  if (!isset($variables['menu_name'])) {

    // In rare cases (for unknown reasons) menu_name may not be set.
    // As fallback, we can fetch it from the first menu item.
    $first_link = reset($variables['items']);

    /** @var Drupal\Core\Menu\MenuLinkDefault $original_link */

    // Fetch the menu_name from the original link.
    $original_link = $first_link['original_link'];
    $variables['menu_name'] = $original_link
      ->getMenuName();
  }
  if ($variables['menu_name'] == 'admin') {
    if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) {
      admin_toolbar_links_access_filter_filter_non_accessible_links($variables['items']);
    }
  }
}

/**
 * Hides links from admin menu, if user doesn't have access rights.
 */
function admin_toolbar_links_access_filter_filter_non_accessible_links(array &$items) {
  foreach ($items as $route => &$item) {
    $route_name = $route;
    $route_params = [];
    if (!empty($item['original_link'])) {

      /** @var \Drupal\Core\Menu\MenuLinkBase $original_link */
      $original_link = $item['original_link'];
      if ($original_link
        ->getUrlObject()
        ->isExternal()) {

        // Do not filter external URL at all.
        continue;
      }
      $route_name = $original_link
        ->getRouteName();
      $route_params = $original_link
        ->getRouteParameters();
    }

    // Check, if user has access rights to the route.
    if (!\Drupal::accessManager()
      ->checkNamedRoute($route_name, $route_params)) {
      unset($items[$route]);
    }
    else {
      if (!empty($items[$route]['below'])) {

        // Recursively call this function for the child items.
        admin_toolbar_links_access_filter_filter_non_accessible_links($items[$route]['below']);
      }
      if (empty($items[$route]['below']) && \Drupal::moduleHandler()
        ->moduleExists('admin_toolbar')) {

        // Every child item has been cleared out.
        // Now check, if the given route represents an overview page only,
        // without having functionality on its own. In this case, we can safely
        // unset this item, as there aren't any children left.
        // This assumption is only valid, when the admin_toolbar module is
        // installed because otherwise we won't have child items at all.
        if (admin_toolbar_links_access_filter_is_overview_page($route)) {
          unset($items[$route]);
        }
        else {

          // Let's remove the expanded flag.
          $items[$route]['is_expanded'] = FALSE;
        }
      }
    }
  }
}

/**
 * Checks if the given route name is an overview page.
 *
 * Checks if the given route name matches a pure (admin) overview page that can
 * be skipped, if there are no child items set. The typical example are routes
 * having the SystemController::systemAdminMenuBlockPage() function as their
 * controller callback set.
 *
 * @param string $route_name
 *   The route name to check.
 *
 * @return bool
 *   TRUE, if the given route name matches a pure admin overview page route,
 *   FALSE otherwise.
 */
function admin_toolbar_links_access_filter_is_overview_page($route_name) {

  // @var \Drupal\Core\Routing\RouteProviderInterface $route_provider.
  $route_provider = \Drupal::service('router.route_provider');
  $overview_page_controllers = [
    '\\Drupal\\system\\Controller\\AdminController::index',
    '\\Drupal\\system\\Controller\\SystemController::overview',
    '\\Drupal\\system\\Controller\\SystemController::systemAdminMenuBlockPage',
  ];
  try {
    $route = $route_provider
      ->getRouteByName($route_name);
    $controller = $route
      ->getDefault('_controller');
    return !empty($controller) && in_array($controller, $overview_page_controllers);
  } catch (RouteNotFoundException $ex) {
  }
  return FALSE;
}

/**
 * Checks, if the given user has admin rights.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *   The account to check.
 *
 * @return bool
 *   TRUE, if the given user account has at least one role with admin rights
 *   assigned, FALSE otherwise.
 */
function admin_toolbar_links_access_filter_user_has_admin_role(AccountInterface $account) {
  static $user_has_admin_role = [];
  $uid = $account
    ->id();
  if (!isset($user_has_admin_role[$uid])) {
    $roles = Role::loadMultiple($account
      ->getRoles());
    foreach ($roles as $role) {
      if ($role
        ->isAdmin()) {
        $user_has_admin_role[$uid] = TRUE;
        break;
      }
      $user_has_admin_role[$uid] = FALSE;
    }
  }
  return $user_has_admin_role[$uid];
}

Functions

Namesort descending Description
admin_toolbar_links_access_filter_filter_non_accessible_links Hides links from admin menu, if user doesn't have access rights.
admin_toolbar_links_access_filter_help Implements hook_help().
admin_toolbar_links_access_filter_is_overview_page Checks if the given route name is an overview page.
admin_toolbar_links_access_filter_preprocess_menu Implements hook_preprocess_menu().
admin_toolbar_links_access_filter_user_has_admin_role Checks, if the given user has admin rights.