diff --git a/core/modules/help/help.api.php b/core/modules/help/help.api.php
index 60c6867..c847a39 100644
--- a/core/modules/help/help.api.php
+++ b/core/modules/help/help.api.php
@@ -22,8 +22,8 @@
  * Help block (provided by the core Help module), if the block is displayed on
  * that page. The module overview help information is displayed by the Help
  * module. It can be accessed from the page at admin/help or from the Extend
- * Extend page. If a module implements hook_help() the help system expects
- * module overview help to be provided.
+ * page. If a module implements hook_help() the help system expects module
+ * overview help to be provided.
  *
  * For detailed usage examples of:
  * - Module overview help, see content_translation_help(). Module overview
@@ -56,5 +56,65 @@ function hook_help($route_name, \Drupal\Core\Routing\RouteMatchInterface $route_
 }
 
 /**
+ * Returns information about a section for the help page at admin/help.
+ *
+ * @return array
+ *   Array where each element represents a section to be listed on the main
+ *   help page at admin/help. The outer array key is a unique machine name
+ *   for the section; each section is represented by an array with the
+ *   following elements:
+ *   - header: (required) Translated text for the section header.
+ *   - description: (optional) Translated text for the description below the
+ *     header.
+ *   - permission: (optional) Permission needed to see this section, beyond
+ *     the generic 'access administration pages' needed to see the admin/help
+ *     page itself.
+ *   - topics_callback: (required) Callable in the format of
+ *     callback_help_section_list() that generates the topics list for this
+ *     section.
+ *   - cache: (optional) Information to be put into the #cache element of the
+ *     render array for this section.
+ */
+function hook_help_section_info() {
+  return [
+    'hook_help' => [
+      'header' => t('Module overviews'),
+      'description' => t('Module overviews are provided by modules. Overviews available for your installed modules:'),
+      'permission' => 'access administration pages',
+      'topics_callback' => 'help_list_hook_help_topics',
+    ],
+  ];
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
+
+/**
+ * Generate a list of topics for hook_help_section_info().
+ *
+ * The name of this function name or callable is returned as 'topics_callback'
+ * in a hook_help_section_info() return value.
+ *
+ * @return array
+ *   A sorted list of topic links or render arrays for topic links. The links
+ *   will be shown in the help section. If the returned array of links is
+ *   empty, the section will be shown with some generic empty text.
+ */
+function callback_help_section_list() {
+  // This sample callback lists the hook_help() module overview topics.
+  $topics = [];
+  $route_match = \Drupal::routeMatch();
+  $module_info = system_rebuild_module_data();
+
+  foreach (\Drupal::moduleHandler()->getImplementations('help') as $module) {
+    if (\Drupal::moduleHandler()->invoke($module, 'help', ["help.page.$module", $route_match])) {
+      $title = $module_info[$module]->info['name'];
+      $topics[$title] = Link::createFromRoute($title, 'help.page', ['name' => $module]);
+    }
+  }
+
+  // Sort topics by title, which is the array key above.
+  ksort($topics);
+  return $topics;
+}
diff --git a/core/modules/help/help.module b/core/modules/help/help.module
index 0aadd5b..0224b33 100644
--- a/core/modules/help/help.module
+++ b/core/modules/help/help.module
@@ -5,8 +5,9 @@
  * Manages displaying online help.
  */
 
-use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Block\BlockPluginInterface;
+use Drupal\Core\Link;
+use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Implements hook_help().
@@ -25,7 +26,7 @@ function help_help($route_name, RouteMatchInterface $route_match) {
         $output .= '<li>' . t('<strong>Start posting content</strong> Finally, you may <a href=":content">add new content</a> to your website.', array(':content' => \Drupal::url('node.add_page'))) . '</li>';
       }
       $output .= '</ol>';
-      $output .= '<p>' . t('For more information, refer to the subjects listed in the Help Topics section or to the <a href=":docs">online documentation</a> and <a href=":support">support</a> pages at <a href=":drupal">drupal.org</a>.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')) . '</p>';
+      $output .= '<p>' . t('For more information, refer to the help listed on this page or to the <a href=":docs">online documentation</a> and <a href=":support">support</a> pages at <a href=":drupal">drupal.org</a>.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')) . '</p>';
       return $output;
 
     case 'help.page.help':
