From b9a978d2028212b430df6bf165f662ca973bedbc Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Wed, 26 Feb 2014 10:53:29 +0000
Subject: [PATCH] Issue #2177041 by dawehner, Berdir, jibran: Remove all
 implementations of hook_menu.

---
 core/core.services.yml                        |  5 ++
 core/includes/menu.inc                        | 10 ++-
 .../EventSubscriber/PathRootsSubscriber.php   | 81 +++++++++++++++++
 core/lib/Drupal/Core/Path/AliasWhitelist.php  |  4 +-
 core/modules/action/action.module             | 12 ---
 core/modules/aggregator/aggregator.module     | 42 ---------
 core/modules/ban/ban.module                   | 17 ----
 core/modules/block/block.module               | 23 -----
 .../block/custom_block/custom_block.module    | 32 ++-----
 .../LocalAction/CustomBlockAddLocalAction.php |  4 +
 .../custom_block_test.module                  | 14 ---
 core/modules/book/book.module                 | 22 -----
 core/modules/comment/comment.module           | 30 +------
 core/modules/config/config.module             | 13 ---
 .../tests/config_test/config_test.module      | 26 ------
 .../config_translation.module                 | 14 ---
 core/modules/contact/contact.module           | 28 ------
 .../content_translation.module                |  4 -
 core/modules/dblog/dblog.module               | 36 --------
 core/modules/editor/editor.module             | 10 +--
 core/modules/entity/entity.module             | 51 -----------
 .../modules/field_test/field_test.module      | 13 ---
 core/modules/field_ui/field_ui.module         | 14 ---
 core/modules/filter/filter.module             | 30 -------
 core/modules/forum/forum.module               | 34 -------
 core/modules/help/help.module                 | 19 ----
 core/modules/image/image.module               | 35 --------
 core/modules/language/language.module         | 23 -----
 .../LanguageUILanguageNegotiationTest.php     |  2 +-
 core/modules/locale/locale.module             | 21 -----
 core/modules/menu/menu.module                 | 30 -------
 .../menu_link/MenuLinkStorageController.php   |  3 +-
 core/modules/node/node.module                 | 47 ----------
 core/modules/path/path.module                 | 22 -----
 core/modules/picture/picture.module           | 24 -----
 core/modules/search/search.module             | 24 -----
 core/modules/shortcut/shortcut.module         | 28 ------
 core/modules/simpletest/simpletest.module     | 18 ----
 core/modules/statistics/statistics.module     | 13 ---
 .../system/Controller/AdminController.php     |  2 +-
 .../Drupal/system/Tests/Menu/LinksTest.php    | 21 +++++
 .../system/Tests/Path/PathUnitTestBase.php    |  2 +-
 .../modules/module_test/module_test.module    | 19 ----
 .../modules/plugin_test/plugin_test.module    | 11 ---
 .../test_page_test/test_page_test.module      | 12 ---
 .../modules/theme_test/theme_test.module      | 21 -----
 core/modules/taxonomy/taxonomy.module         | 27 ------
 .../toolbar/Tests/ToolbarAdminMenuTest.php    |  1 +
 .../tour/tests/tour_test/tour_test.module     | 15 ++--
 core/modules/update/update.module             | 16 ----
 core/modules/user/user.module                 | 82 -----------------
 .../views/display/DisplayPluginBase.php       | 15 ----
 core/modules/views/views.module               | 45 ----------
 core/modules/views_ui/views_ui.module         | 23 -----
 .../PathRootsSubscriberTest.php               | 89 +++++++++++++++++++
 55 files changed, 233 insertions(+), 1046 deletions(-)
 create mode 100644 core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php
 create mode 100644 core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php

diff --git a/core/core.services.yml b/core/core.services.yml
index 0c038ec30632..afb710bb05e9 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -302,6 +302,11 @@ services:
     calls:
       - [setContext, ['@router.request_context']]
       - [add, ['@router.dynamic']]
+  router.path_roots_subscriber:
+    class: Drupal\Core\EventSubscriber\PathRootsSubscriber
+    arguments: ['@state']
+    tags:
+      - { name: event_subscriber }
   entity.query:
     class: Drupal\Core\Entity\Query\QueryFactory
     arguments: ['@entity.manager']
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 668d689ce7bd..495fb4722b88 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -13,6 +13,7 @@
 use Drupal\Core\Routing\RequestHelper;
 use Drupal\Core\Template\Attribute;
 use Drupal\menu_link\Entity\MenuLink;