@@ -44,6 +45,21 @@ function help_help($route_name, RouteMatchInterface $route_match) {
 }
 
 /**
+ * Implements hook_theme().
+ */
+function help_theme($existing, $type, $theme, $path) {
+ return [
+    'help_section' => [
+      'variables' => [
+        'title' => NULL,
+        'description' => NULL,
+        'links' => NULL,
+      ],
+    ],
+ ];
+}
+
+/**
  * Implements hook_preprocess_HOOK() for block templates.
  */
 function help_preprocess_block(&$variables) {
@@ -60,3 +76,46 @@ function help_block_view_help_block_alter(array &$build, BlockPluginInterface $b
   // the help block, so don't needlessly draw attention to it.
   unset($build['#contextual_links']);
 }
+
+/**
+ * Implements hook_help_section_info().
+ */
+function help_help_section_info() {
+  return [
+    'hook_help' => [
+      'header' => t('Module overviews'),
+      'description' => t('Module overviews are provided by modules. Overviews available for your installed modules:'),
+      'permission' => 'access administration pages',
+      'topics_callback' => 'help_list_hook_help_topics',
+      // There is no cache information provided in this implementation, because
+      // the topic list comes from a list of modules implementing hook_help().
+      // If a module adds or removes hook_help() or gets installed/uninstalled,
+      // hopefully the page cache would get cleared anyway.
+    ],
+  ];
+}
+
+/**
+ * Generates a list of hook_help() topics for the admin/help page.
+ *
+ * @return array
+ *   List of links to hook_help() topics for enabled modules that implement it.
+ *
+ * @see help_help_section_info().
+ */
+function help_list_hook_help_topics() {
+  $topics = [];
+  $route_match = \Drupal::routeMatch();
+  $module_info = system_rebuild_module_data();
+
+  foreach (\Drupal::moduleHandler()->getImplementations('help') as $module) {
+    if (\Drupal::moduleHandler()->invoke($module, 'help', ["help.page.$module", $route_match])) {
+      $title = $module_info[$module]->info['name'];
+      $topics[$title] = Link::createFromRoute($title, 'help.page', ['name' => $module]);
+    }
+  }
+
+  // Sort topics by title, which is the array key above.
+  ksort($topics);
+  return $topics;
+}
diff --git a/core/modules/help/src/Controller/HelpController.php b/core/modules/help/src/Controller/HelpController.php
index dcb50bd..fd5b1f8 100644
--- a/core/modules/help/src/Controller/HelpController.php
+++ b/core/modules/help/src/Controller/HelpController.php
@@ -45,57 +45,86 @@ public static function create(ContainerInterface $container) {
   }
 
   /**
-   * Prints a page listing a glossary of Drupal terminology.
+   * Prints a page listing various types of help.
    *
-   * @return string
-   *   An HTML string representing the contents of help page.
+   * The page has sections defined by hook_help_section_info().
+   *
+   * @return array
+   *   A render array for the help page.
    */
   public function helpMain() {
-    $output = array(
-      '#markup' => '<h2>' . $this->t('Help topics') . '</h2><p>' . $this->t('Help is available on the following items:') . '</p>',
-      'links' => $this->helpLinksAsList(),
-    );
+    $output = [
+      '#cache' => [
+        'contexts' => [
+          // Users will have different permissions for various sections of this
+          // page, so we must cache the page per user.
+          'user',
+        ],
+      ],
+    ];
+
+    $sections = $this->moduleHandler()->invokeAll('help_section_info');
+    foreach ($sections as $name => $info) {
+      // Skip this section if there is not a callback.
+      if (empty($info['topics_callback'])) {
+        continue;
+      }
+
+      // Check the provided permission.
+      if (!empty($info['permission']) && !$this->currentuser()->hasPermission($info['permission'])) {
+        continue;
+      }
+
+      // Generate the links, and include the section.
+      $this_output = [
+        '#theme' => 'help_section',
+        '#title' => $info['header'],
+        '#description' => isset($info['description']) ? $info['description'] : '',
+        '#links' => $this->t('There is currently nothing in this section'),
+      ];
+      $links = call_user_func($info['topics_callback']);
+      if (is_array($links) && count($links)) {
+        $this_output['#links'] = $this->fourColumnList($links);
+      }
+      if (!empty($info['cache'])) {
+        $this_output['#cache'] = $info['cache'];
+      }
+
+      $output[$name] = $this_output;
+    }
+
     return $output;
   }
 
   /**
-   * Provides a formatted list of available help topics.
+   * Makes a four-column list of items
+   *
+   * @param array $items
+   *   Array of string or render array items to separate into four columns.
    *
-   * @return string
-   *   A string containing the formatted list.
+   * @return array
+   *   Render array for a four-column UL list of the items.
    */
-  protected function helpLinksAsList() {
-    $modules = array();
-    foreach ($this->moduleHandler()->getImplementations('help') as $module) {
-      $modules[$module] = $this->moduleHandler->getName($module);
-    }
-    asort($modules);
-
-    // Output pretty four-column list.
-    $count = count($modules);
+  protected function fourColumnList($items) {
+    $output = [];
+    $count = count($items);
     $break = ceil($count / 4);
-    $column = array(
-      '#type' => 'container',
-      'links' => array('#theme' => 'item_list'),
-      '#attributes' => array('class' => array('layout-column', 'layout-column--quarter')),
-    );
-    $output = array(
-      '#prefix' => '<div class="clearfix">',
-      '#suffix' => '</div>',
-      0 => $column,
-    );
 
-    $i = 0;
-    $current_column = 0;
-    foreach ($modules as $module => $name) {
-      $output[$current_column]['links']['#items'][] = $this->l($name, new Url('help.page', array('name' => $module)));
-      if (($i + 1) % $break == 0 && ($i + 1) != $count) {
-        $current_column++;
-        $output[$current_column] = $column;
-      }
-      $i++;
+    for ($i = 0; $i < 4; $i++) {
+      $slice = array_slice($items, $break * $i, $break);
+      $output[$i] =  [
+        '#type' => 'container',
+        '#attributes' => ['class' => ['layout-column', 'layout-column--quarter']],
+        'links' => [
+          '#theme' => 'item_list',
+          '#items' => $slice,
+        ],
+      ];
     }
 
+    $output['#prefix'] = '<div class="clearfix">';
+    $output['#suffix'] = '</div>';
+
     return $output;
   }
 
diff --git a/core/modules/help/src/Tests/HelpTest.php b/core/modules/help/src/Tests/HelpTest.php
index 64ad4a7..98b3ad0 100644
--- a/core/modules/help/src/Tests/HelpTest.php
+++ b/core/modules/help/src/Tests/HelpTest.php
@@ -52,7 +52,7 @@ protected function setUp() {
   }
 
   /**
-   * Logs in users, creates dblog events, and tests dblog functionality.
+   * Logs in users, tests help pages.
    */
   public function testHelp() {
     // Login the root user to ensure as many admin links appear as possible on
@@ -67,10 +67,11 @@ public function testHelp() {
     // Verify that introductory help text exists, goes for 100% module coverage.
     $this->drupalLogin($this->adminUser);
     $this->drupalGet('admin/help');
-    $this->assertRaw(t('For more information, refer to the subjects listed in the Help Topics section or to the <a href=":docs">online documentation</a> and <a href=":support">support</a> pages at <a href=":drupal">drupal.org</a>.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')), 'Help intro text correctly appears.');
+    $this->assertRaw(t('For more information, refer to the help listed on this page or to the <a href=":docs">online documentation</a> and <a href=":support">support</a> pages at <a href=":drupal">drupal.org</a>.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')));
 
-    // Verify that help topics text appears.
-    $this->assertRaw('<h2>' . t('Help topics') . '</h2><p>' . t('Help is available on the following items:') . '</p>', 'Help topics text correctly appears.');
+    // Verify that hook_help() section title and description appear.
+    $this->assertRaw('<h2>' . t('Module overviews') . '</h2>');
+    $this->assertRaw('<p>' . t('Module overviews are provided by modules. Overviews available for your installed modules:'), '</p>');
 
     // Make sure links are properly added for modules implementing hook_help().
     foreach ($this->getModuleList() as $module => $name) {
@@ -81,10 +82,25 @@ public function testHelp() {
     // handled correctly.
     $this->clickLink(\Drupal::moduleHandler()->getName('help_test'));
     $this->assertRaw(t('No help is available for module %module.', array('%module' => \Drupal::moduleHandler()->getName('help_test'))));
+
+    // Verify that the order of topics is alphabetical by displayed module
+    // name, by checking the order of some modules, including some that would
+    // have a different order if it was done by machine name instead.
+    $this->drupalGet('admin/help');
+    $page_text = $this->getTextContent();
+    $start = strpos($page_text, 'Module overviews');
+    $pos = $start;
+    $list = ['Block', 'Color', 'Custom Block', 'History', 'Text Editor'];
+    foreach ($list as $name) {
+      $this->assertLink($name);
+      $new_pos = strpos($page_text, $name, $start);
+      $this->assertTrue($new_pos > $pos, 'Order of ' . $name . ' is correct on page');
+      $pos = $new_pos;
+    }
   }
 
   /**
-   * Verifies the logged in user has access to the various help nodes.
+   * Verifies the logged in user has access to the various help pages.
    *
    * @param int $response
    *   (optional) An HTTP response code. Defaults to 200.
@@ -100,7 +116,7 @@ protected function verifyHelp($response = 200) {
     }
 
     foreach ($this->getModuleList() as $module => $name) {
-      // View module help node.
+      // View module help page.
       $this->drupalGet('admin/help/' . $module);
       $this->assertResponse($response);
       if ($response == 200) {
diff --git a/core/modules/help/templates/help-section.html.twig b/core/modules/help/templates/help-section.html.twig
new file mode 100644
index 0000000..4134312
--- /dev/null
+++ b/core/modules/help/templates/help-section.html.twig
@@ -0,0 +1,17 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a section of the help page.
+ *
+ * Available variables:
+ * - title: The section title.
+ * - description: The description text for the section.
+ * - links: Links to display in the section. These should normally be formatted
+ *   as a four-column list.
+ *
+ * @ingroup themeable
+ */
+#}
+<h2>{{ title }}</h2>
+<p>{{ description }}</p>
+{{ links }}
diff --git a/core/modules/tour/src/Tests/TourHelpPageTest.php b/core/modules/tour/src/Tests/TourHelpPageTest.php
new file mode 100644
index 0000000..0b54145
--- /dev/null
+++ b/core/modules/tour/src/Tests/TourHelpPageTest.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\tour\Tests\TourHelpPageTest.
+ */
+
+namespace Drupal\tour\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Verifies help page display of tours.
+ *
+ * @group help
+ */
+class TourHelpPageTest extends WebTestBase {
+
+  /**
+   * Modules to enable, including some providing tours.
+   *
+   * @var array
+   */
+  public static $modules = ['help', 'tour', 'locale', 'language'];
+
+  /**
+   * User that can access tours and help.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $tourUser;
+
+  /**
+   * A user who can access help but not tours.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $noTourUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create users.
+    $this->tourUser = $this->drupalCreateUser(['access administration pages', 'access tour']);
+    $this->noTourUser = $this->drupalCreateUser(['access administration pages']);
+  }
+
+  /**
+   * Logs in users, tests help pages.
+   */
+  public function testHelp() {
+    $this->drupalLogin($this->tourUser);
+    $this->verifyHelp();
+
+    $this->drupalLogin($this->noTourUser);
+    $this->verifyHelp(FALSE);
+  }
+
+  /**
+   * Verifies the logged in user has access to the help properly.
+   *
+   * @param bool $tours_ok
+   *   (optional) TRUE (default) if the user should see tours, FALSE if not.
+   */
+  protected function verifyHelp($tours_ok = TRUE) {
+    $this->drupalGet('admin/help');
+
+    // All users should be able to see the module section.
+    $this->assertText('Module overviews are provided by modules');
+    foreach ($this->getModuleList() as $name) {
+      $this->assertLink($name);
+    }
+
+    // Some users should be able to see the tour section.
+    if ($tours_ok) {
+      $this->assertText('Tours guide you through workflows');
+    }
+    else {
+      $this->assertNoText('Tours guide you through workflows');
+    }
+
+    $titles = $this->getTourList();
+
+    // Test the titles that should be links.
+    foreach ($titles[0] as $title) {
+      if ($tours_ok) {
+        $this->assertLink($title);
+      }
+      else {
+        $this->assertNoLink($title);
+      }
+    }
+
+    // Test the titles that should not be links.
+    foreach ($titles[1] as $title) {
+      if ($tours_ok) {
+        $this->assertText($title);
+        $this->assertNoLink($title);
+      }
+      else {
+        $this->assertNoText($title);
+      }
+    }
+  }
+
+  /**
+   * Gets a list of modules to test for hook_help() pages.
+   *
+   * @return array
+   *   A list of module names to test.
+   */
+  protected function getModuleList() {
+    return [ 'Help', 'Tour' ];
+  }
+
+  /**
+   * Gets a list of tours to test.
+   *
+   * @return array
+   *   A list of tour titles to test. The first array element is a list of tours
+   *   with links, and the second is a list of tours without links.
+   */
+  protected function getTourList() {
+    return [ ['Adding languages', 'Translation'], ['Editing languages']];
+  }
+
+}
diff --git a/core/modules/tour/tour.module b/core/modules/tour/tour.module
index ed53f25..53c83b8 100644
--- a/core/modules/tour/tour.module
+++ b/core/modules/tour/tour.module
@@ -5,6 +5,7 @@
  * Main functions of the module.
  */
 
+use Drupal\Core\Link;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -111,3 +112,68 @@ function tour_tour_insert($entity) {
 function tour_tour_update($entity) {
   \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions();
 }
+
+/**
+ * Implements hook_help_section_info().
+ */
+function tour_help_section_info() {
+  // The list of topics depends on the list cache tag for the tour entity.
+  $tags = \Drupal::entityTypeManager()->getDefinition('tour')->getListCacheTags();
+  return [
+    'tour' => [
+      'header' => t('Tours'),
+      'description' => t('Tours guide you through workflows or explain concepts on various user interface pages. The tours with links in this list are on user interface landing pages; the tours without links will show on individual pages (such as when editing a View using the Views UI module). Available tours:'),
+      'permission' => 'access tour',
+      'topics_callback' => 'tour_list_tours',
+      'cache' => ['tags' => $tags],
+    ],
+  ];
+}
+
+/**
+ * Generates a list of tours for the admin/help page.
+ *
+ * @return array
+ *   List of all available tours, with titles made into links where possible.
+ *
+ * @see tour_help_section_info().
+ */
+function tour_list_tours() {
+  /** @var \Drupal\Core\Entity\EntityStorageInterface $tour_storage */
+  $tour_storage = \Drupal::entityTypeManager()->getStorage('tour');
+  /** @var \Drupal\tour\TourInterface[] $entities */
+  $entities = $tour_storage->loadMultiple();
+  // Sort in the manner defined by Tour (by tour title).
+  uasort($entities, ['Drupal\tour\Entity\Tour', 'sort']);
+
+  // Make a link to each tour, using the first of its routes that can
+  // be linked to. Some routes require parameters, and cannot be made into
+  // links, so use a try/catch loop to try to make a link.
+  $topics = [];
+  foreach ($entities as $entity) {
+    $title = $entity->label();
+    $id = $entity->id();
+    $routes = $entity->getRoutes();
+    $made_link = FALSE;
+    foreach ($routes as $route) {
+      try {
+        $params = isset($route['route_params']) ? $route['route_params'] : [];
+        // Generate the link HTML directly, using toString(), to catch missing
+        // parameter exceptions now instead of at render time.
+        $topics[$id] = Link::createFromRoute($title, $route['route_name'], $params)->toString();
+        $made_link = TRUE;
+        break;
+      }
+      catch (\Exception $e) {
+        // If there was an exception, just try the next route.
+      }
+    }
+    if (!$made_link) {
+      // None of the routes worked to make a link, so at least display the
+      // tour title.
+      $topics[$id] = $title;
+    }
+  }
+
+  return $topics;
+}
diff --git a/core/themes/stable/templates/admin/help-section.html.twig b/core/themes/stable/templates/admin/help-section.html.twig
new file mode 100644
index 0000000..4134312
--- /dev/null
+++ b/core/themes/stable/templates/admin/help-section.html.twig
@@ -0,0 +1,17 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a section of the help page.
+ *
+ * Available variables:
+ * - title: The section title.
+ * - description: The description text for the section.
+ * - links: Links to display in the section. These should normally be formatted
+ *   as a four-column list.
+ *
+ * @ingroup themeable
+ */
+#}
+<h2>{{ title }}</h2>
+<p>{{ description }}</p>
+{{ links }}