+use Drupal\menu_link\MenuLinkInterface;
 use Drupal\menu_link\MenuLinkStorageController;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -561,7 +562,10 @@ function _menu_check_access(&$item, $map) {
  *   (link title attribute) matches the description, it is translated as well.
  */
 function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
-  $title_callback = $item['title_callback'];
+  // Allow default menu links to be translated.
+  // @todo Figure out a proper way to support translations of menu links, see
+  //   https://drupal.org/node/2193777.
+  $title_callback = $item instanceof MenuLinkInterface && !$item->customized ? 't' :  $item['title_callback'];
   $item['localized_options'] = $item['options'];
   // All 'class' attributes are assumed to be an array during rendering, but
   // links stored in the database may use an old string value.
@@ -580,6 +584,8 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
   if (!$link_translate || !isset($item['link_title']) || ($item['title'] == $item['link_title'])) {
     // t() is a special case. Since it is used very close to all the time,
     // we handle it directly instead of using indirect, slower methods.
+    // @todo Recheck this line once https://drupal.org/node/2084421 is in.
+    $item['title'] = isset($item['link_title']) ? $item['link_title'] : $item['title'];
     if ($title_callback == 't') {
       if (empty($item['title_arguments'])) {
         $item['title'] = t($item['title']);
@@ -2395,7 +2401,7 @@ function menu_link_rebuild_defaults() {
   if ($all_links) {
     $query = \Drupal::entityQuery('menu_link')
       ->condition('machine_name', array_keys($all_links), 'NOT IN')
-      ->condition('machine_name', NULL, '<>')
+      ->exists('machine_name')
       ->condition('external', 0)
       ->condition('updated', 0)
       ->condition('customized', 0)
diff --git a/core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php
new file mode 100644
index 000000000000..f2701bc681f5
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\PathRootsSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\KeyValueStore\StateInterface;
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Core\Routing\RoutingEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Provides all available first bits of all route paths.
+ */
+class PathRootsSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Stores the path roots available in the router.
+   *
+   * A path root is the first virtual directory of a path, like 'admin', 'node'
+   * or 'user'.
+   *
+   * @var array
+   */
+  protected $pathRoots;
+
+  /**
+   * The state key value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Constructs a new PathRootsSubscriber instance.
+   *
+   * @param \Drupal\Core\KeyValueStore\StateInterface $state
+   *   The state key value store.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * Collects all path roots.
+   *
+   * @param \Drupal\Core\Routing\RouteBuildEvent $event
+   *   The route build event.
+   */
+  public function onRouteAlter(RouteBuildEvent $event) {
+    $collection = $event->getRouteCollection();
+    foreach ($collection->all() as $route) {
+      $bits = explode('/', ltrim($route->getPath(), '/'));
+      $this->pathRoots[$bits[0]] = $bits[0];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onRouteFinished() {
+    $this->state->set('router.path_roots', array_keys($this->pathRoots));
+    unset($this->pathRoots);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events = array();
+    // Try to set a low priority to ensure that all routes are already added.
+    $events[RoutingEvents::ALTER][] = array('onRouteAlter', -1024);
+    $events[RoutingEvents::FINISHED][] = array('onRouteFinished');
+    return $events;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Path/AliasWhitelist.php b/core/lib/Drupal/Core/Path/AliasWhitelist.php
index e748315b7962..b990c3bfb806 100644
--- a/core/lib/Drupal/Core/Path/AliasWhitelist.php
+++ b/core/lib/Drupal/Core/Path/AliasWhitelist.php
@@ -60,7 +60,7 @@ protected function lazyLoadCache() {
 
     // On a cold start $this->storage will be empty and the whitelist will
     // need to be rebuilt from scratch. The whitelist is initialized from the
-    // list of all valid path roots stored in the 'menu_path_roots' state,
+    // list of all valid path roots stored in the 'router.path_roots' state,
     // with values initialized to NULL. During the request, each path requested
     // that matches one of these keys will be looked up and the array value set
     // to either TRUE or FALSE. This ensures that paths which do not exist in
@@ -75,7 +75,7 @@ protected function lazyLoadCache() {
    * Loads menu path roots to prepopulate cache.
    */
   protected function loadMenuPathRoots() {
-    if ($roots = $this->state->get('menu_path_roots')) {
+    if ($roots = $this->state->get('router.path_roots')) {
       foreach ($roots as $root) {
         $this->storage[$root] = NULL;
         $this->persist($root);
diff --git a/core/modules/action/action.module b/core/modules/action/action.module
index 07e7b48fbda2..ee2f6282c2c7 100644
--- a/core/modules/action/action.module
+++ b/core/modules/action/action.module
@@ -44,18 +44,6 @@ function action_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function action_menu() {
-  $items['admin/config/system/actions'] = array(
-    'title' => 'Actions',
-    'description' => 'Manage the actions defined for your site.',
-    'route_name' => 'action.admin',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index d6d701ebe835..fce70cb1a188 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -87,48 +87,6 @@ function aggregator_theme() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function aggregator_menu() {
-  $items['admin/config/services/aggregator'] = array(
-    'title' => 'Feed aggregator',
-    'description' => "Configure which content your site aggregates from other sites, and how often it polls them.",
-    'route_name' => 'aggregator.admin_overview',
-    'weight' => 10,
-  );
-  $items['admin/config/services/aggregator/remove/%aggregator_feed'] = array(
-    'title' => 'Remove items',
-    'route_name' => 'aggregator.feed_items_delete',
-  );
-  $items['admin/config/services/aggregator/update/%aggregator_feed'] = array(
-    'title' => 'Update items',
-    'route_name' => 'aggregator.feed_refresh',
-  );
-  $items['aggregator'] = array(
-    'title' => 'Feed aggregator',
-    'weight' => 5,
-    'route_name' => 'aggregator.page_last',
-  );
-  $items['aggregator/sources'] = array(
-    'title' => 'Sources',
-    'route_name' => 'aggregator.sources',
-  );
-  $items['aggregator/sources/%aggregator_feed'] = array(
-    'route_name' => 'aggregator.feed_view',
-  );
-  $items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array(
-    'title' => 'Edit feed',
-    'route_name' => 'aggregator.feed_edit',
-  );
-  $items['admin/config/services/aggregator/delete/feed/%aggregator_feed'] = array(
-    'title' => 'Delete feed',
-    'route_name' => 'aggregator.feed_delete',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/ban/ban.module b/core/modules/ban/ban.module
index 7d09e7c64ffe..e45ed1349242 100644
--- a/core/modules/ban/ban.module
+++ b/core/modules/ban/ban.module
@@ -37,23 +37,6 @@ function ban_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function ban_menu() {
-  $items['admin/config/people/ban'] = array(
-    'title' => 'IP address bans',
-    'description' => 'Manage banned IP addresses.',
-    'route_name' => 'ban.admin_page',
-    'weight' => 10,
-  );
-  $items['admin/config/people/ban/delete/%'] = array(
-    'title' => 'Delete IP address',
-    'route_name' => 'ban.delete',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 2ee5f480b31c..e97852c7466b 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -92,29 +92,6 @@ function block_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- *
- * @todo Clarify the documentation for the per-plugin block admin links.
- */
-function block_menu() {
-  $items['admin/structure/block'] = array(
-    'title' => 'Block layout',
-    'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
-    'route_name' => 'block.admin_display',
-  );
-  $items['admin/structure/block/manage/%block'] = array(
-    'title' => 'Configure block',
-    'route_name' => 'block.admin_edit',
-  );
-  $items['admin/structure/block/add/%/%'] = array(
-    'title' => 'Place block',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-    'route_name' => 'block.admin_add',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index 2365ded6df93..633e9fb8959b 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -37,33 +37,6 @@ function custom_block_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function custom_block_menu() {
-  $items['admin/structure/block/custom-blocks'] = array(
-    'title' => 'Custom block library',
-    'description' => 'Manage custom blocks.',
-    'route_name' => 'custom_block.list',
-    'type' => MENU_NORMAL_ITEM,
-  );
-
-  $items['admin/structure/block/custom-blocks/manage/%custom_block_type'] = array(
-    'title' => 'Edit custom block type',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(5),
-    'route_name' => 'custom_block.type_edit',
-  );
-
-  $items['block/add'] = array(
-    'title' => 'Add custom block',
-    'description' => 'Add custom block',
-    'route_name' => 'custom_block.add_page',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
@@ -73,6 +46,11 @@ function custom_block_menu_link_defaults() {
     'description' => 'Add custom block',
     'route_name' => 'custom_block.add_page',
   );
+  $items['custom_block.list'] = array(
+    'link_title' => 'Custom block library',
+    'parent' => 'block.admin.structure',
+    'description' => 'Manage custom blocks.',
+  );
 
   return $links;
 }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
index 1f4d86ff23cd..af9b359ef015 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
@@ -29,6 +29,10 @@ public function getOptions(Request $request) {
     if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'custom_block.list') {
       $options['query']['destination'] = 'admin/structure/block/custom-blocks';
     }
+    // Adds a destination on custom block listing.
+    if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'custom_block.list') {
+      $options['query']['destination'] = 'admin/structure/block/custom-blocks';
+    }
     return $options;
   }
 
diff --git a/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module b/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module
index 71860980b68b..8c530539e06c 100644
--- a/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module
+++ b/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module
@@ -66,17 +66,3 @@ function custom_block_test_custom_block_insert(CustomBlock $custom_block) {
     throw new Exception('Test exception for rollback.');
   }
 }
-
-/**
- * Implements hook_menu().
- */
-function custom_block_test_menu() {
-  $items = array();
-  // Add a block-view callback.
-  $items['custom-block/%custom_block'] = array(
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(1),
-    'route_name' => 'custom_block_test.custom_block_view',
-  );
-  return $items;
-}
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index acfa539f5d81..b7a8cc776d2f 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -162,28 +162,6 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function book_menu() {
-  $items['admin/structure/book'] = array(
-    'title' => 'Books',
-    'description' => "Manage your site's book outlines.",
-    'route_name' => 'book.admin',
-  );
-  $items['book'] = array(
-    'title' => 'Books',
-    'route_name' => 'book.render',
-    'type' => MENU_SUGGESTED_ITEM,
-  );
-  $items['node/%node/outline/remove'] = array(
-    'title' => 'Remove from outline',
-    'route_name' => 'book.remove',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 0cbe24c63ee8..bfdbb2b1b906 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -177,28 +177,6 @@ function comment_theme() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function comment_menu() {
-  $items['admin/structure/comments'] = array(
-    'title' => 'Comment forms',
-    'description' => 'Manage fields and displays settings for comment forms.',
-    'route_name' => 'comment.bundle_list',
-  );
-  $items['admin/structure/comments/manage/%'] = array(
-    'title' => 'Comment form',
-    'route_name' => 'comment.bundle',
-  );
-  $items['admin/content/comment'] = array(
-    'title' => 'Comments',
-    'description' => 'List and edit site comments and the comment approval queue.',
-    'route_name' => 'comment.admin',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
@@ -220,12 +198,12 @@ function comment_menu_link_defaults() {
 }
 
 /**
- * Implements hook_menu_alter().
+ * Implements hook_menu_link_defaults_alter()
  */
-function comment_menu_alter(&$items) {
-  if (isset($items['admin/content'])) {
+function comment_menu_links_defaults_alter(&$links) {
+  if (isset($links['node.admin.content'])) {
     // Add comments to the description for admin/content if any.
-    $items['admin/content']['description'] = 'Administer content and comments.';
+    $links['node.admin.content']['description'] = 'Administer content and comments.';
   }
 }
 
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index 3cb71e6bbdac..776a9fc43054 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -57,19 +57,6 @@ function config_file_download($uri) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function config_menu() {
-  $items['admin/config/development/configuration'] = array(
-    'title' => 'Configuration management',
-    'description' => 'Import, export, or synchronize your site configuration.',
-    'route_name' => 'config.sync',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module
index 51e406f513e7..77826e0198bd 100644
--- a/core/modules/config/tests/config_test/config_test.module
+++ b/core/modules/config/tests/config_test/config_test.module
@@ -10,32 +10,6 @@
 
 require_once dirname(__FILE__) . '/config_test.hooks.inc';
 
-/**
- * Implements hook_menu().
- */
-function config_test_menu() {
-  $items['admin/structure/config_test'] = array(
-    'title' => 'Test configuration',
-    'route_name' => 'config_test.list_page',
-  );
-  $items['admin/structure/config_test/manage/%config_test'] = array(
-    'route_name' => 'config_test.entity',
-  );
-  $items['admin/structure/config_test/manage/%config_test/delete'] = array(
-    'title' => 'Delete',
-    'route_name' => 'config_test.entity_delete',
-  );
-  $items['admin/structure/config_test/manage/%config_test/enable'] = array(
-    'title' => 'Enable',
-    'route_name' => 'config_test.entity_enable',
-  );
-  $items['admin/structure/config_test/manage/%config_test/disable'] = array(
-    'title' => 'Disable',
-    'route_name' => 'config_test.entity_disable',
-  );
-  return $items;
-}
-
 /**
  * Loads a ConfigTest object.
  *
diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module
index 077e0cd7952b..22046898adf3 100644
--- a/core/modules/config_translation/config_translation.module
+++ b/core/modules/config_translation/config_translation.module
@@ -31,20 +31,6 @@ function config_translation_help($path) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function config_translation_menu() {
-  $items = array();
-  $items['admin/config/regional/config-translation'] = array(
-    'title' => 'Configuration translation',
-    'description' => 'Translate the configuration.',
-    'route_name' => 'config_translation.mapper_list',
-    'weight' => 30,
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index bd9454f1f475..0a366cb17127 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -51,34 +51,6 @@ function contact_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function contact_menu() {
-  $items['admin/structure/contact'] = array(
-    'title' => 'Contact form categories',
-    'description' => 'Create a system contact form and set up categories for the form to use.',
-    'route_name' => 'contact.category_list',
-  );
-  $items['admin/structure/contact/manage/%contact_category'] = array(
-    'title' => 'Edit contact category',
-    'route_name' => 'contact.category_edit',
-  );
-
-  $items['contact'] = array(
-    'title' => 'Contact',
-    'route_name' => 'contact.site_page',
-    'menu_name' => 'footer',
-    'type' => MENU_SUGGESTED_ITEM,
-  );
-  $items['contact/%contact_category'] = array(
-    'title' => 'Contact category form',
-    'route_name' => 'contact.site_page_category',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 19e4ea6d43a6..d425866e86d4 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -244,10 +244,6 @@ function content_translation_menu() {
  *   https://drupal.org/node/1987882 and https://drupal.org/node/2047633.
  */
 function content_translation_menu_alter(array &$items) {
-  // Clarify where translation settings are located.
-  $items['admin/config/regional/content-language']['title'] = 'Content language and translation';
-  $items['admin/config/regional/content-language']['description'] = 'Configure language and translation support for content.';
-
   // Check that the declared menu base paths are actually valid.
   foreach (\Drupal::entityManager()->getDefinitions() as $entity_type_id => $entity_type) {
     if (content_translation_enabled($entity_type_id)) {
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index 4060d63981b4..cd8e2c082c9e 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -36,42 +36,6 @@ function dblog_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function dblog_menu() {
-  $items['admin/reports/dblog'] = array(
-    'title' => 'Recent log messages',
-    'description' => 'View events that have recently been logged.',
-    'route_name' => 'dblog.overview',
-    'weight' => -1,
-  );
-  $items['admin/reports/page-not-found'] = array(
-    'title' => "Top 'page not found' errors",
-    'description' => "View 'page not found' errors (404s).",
-    'route_name' => 'dblog.page_not_found',
-  );
-  $items['admin/reports/access-denied'] = array(
-    'title' => "Top 'access denied' errors",
-    'description' => "View 'access denied' errors (403s).",
-    'route_name' => 'dblog.access_denied',
-  );
-  $items['admin/reports/event/%'] = array(
-    'title' => 'Details',
-    'route_name' => 'dblog.event',
-  );
-
-  if (\Drupal::moduleHandler()->moduleExists('search')) {
-    $items['admin/reports/search'] = array(
-      'title' => 'Top search phrases',
-      'description' => 'View most popular search phrases.',
-      'route_name' => 'dblog.search',
-    );
-  }
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index f1a9840128dd..9266911262f3 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -39,19 +39,11 @@ function editor_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu_alter().
+ * Implements hook_menu_link_defaults_alter().
  *
  * Rewrites the menu entries for filter module that relate to the configuration
  * of text editors.
  */
-function editor_menu_alter(&$items) {
-  $items['admin/config/content/formats']['title'] = 'Text formats and editors';
-  $items['admin/config/content/formats']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
-}
-
-/**
- * Implements hook_menu_link_defaults_alter().
- */
 function editor_menu_link_defaults_alter(array &$links) {
   $links['filter.admin.formats']['link_title'] = 'Text formats and editors';
   $links['filter.admin.formats']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index 4816d0b57dd3..f921fcfc8326 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -44,57 +44,6 @@ function entity_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function entity_menu() {
-  $items = array();
-
-  $items['admin/structure/display-modes'] = array(
-    'title' => 'Display modes',
-    'description' => 'Configure what displays are available for your content and forms.',
-    'route_name' => 'entity.display_mode',
-  );
-
-  // View modes.
-  $items['admin/structure/display-modes/view'] = array(
-    'title' => 'View modes',
-    'description' => 'Manage custom view modes.',
-    'route_name' => 'entity.view_mode_list',
-  );
-  $items['admin/structure/display-modes/view/add'] = array(
-    'title' => 'Add view mode',
-    'route_name' => 'entity.view_mode_add',
-    'type' => MENU_SIBLING_LOCAL_TASK,
-  );
-  $items['admin/structure/display-modes/view/add/%'] = array(
-    'route_name' => 'entity.view_mode_add_type',
-  );
-  $items['admin/structure/display-modes/view/manage/%/delete'] = array(
-    'route_name' => 'entity.view_mode_delete',
-  );
-
-  // Form modes.
-  $items['admin/structure/display-modes/form'] = array(
-    'title' => 'Form modes',
-    'description' => 'Manage custom form modes.',
-    'route_name' => 'entity.form_mode_list',
-  );
-  $items['admin/structure/display-modes/form/add'] = array(
-    'title' => 'Add form mode',
-    'route_name' => 'entity.form_mode_add',
-    'type' => MENU_SIBLING_LOCAL_TASK,
-  );
-  $items['admin/structure/display-modes/form/add/%'] = array(
-    'route_name' => 'entity.form_mode_add_type',
-  );
-  $items['admin/structure/display-modes/form/manage/%/delete'] = array(
-    'route_name' => 'entity.form_mode_delete',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index c386131ec734..5ece0401cb5f 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -36,19 +36,6 @@ function field_test_permission() {
   return $perms;
 }
 
-/**
- * Implements hook_menu().
- */
-function field_test_menu() {
-  $items = array();
-  $items['test-entity/nested/%entity_test/%entity_test'] = array(
-    'title' => 'Nested entity form',
-    'route_name' => 'field_test.entity_nested_form',
-  );
-
-  return $items;
-}
-
 /**
  * Store and retrieve keyed data for later verification by unit tests.
  *
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 08c1cf6eebdb..4279bb3dbfae 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -52,20 +52,6 @@ function field_ui_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function field_ui_menu() {
-  $items['admin/reports/fields'] = array(
-    'title' => 'Field list',
-    'description' => 'Overview of fields on all entity types.',
-    'route_name' => 'field_ui.list',
-    'type' => MENU_NORMAL_ITEM,
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index ca500305a25a..2b09ea7ae86f 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -94,36 +94,6 @@ function filter_element_info() {
   return $type;
 }
 
-/**
- * Implements hook_menu().
- */
-function filter_menu() {
-  $items['filter/tips'] = array(
-    'title' => 'Compose tips',
-    'type' => MENU_SUGGESTED_ITEM,
-    'route_name' => 'filter.tips_all',
-  );
-  $items['filter/tips/%'] = array(
-    'title' => 'Compose tips',
-    'route_name' => 'filter.tips',
-  );
-  $items['admin/config/content/formats'] = array(
-    'title' => 'Text formats',
-    'description' => 'Configure how content input by users is filtered, including allowed HTML tags. Also allows enabling of module-provided filters.',
-    'route_name' => 'filter.admin_overview',
-  );
-  $items['admin/config/content/formats/manage/%'] = array(
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(5),
-    'route_name' => 'filter.format_edit',
-  );
-  $items['admin/config/content/formats/manage/%/disable'] = array(
-    'title' => 'Disable text format',
-    'route_name' => 'filter.admin_disable',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 284378293622..b1bb1ea4f483 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -94,40 +94,6 @@ function forum_theme() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function forum_menu() {
-  $items['forum'] = array(
-    'title' => 'Forums',
-    'route_name' => 'forum.index',
-  );
-  $items['forum/%forum'] = array(
-    'title' => 'Forums',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(1),
-    'route_name' => 'forum.page',
-  );
-  $items['admin/structure/forum'] = array(
-    'title' => 'Forums',
-    'description' => 'Control forum hierarchy settings.',
-    'route_name' => 'forum.overview',
-  );
-  $items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
-    'title' => 'Edit container',
-    'route_name' => 'forum.edit_container',
-  );
-  $items['admin/structure/forum/edit/forum/%taxonomy_term'] = array(
-    'title' => 'Edit forum',
-    'route_name' => 'forum.edit_forum',
-  );
-  $items['admin/structure/forum/delete/forum/%taxonomy_term'] = array(
-    'title' => 'Delete forum',
-    'route_name' => 'forum.delete',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/help/help.module b/core/modules/help/help.module
index 6d074056c340..89e0f3175dfa 100644
--- a/core/modules/help/help.module
+++ b/core/modules/help/help.module
@@ -5,25 +5,6 @@
  * Manages displaying online help.
  */
 
-/**
- * Implements hook_menu().
- */
-function help_menu() {
-  $items['admin/help'] = array(
-    'title' => 'Help',
-    'description' => 'Reference for usage, configuration, and modules.',
-    'route_name' => 'help.main',
-    'weight' => 9,
-  );
-
-  $items['admin/help/%'] = array(
-    'route_name' => 'help.page',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 4d9c5f88d635..c1420c1d10b0 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -83,41 +83,6 @@ function image_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function image_menu() {
-  $items = array();
-
-  $items['admin/config/media/image-styles'] = array(
-    'title' => 'Image styles',
-    'description' => 'Configure styles that can be used for resizing or adjusting images on display.',
-    'route_name' => 'image.style_list',
-  );
-  $items['admin/config/media/image-styles/manage/%image_style'] = array(
-    'title' => 'Edit style',
-    'description' => 'Configure an image style.',
-    'route_name' => 'image.style_edit',
-  );
-  $items['admin/config/media/image-styles/manage/%/effects/%'] = array(
-    'title' => 'Edit image effect',
-    'description' => 'Edit an existing effect within a style.',
-    'route_name' => 'image.effect_edit_form',
-  );
-  $items['admin/config/media/image-styles/manage/%image_style/effects/%/delete'] = array(
-    'title' => 'Delete image effect',
-    'description' => 'Delete an existing effect from a style.',
-    'route_name' => 'image.effect_delete',
-  );
-  $items['admin/config/media/image-styles/manage/%/add/%'] = array(
-    'title' => 'Add image effect',
-    'description' => 'Add a new effect to a style.',
-    'route_name' => 'image.effect_add_form',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 83356b7c7f1d..9d2305825bc0 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -68,29 +68,6 @@ function language_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function language_menu() {
-  // Base language management and configuration.
-  $items['admin/config/regional/language'] = array(
-    'title' => 'Languages',
-    'description' => 'Configure languages for content and the user interface.',
-    'route_name' => 'language.admin_overview',
-    'weight' => 0,
-  );
-
-  // Content language settings.
-  $items['admin/config/regional/content-language'] = array(
-    'title' => 'Content language',
-    'description' => 'Configure language support for content.',
-    'route_name' => 'language.content_settings_page',
-    'weight' => 10,
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index 89376c8a98a2..89832f3cf69d 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -111,7 +111,7 @@ function testUILanguageNegotiation() {
 
     // We will look for this string in the admin/config screen to see if the
     // corresponding translated string is shown.
-    $default_string = 'Configure languages for content and the user interface';
+    $default_string = 'Hide descriptions';
 
     // First visit this page to make sure our target string is searchable.
     $this->drupalGet('admin/config');
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index a4727d4703b1..105f44ec0cbd 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -167,27 +167,6 @@ function locale_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function locale_menu() {
-  // Translation functionality.
-  $items['admin/config/regional/translate'] = array(
-    'title' => 'User interface translation',
-    'description' => 'Translate the built-in user interface.',
-    'route_name' => 'locale.translate_page',
-    'weight' => 15,
-  );
-
-  $items['admin/reports/translations'] = array(
-    'title' => 'Available translation updates',
-    'route_name' => 'locale.translate_status',
-    'description' => 'Get a status report about available interface translations for your installed modules and themes.',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 32593535544c..15e02ab24ed2 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -62,36 +62,6 @@ function menu_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function menu_menu() {
-  $items['admin/structure/menu'] = array(
-    'title' => 'Menus',
-    'description' => 'Add new menus to your site, edit existing menus, and rename and reorganize menu links.',
-    'route_name' => 'menu.overview_page',
-  );
-  $items['admin/structure/menu/manage/%menu'] = array(
-    'title' => 'Edit menu',
-    'route_name' => 'menu.menu_edit',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(4),
-  );
-  $items['admin/structure/menu/item/%menu_link/edit'] = array(
-    'title' => 'Edit menu link',
-    'route_name' => 'menu.link_edit',
-  );
-  $items['admin/structure/menu/item/%menu_link/reset'] = array(
-    'title' => 'Reset menu link',
-    'route_name' => 'menu.link_reset',
-  );
-  $items['admin/structure/menu/item/%menu_link/delete'] = array(
-    'title' => 'Delete menu link',
-    'route_name' => 'menu.link_delete',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
index d244a716460d..10d998e5c27f 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
@@ -218,8 +218,7 @@ public function loadModuleAdminTasks() {
       ->condition('base.link_path', 'admin/%', 'LIKE')
       ->condition('base.hidden', 0, '>=')
       ->condition('base.module', 'system')
-      ->condition('m.number_parts', 1, '>')
-      ->condition('m.page_callback', 'system_admin_menu_block_page', '<>');
+      ->condition('base.route_name', 'system.admin', '<>');
     $ids = $query->execute()->fetchCol(1);
 
     return $this->loadMultiple($ids);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 5bef612316f1..a38d788af06a 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -936,53 +936,6 @@ function _node_revision_access(NodeInterface $node, $op = 'view', $account = NUL
   return \Drupal::service('access_check.node.revision')->checkAccess($node, $account, $op, $langcode);
 }
 
-/**
- * Implements hook_menu().
- */
-function node_menu() {
-  $items['admin/content'] = array(
-    'title' => 'Content',
-    'description' => 'Find and manage content.',
-    'route_name' => 'node.content_overview',
-    'weight' => -10,
-  );
-
-  $items['admin/structure/types'] = array(
-    'title' => 'Content types',
-    'description' => 'Manage content types, including default status, front page promotion, comment settings, etc.',
-    'route_name' => 'node.overview_types',
-  );
-  $items['node/add'] = array(
-    'title' => 'Add content',
-    'route_name' => 'node.add_page',
-  );
-  $items['node/add/%node_type'] = array(
-    'description callback' => 'node_type_get_description',
-    'description arguments' => array(2),
-    'route_name' => 'node.add',
-  );
-  $items['node/%node'] = array(
-    'title callback' => 'node_page_title',
-    'title arguments' => array(1),
-    // The controller also sets the #title in case the routes' title is
-    // overridden by a menu link.
-    'route_name' => 'node.view',
-  );
-  $items['node/%node/revisions/%node_revision/view'] = array(
-    'title' => 'Revisions',
-    'route_name' => 'node.revision_show',
-  );
-  $items['node/%node/revisions/%node_revision/revert'] = array(
-    'title' => 'Revert to earlier revision',
-    'route_name' => 'node.revision_revert_confirm',
-  );
-  $items['node/%node/revisions/%node_revision/delete'] = array(
-    'title' => 'Delete earlier revision',
-    'route_name' => 'node.revision_delete_confirm',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 3c9f61158e7e..10816eecbe79 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -53,28 +53,6 @@ function path_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function path_menu() {
-  $items['admin/config/search/path'] = array(
-    'title' => 'URL aliases',
-    'description' => "Change your site's URL paths by aliasing them.",
-    'route_name' => 'path.admin_overview',
-    'weight' => -5,
-  );
-  $items['admin/config/search/path/edit/%path'] = array(
-    'title' => 'Edit alias',
-    'route_name' => 'path.admin_edit',
-  );
-  $items['admin/config/search/path/delete/%path'] = array(
-    'title' => 'Delete alias',
-    'route_name' => 'path.delete',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/picture/picture.module b/core/modules/picture/picture.module
index ae676c9e67dd..f7aecacce0b4 100644
--- a/core/modules/picture/picture.module
+++ b/core/modules/picture/picture.module
@@ -45,30 +45,6 @@ function picture_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function picture_menu() {
-  $items = array();
-
-  $items['admin/config/media/picturemapping'] = array(
-    'title' => 'Picture Mappings',
-    'description' => 'Manage picture mappings',
-    'weight' => 10,
-    'route_name' => 'picture.mapping_page',
-  );
-  $items['admin/config/media/picturemapping/%picture_mapping'] = array(
-    'title' => 'Edit picture mapping',
-    'route_name' => 'picture.mapping_page_edit',
-  );
-  $items['admin/config/media/picturemapping/%picture_mapping/duplicate'] = array(
-    'title' => 'Duplicate picture mapping',
-    'route_name' => 'picture.mapping_page_duplicate',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 600dc83360ee..e60d020e88c8 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -138,30 +138,6 @@ function search_preprocess_block(&$variables) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function search_menu() {
-  $items['search'] = array(
-    'title' => 'Search',
-    'type' => MENU_SUGGESTED_ITEM,
-    'route_name' => 'search.view',
-  );
-  $items['admin/config/search/settings'] = array(
-    'title' => 'Search settings',
-    'description' => 'Configure relevance settings for search and other indexing options.',
-    'route_name' => 'search.settings',
-    'weight' => -10,
-  );
-  $items['admin/config/search/settings/reindex'] = array(
-    'title' => 'Clear index',
-    'route_name' => 'search.reindex_confirm',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 56317453e3a7..a97b447e7878 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -61,33 +61,6 @@ function shortcut_permission() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function shortcut_menu() {
-  $items['admin/config/user-interface/shortcut'] = array(
-    'title' => 'Shortcuts',
-    'description' => 'Add and modify shortcut sets.',
-    'route_name' => 'shortcut.set_admin',
-  );
-  $items['admin/config/user-interface/shortcut/manage/%shortcut_set'] = array(
-    'title' => 'Edit shortcuts',
-    'route_name' => 'shortcut.set_customize',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(5),
-  );
-  $items['admin/config/user-interface/shortcut/link/%shortcut'] = array(
-    'title' => 'Edit shortcut',
-    'route_name' => 'shortcut.link_edit',
-  );
-  $items['admin/config/user-interface/shortcut/link/%shortcut/delete'] = array(
-    'title' => 'Delete shortcut',
-    'route_name' => 'shortcut.link_delete',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
@@ -389,7 +362,6 @@ function shortcut_preprocess_page(&$variables) {
   // shortcuts and if the page's actual content is being shown (for example,
   // we do not want to display it on "access denied" or "page not found"
   // pages).
-
   // Load the router item corresponding to the current page.
   $request = \Drupal::request();
   $item = array();
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 99ca6014795e..f7e375aaf018 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -29,24 +29,6 @@ function simpletest_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function simpletest_menu() {
-  $items['admin/config/development/testing'] = array(
-    'title' => 'Testing',
-    'description' => 'Run tests against Drupal core and your modules. These tests help assure that your site code is working as designed.',
-    'route_name' => 'simpletest.test_form',
-    'weight' => -5,
-  );
-  $items['admin/config/development/testing/results/%'] = array(
-    'title' => 'Test result',
-    'description' => 'View result of tests.',
-    'route_name' => 'simpletest.result_form',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index 5f3a4af0a614..8dc09d20c304 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -78,19 +78,6 @@ function statistics_node_links_alter(array &$node_links, NodeInterface $entity,
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function statistics_menu() {
-  $items['admin/config/system/statistics'] = array(
-    'title' => 'Statistics',
-    'description' => 'Control details about what and how your site logs content statistics.',
-    'route_name' => 'statistics.settings',
-    'weight' => -15,
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/system/lib/Drupal/system/Controller/AdminController.php b/core/modules/system/lib/Drupal/system/Controller/AdminController.php
index 6a7bbc0247bb..f1e231f18c60 100644
--- a/core/modules/system/lib/Drupal/system/Controller/AdminController.php
+++ b/core/modules/system/lib/Drupal/system/Controller/AdminController.php
@@ -36,7 +36,7 @@ public function index() {
         // 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";
+        $permission_key = "user.admin.people.permissions.$module";
         if (isset($admin_tasks[$permission_key])) {
           $permission_task = $admin_tasks[$permission_key];
           unset($admin_tasks[$permission_key]);
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php
index cc8c4e08bb54..52fa21b2be99 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Menu;
 
+use Drupal\locale\TranslationString;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -260,4 +261,24 @@ public function testRouterIntegration() {
     $this->assertEqual($menu_link->route_parameters, array('value' => 'test'));
   }
 
+  /**
+   * Tests uninstall a module providing default links.
+   */
+  public function testModuleUninstalledMenuLinks() {
+    \Drupal::moduleHandler()->install(array('menu_test'));
+    \Drupal::service('router.builder')->rebuild();
+    menu_link_rebuild_defaults();
+    $result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
+    $menu_links = \Drupal::entityManager()->getStorageController('menu_link')->loadMultiple($result);
+    $this->assertEqual(count($menu_links), 1);
+    $menu_link = reset($menu_links);
+    $this->assertEqual($menu_link->machine_name, 'menu_test');
+
+    // Uninstall the module and ensure the menu link got removed.
+    \Drupal::moduleHandler()->uninstall(array('menu_test'));
+    $result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
+    $menu_links = \Drupal::entityManager()->getStorageController('menu_link')->loadMultiple($result);
+    $this->assertEqual(count($menu_links), 0);
+  }
+
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
index faaa1580edda..64a92ea6ff2f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
@@ -20,7 +20,7 @@ public function setUp() {
     $this->fixtures = new UrlAliasFixtures();
     // The alias whitelist expects that the menu path roots are set by a
     // menu router rebuild.
-    \Drupal::state()->set('menu_path_roots', array('user', 'admin'));
+    \Drupal::state()->set('router.path_roots', array('user', 'admin'));
   }
 
   public function tearDown() {
diff --git a/core/modules/system/tests/modules/module_test/module_test.module b/core/modules/system/tests/modules/module_test/module_test.module
index e0ae6f480e03..b1372c0f8d2b 100644
--- a/core/modules/system/tests/modules/module_test/module_test.module
+++ b/core/modules/system/tests/modules/module_test/module_test.module
@@ -68,25 +68,6 @@ function module_test_hook_info() {
   return $hooks;
 }
 
-/**
- * Implements hook_menu().
- */
-function module_test_menu() {
-  $items['module-test/hook-dynamic-loading-invoke'] = array(
-    'title' => 'Test hook dynamic loading (invoke)',
-    'route_name' => 'module_test.dynamic_invoke',
-  );
-  $items['module-test/hook-dynamic-loading-invoke-all'] = array(
-    'title' => 'Test hook dynamic loading (invoke_all)',
-    'route_name' => 'module_test.dynamic_invoke_all',
-  );
-  $items['module-test/class-loading'] = array(
-    'title' => 'Test loading a class from another module',
-    'route_name' => 'module_test.class_loading',
-  );
-  return $items;
-}
-
 /**
  * Page callback for 'hook dynamic loading' test.
  *
diff --git a/core/modules/system/tests/modules/plugin_test/plugin_test.module b/core/modules/system/tests/modules/plugin_test/plugin_test.module
index 6a33894d5a00..147e05261611 100644
--- a/core/modules/system/tests/modules/plugin_test/plugin_test.module
+++ b/core/modules/system/tests/modules/plugin_test/plugin_test.module
@@ -14,14 +14,3 @@ function plugin_test_plugin_test_alter(&$definitions) {
   }
   $definitions['user_login']['altered_single'] = TRUE;
 }
-
-/**
- * Implements hook_menu().
- */
-function plugin_test_menu() {
-  $items = array();
-  $items['plugin_definition_test'] = array(
-    'route_name' => 'plugin_test.definition',
-  );
-  return $items;
-}
diff --git a/core/modules/system/tests/modules/test_page_test/test_page_test.module b/core/modules/system/tests/modules/test_page_test/test_page_test.module
index 7933a85a3aff..93c10c5f4186 100644
--- a/core/modules/system/tests/modules/test_page_test/test_page_test.module
+++ b/core/modules/system/tests/modules/test_page_test/test_page_test.module
@@ -1,17 +1,5 @@
 <?php
 
-/**
- * Implements hook_menu().
- */
-function test_page_test_menu() {
-  $items['test-page'] = array(
-    'title' => 'Test front page',
-    'route_name' => 'test_page_test.test_page',
-  );
-
-  return $items;
-}
-
 /**
  * Page callback: Returns a test page and sets the title.
  *
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module
index 4e1fc13ad92a..667ad83759e7 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -63,27 +63,6 @@ function theme_test_system_theme_info() {
   return $themes;
 }
 
-/**
- * Implements hook_menu().
- */
-function theme_test_menu() {
-  $items['theme-test/suggestion'] = array(
-    'route_name' => 'theme_test.suggestion',
-    'theme callback' => '_theme_custom_theme',
-    'type' => MENU_CALLBACK,
-  );
-  $items['theme-test/alter'] = array(
-    'theme callback' => '_theme_custom_theme',
-    'route_name' => 'theme_test.alter',
-    'type' => MENU_CALLBACK,
-  );
-  $items['theme-test/function-template-overridden'] = array(
-    'theme callback' => '_theme_custom_theme',
-    'route_name' => 'theme_test.function_template_override',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_preprocess_HOOK() for HTML document templates.
  */
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 3124f634f79b..e51eef81b226 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -232,33 +232,6 @@ function taxonomy_theme() {
   );
 }
 
-/**
- * Implements hook_menu().
- */
-function taxonomy_menu() {
-  $items['admin/structure/taxonomy'] = array(
-    'title' => 'Taxonomy',
-    'description' => 'Manage tagging, categorization, and classification of your content.',
-    'route_name' => 'taxonomy.vocabulary_list',
-  );
-
-  $items['taxonomy/term/%taxonomy_term'] = array(
-    'title' => 'Taxonomy term',
-    'title callback' => 'taxonomy_term_title',
-    'title arguments' => array(2),
-    'route_name' => 'taxonomy.term_page',
-  );
-  $items['taxonomy/term/%taxonomy_term/feed'] = array(
-    'title' => 'Taxonomy term',
-    'title callback' => 'taxonomy_term_title',
-    'title arguments' => array(2),
-    'route_name' => 'taxonomy.term_feed',
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php
index 3ca1039b7eb8..082a6a7e2fac 100644
--- a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php
+++ b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php
@@ -411,6 +411,7 @@ function testLocaleTranslationSubtreesHashCacheClear() {
       'translation' => 'untranslated',
     );
     $this->drupalPostForm('admin/config/regional/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available'));
     $this->assertText($name, 'Search found the string as untranslated.');
 
     // Assume this is the only result.
diff --git a/core/modules/tour/tests/tour_test/tour_test.module b/core/modules/tour/tests/tour_test/tour_test.module
index 0df3e57d5d1b..3b1ca24ad835 100644
--- a/core/modules/tour/tests/tour_test/tour_test.module
+++ b/core/modules/tour/tests/tour_test/tour_test.module
@@ -18,18 +18,19 @@ function tour_test_admin_paths() {
 }
 
 /**
- * Implements hook_menu().
+ * Implements hook_menu_link_defaults().
  */
-function tour_test_menu() {
-  $items['tour-test-1'] = array(
+function hook_menu_link_defaults() {
+  $links['tour_test.1'] = array(
     'route_name' => 'tour_test.1',
-    'title' => 'Tour test 1'
+    'link_title' => 'Tour test 1'
   );
-  $items['tour-test-2/subpath'] = array(
+  $links['tour_test.2'] = array(
     'route_name' => 'tour_test.2',
-    'title' => 'Tour test 2'
+    'link_title' => 'Tour test 2'
   );
-  return $items;
+
+  return $links;
 }
 
 /**
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 027c2854e3aa..c2dea88a9b91 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -144,22 +144,6 @@ function update_page_build() {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function update_menu() {
-  $items = array();
-
-  $items['admin/reports/updates'] = array(
-    'title' => 'Available updates',
-    'description' => 'Get a status report about available updates for your installed modules and themes.',
-    'route_name' => 'update.status',
-    'weight' => -50,
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 4ff18d3836ee..5ea8cfa48016 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -715,88 +715,6 @@ function user_register_access() {
   return user_is_anonymous() && (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY);
 }
 
-/**
- * Implements hook_menu().
- */
-function user_menu() {
-  // Registration and login pages.
-  $items['user'] = array(
-    'title' => 'User account',
-    'title callback' => 'user_menu_title',
-    'weight' => -10,
-    'route_name' => 'user.page',
-    'menu_name' => 'account',
-  );
-
-  // Since menu_get_ancestors() does not support multiple placeholders in a row,
-  // this MENU_CALLBACK cannot be removed yet.
-  $items['user/reset/%/%/%'] = array(
-    'title' => 'Reset password',
-    'route_name' => 'user.reset',
-    'type' => MENU_CALLBACK,
-  );
-
-  $items['user/logout'] = array(
-    'title' => 'Log out',
-    'route_name' => 'user.logout',
-    'weight' => 10,
-    'menu_name' => 'account',
-  );
-
-  // User listing pages.
-  $items['admin/people'] = array(
-    'title' => 'People',
-    'description' => 'Manage user accounts, roles, and permissions.',
-    'route_name' => 'user.admin_account',
-    'position' => 'left',
-    'weight' => -4,
-  );
-
-  // Permissions and role forms.
-  $items['admin/people/permissions'] = array(
-    'title' => 'Permissions',
-    'description' => 'Determine access to features by selecting permissions for roles.',
-    'route_name' => 'user.admin_permissions',
-    'type' => MENU_SIBLING_LOCAL_TASK,
-  );
-
-  $items['admin/people/roles/manage/%user_role'] = array(
-    'title' => 'Edit role',
-    'route_name' => 'user.role_edit',
-  );
-
-  // Administration pages.
-  $items['admin/config/people'] = array(
-    'title' => 'People',
-    'description' => 'Configure user accounts.',
-    'position' => 'left',
-    'weight' => -20,
-    'route_name' => 'user.admin_index',
-  );
-
-  $items['admin/config/people/accounts'] = array(
-    'title' => 'Account settings',
-    'description' => 'Configure default behavior of users, including registration requirements, e-mails, and fields.',
-    'weight' => -10,
-    'route_name' => 'user.account_settings',
-  );
-
-  $items['user/%user'] = array(
-    'title' => 'My account',
-    'title callback' => 'user_page_title',
-    'title arguments' => array(1),
-    'route_name' => 'user.view',
-  );
-  $items['user/%user/cancel'] = array(
-    'route_name' => 'user.cancel',
-  );
-  $items['user/%user/cancel/confirm/%/%'] = array(
-    'title' => 'Confirm account cancellation',
-    'route_name' => 'user.cancel_confirm',
-  );
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index 72d27253eacf..47626aa3e5ce 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -2385,21 +2385,6 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
     return array();
   }
 
-  /**
-   * If this display creates a page with a menu item, implement it here.
-   *
-   * @param array $callbacks
-   *   An array of already existing menu items provided by drupal.
-   *
-   * @return array
-   *   The menu router items registers for this display.
-   *
-   * @see hook_menu()
-   */
-  public function executeHookMenu($callbacks) {
-    return array();
-  }
-
   /**
    * Render this display.
    */
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index f6fbd2ebf509..1d1f1b53a906 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -270,51 +270,6 @@ function views_permission() {
   );
 }
 
-/**
- * Implement hook_menu_alter().
- */
-function views_menu_alter(&$callbacks) {
-  $our_paths = array();
-  $views = views_get_applicable_views('uses_hook_menu');
-  foreach ($views as $data) {
-    list($view, $display_id) = $data;
-    $result = $view->executeHookMenu($display_id, $callbacks);
-    if (is_array($result)) {
-      // The menu system doesn't support having two otherwise
-      // identical paths with different placeholders.  So we
-      // want to remove the existing items from the menu whose
-      // paths would conflict with ours.
-
-      // First, we must find any existing menu items that may
-      // conflict.  We use a regular expression because we don't
-      // know what placeholders they might use.  Note that we
-      // first construct the regex itself by replacing %views_arg
-      // in the display path, then we use this constructed regex
-      // (which will be something like '#^(foo/%[^/]*/bar)$#') to
-      // search through the existing paths.
-      $regex = '#^(' . preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) . ')$#';
-      $matches = preg_grep($regex, array_keys($callbacks));
-
-      // Remove any conflicting items that were found.
-      foreach ($matches as $path) {
-        // Don't remove the paths we just added!
-        if (!isset($our_paths[$path])) {
-          unset($callbacks[$path]);
-        }
-      }
-      foreach ($result as $path => $item) {
-        if (!isset($callbacks[$path])) {
-          // Add a new item, possibly replacing (and thus effectively
-          // overriding) one that we removed above.
-          $callbacks[$path] = $item;
-        }
-        $our_paths[$path] = TRUE;
-      }
-    }
-    $view->destroy();
-  }
-}
-
 /**
  * Implements hook_menu_link_defaults_alter().
  */
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 246f4ba27bd3..1d4a59826626 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -37,29 +37,6 @@ function views_ui_help($path, $arg) {
   }
 }
 
-/**
- * Implements hook_menu().
- */
-function views_ui_menu() {
-  $items = array();
-
-  // Top-level Views module pages (not tied to a particular View).
-  $items['admin/structure/views'] = array(
-    'title' => 'Views',
-    'description' => 'Manage customized lists of content.',
-    'route_name' => 'views_ui.list',
-  );
-
-  // A page in the Reports section to show usage of plugins in all views.
-  $items['admin/reports/views-plugins'] = array(
-    'title' => 'Views plugins',
-    'description' => 'Overview of plugins used in all views.',
-    'route_name' => 'views_ui.reports_plugins',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php
new file mode 100644
index 000000000000..87e722b5b643
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\EventSubscriber\PathRootsSubscriberTest.
+ */
+
+namespace Drupal\Tests\Core\EventSubscriber;
+
+use Drupal\Core\EventSubscriber\PathRootsSubscriber;
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Tests Drupal\Core\EventSubscriber\PathRootsSubscriber.
+ *
+ * @group Drupal
+ * @group Routing
+ *
+ * @coversDefaultClass \Drupal\Core\EventSubscriber\PathRootsSubscriber
+ */
+class PathRootsSubscriberTest extends UnitTestCase {
+
+  /**
+   * The mocked state.
+   *
+   * @var \Drupal\Core\KeyValueStore\StateInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $state;
+
+  /**
+   * The tested path root subscriber.
+   *
+   * @var \Drupal\Core\EventSubscriber\PathRootsSubscriber
+   */
+  protected $pathRootsSubscriber;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Drupal\Core\EventSubscriber\PathRootsSubscriber',
+      'description' => '',
+      'group' => 'Routing'
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->state = $this->getMock('Drupal\Core\KeyValueStore\StateInterface');
+    $this->pathRootsSubscriber = new PathRootsSubscriber($this->state);
+  }
+
+  /**
+   * Tests altering and finished event.
+   *
+   * @covers ::onRouteAlter()
+   * @covers ::onRouteFinished()
+   */
+  public function testSubscribing() {
+    $route_collection = new RouteCollection();
+    $route_collection->add('test_route1', new Route('/test/bar'));
+    $route_collection->add('test_route2', new Route('/test/baz'));
+    $route_collection->add('test_route3', new Route('/test2/bar/baz'));
+
+    $event = new RouteBuildEvent($route_collection, 'provider');
+    $this->pathRootsSubscriber->onRouteAlter($event);
+
+    $route_collection = new RouteCollection();
+    $route_collection->add('test_route4', new Route('/test1/bar'));
+    $route_collection->add('test_route5', new Route('/test2/baz'));
+    $route_collection->add('test_route6', new Route('/test2/bar/baz'));
+
+    $event = new RouteBuildEvent($route_collection, 'provider');
+    $this->pathRootsSubscriber->onRouteAlter($event);
+
+    $this->state->expects($this->once())
+      ->method('set')
+      ->with('router.path_roots', array('test', 'test2', 'test1'));
+
+    $this->pathRootsSubscriber->onRouteFinished();
+  }
+
+}
-- 
GitLab