diff --git a/core/includes/common.inc b/core/includes/common.inc
index 8eec0ac..30d7948 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3409,7 +3409,7 @@ function drupal_pre_render_link($element) {
* Pre-render callback: Collects child links into a single array.
*
* This function can be added as a pre_render callback for a renderable array,
- * usually one which will be themed by theme_links(). It iterates through all
+ * usually one which will be themed by links.html.twig. It iterates through all
* unrendered children of the element, collects any #links properties it finds,
* merges them into the parent element's #links array, and prevents those
* children from being rendered separately.
@@ -3430,21 +3430,21 @@ function drupal_pre_render_link($element) {
* '#theme' => 'links__node__comment',
* '#links' => array(
* // An array of links associated with node comments, suitable for
- * // passing in to theme_links().
+ * // passing in to links.html.twig.
* ),
* ),
* 'statistics' => array(
* '#theme' => 'links__node__statistics',
* '#links' => array(
* // An array of links associated with node statistics, suitable for
- * // passing in to theme_links().
+ * // passing in to links.html.twig.
* ),
* ),
* 'translation' => array(
* '#theme' => 'links__node__translation',
* '#links' => array(
* // An array of links associated with node translation, suitable for
- * // passing in to theme_links().
+ * // passing in to links.html.twig.
* ),
* ),
* );
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 5d4a943..32a67a5 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -1400,7 +1400,7 @@ function form_pre_render_actions_dropbutton(array $element) {
}
// Add this button to the corresponding dropbutton.
// @todo Change #type 'dropbutton' to be based on theme_item_list()
- // instead of theme_links() to avoid this preemptive rendering.
+ // instead of links.html.twig to avoid this preemptive rendering.
$button = drupal_render($element[$key]);
$dropbuttons[$dropbutton]['#links'][$key] = array(
'title' => $button,
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index c959a72..778e10e 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -1889,7 +1889,7 @@ function menu_navigation_links($menu_name, $level = 0) {
if ($item['link']['href'] == $router_item['tab_root_href'] && $item['link']['href'] != current_path()) {
$l['attributes']['class'][] = 'active';
}
- // Keyed with the unique mlid to generate classes in theme_links().
+ // Keyed with the unique mlid to generate classes in links.html.twig.
$links['menu-' . $item['link']['mlid'] . $class] = $l;
}
}
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index bfd1aaf..b6f7a61 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1168,9 +1168,11 @@ function template_preprocess_status_messages(&$variables) {
}
/**
- * Returns HTML for a set of links.
+ * Prepares variables for links templates.
*
- * @param $variables
+ * Default template: links.html.twig.
+ *
+ * @param array $variables
* An associative array containing:
* - links: An associative array of links to be themed. The key for each link
* is used as its CSS class. Each link should be itself an array, with the
@@ -1236,11 +1238,9 @@ function template_preprocess_status_messages(&$variables) {
* @see \Drupal\Core\Utility\LinkGenerator::generate()
* @see system_page_build()
*/
-function theme_links($variables) {
+function template_preprocess_links(&$variables) {
$links = $variables['links'];
- $attributes = $variables['attributes'];
- $heading = $variables['heading'];
- $output = '';
+ $heading = &$variables['heading'];
if (!empty($links)) {
// Prepend the heading to the list, if any.
@@ -1258,15 +1258,14 @@ function theme_links($variables) {
if (isset($heading['class'])) {
$heading['attributes']['class'] = $heading['class'];
}
-
- $output .= '<' . $heading['level'] . new Attribute($heading['attributes']) . '>';
- $output .= String::checkPlain($heading['text']);
- $output .= '' . $heading['level'] . '>';
+ // Convert the attributes array into an attributes object.
+ $heading['attributes'] = new Attribute($heading['attributes']);
+ $heading['text'] = String::checkPlain($heading['text']);
}
- $output .= '
';
-
+ $variables['links'] = array();
foreach ($links as $key => $link) {
+ $item = array();
$link += array(
'href' => NULL,
'route_name' => NULL,
@@ -1320,29 +1319,23 @@ function theme_links($variables) {
$li_attributes['data-drupal-link-system-path'] = \Drupal::service('path.alias_manager.cached')->getSystemPath($path);
}
- $item = drupal_render($link_element);
+ $item['link'] = $link_element;
}
+
// Handle title-only text items.
- else {
- // Merge in default array properties into $link.
- $link += array(
- 'html' => FALSE,
- );
- $item = ($link['html'] ? $link['title'] : String::checkPlain($link['title']));
- if (isset($link['attributes'])) {
- $item = '' . $item . '';
- }
+ $text = (!empty($link['html']) ? $link['title'] : String::checkPlain($link['title']));
+ $item['text'] = $text;
+ if (isset($link['attributes'])) {
+ $item['text_attributes'] = new Attribute($link['attributes']);
}
- $output .= '- ';
- $output .= $item;
- $output .= '
';
- }
+ // Handle list item attributes.
+ $item['attributes'] = new Attribute($li_attributes);
- $output .= '
';
+ // Add the item to the list of links.
+ $variables['links'][] = $item;
+ }
}
-
- return $output;
}
/**
@@ -2601,6 +2594,7 @@ function drupal_common_theme() {
),
'links' => array(
'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array(), 'set_active_class' => FALSE),
+ 'template' => 'links',
),
'dropbutton_wrapper' => array(
'variables' => array('children' => NULL),
diff --git a/core/lib/Drupal/Core/Menu/ContextualLinkManagerInterface.php b/core/lib/Drupal/Core/Menu/ContextualLinkManagerInterface.php
index 801990b..1b43dec 100644
--- a/core/lib/Drupal/Core/Menu/ContextualLinkManagerInterface.php
+++ b/core/lib/Drupal/Core/Menu/ContextualLinkManagerInterface.php
@@ -24,7 +24,7 @@
public function getContextualLinkPluginsByGroup($group_name);
/**
- * Gets the contextual links prepared as expected by theme_links().
+ * Gets the contextual links prepared as expected by links.html.twig.
*
* @param string $group_name
* The group name.
diff --git a/core/modules/contextual/contextual.module b/core/modules/contextual/contextual.module
index 3fd2cb9..cb0cdee 100644
--- a/core/modules/contextual/contextual.module
+++ b/core/modules/contextual/contextual.module
@@ -271,7 +271,7 @@ function contextual_pre_render_links($element) {
$items += $contextual_links_manager->getContextualLinksArrayByGroup($group, $args['route_parameters'], $args['metadata']);
}
- // Transform contextual links into parameters suitable for theme_links().
+ // Transform contextual links into parameters suitable for links.html.twig.
$links = array();
foreach ($items as $class => $item) {
$class = drupal_html_class($class);
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 05195e0..38c492b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -2843,7 +2843,7 @@ protected function assertNoTitle($title, $message = '', $group = 'Other') {
* Asserts themed output.
*
* @param $callback
- * The name of the theme function to invoke; e.g. 'links' for theme_links().
+ * The name of the theme function to invoke; e.g. 'links' for links.html.twig.
* @param $variables
* An array of variables to pass to the theme function.
* @param $expected
diff --git a/core/modules/system/css/system.theme.css b/core/modules/system/css/system.theme.css
index 4e83886..f205034 100644
--- a/core/modules/system/css/system.theme.css
+++ b/core/modules/system/css/system.theme.css
@@ -398,7 +398,7 @@ ul.menu a.active {
}
/**
- * Markup generated by theme_links().
+ * Markup generated by links.html.twig.
*/
ul.inline,
ul.links.inline {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php
index 0ae413f..ee4bb10 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php
@@ -149,9 +149,13 @@ function testItemList() {
}
/**
- * Tests theme_links().
+ * Tests links.html.twig.
*/
function testLinks() {
+ // Turn off the query for the l() function to compare the active
+ // link correctly.
+ $original_query = \Drupal::request()->query->all();
+ \Drupal::request()->query->replace(array());
// Verify that empty variables produce no output.
$variables = array();
$expected = '';
@@ -198,6 +202,9 @@ function testLinks() {
$expected = $expected_heading . $expected_links;
$this->assertThemeOutput('links', $variables, $expected);
+ // Restore the original request's query.
+ \Drupal::request()->query->replace($original_query);
+
// Verify that passing an array as heading works (core support).
$variables['heading'] = array('text' => 'Links heading', 'level' => 'h3', 'class' => 'heading');
$expected_heading = 'Links heading
';
diff --git a/core/modules/system/templates/links.html.twig b/core/modules/system/templates/links.html.twig
new file mode 100644
index 0000000..65d87c2
--- /dev/null
+++ b/core/modules/system/templates/links.html.twig
@@ -0,0 +1,59 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a set of links.
+ *
+ * Available variables:
+ * - attributes: Attributes for the UL containing the list of links.
+ * - links: Links to be output.
+ * Each link will have the following elements:
+ * - title: The link text.
+ * - href: The link URL. If omitted, the 'title' is shown as a plain text
+ * item in the links list. If 'href' is supplied, the entire link is passed
+ * to l() as its $options parameter.
+ * - html: (optional) Whether or not 'title' is HTML. If set, the title will
+ * not be passed through check_plain().
+ * - attributes: (optional) HTML attributes for the anchor, or for the
+ * tag if no 'href' is supplied.
+ * - heading: (optional) A heading to precede the links.
+ * - text: The heading text.
+ * - level: The heading level (e.g. 'h2', 'h3').
+ * - attributes: (optional) A keyed list of attributes for the heading.
+ * If the heading is a string, it will be used as the text of the heading and
+ * the level will default to 'h2'.
+ *
+ * Headings should be used on navigation menus and any list of links that
+ * consistently appears on multiple pages. To make the heading invisible use
+ * the 'visually-hidden' CSS class. Do not use 'display:none', which
+ * removes it from screen-readers and assistive technology. Headings allow
+ * screen-reader and keyboard only users to navigate to or skip the links.
+ * See http://juicystudio.com/article/screen-readers-display-none.php and
+ * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
+ *
+ * @see template_preprocess_links()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if links -%}
+ {%- if heading -%}
+ {%- if heading.level -%}
+ <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}{{ heading.level }}>
+ {%- else -%}
+ {{ heading.text }}
+ {%- endif -%}
+ {%- endif -%}
+
+ {%- for item in links -%}
+ -
+ {%- if item.link -%}
+ {{ item.link }}
+ {%- elseif item.text_attributes -%}
+ {{ item.text }}
+ {%- else -%}
+ {{ item.text }}
+ {%- endif -%}
+
+ {%- endfor -%}
+
+{%- endif %}
diff --git a/core/modules/system/tests/modules/ajax_test/ajax_test.module b/core/modules/system/tests/modules/ajax_test/ajax_test.module
index 2ea9eb9..e78d163 100644
--- a/core/modules/system/tests/modules/ajax_test/ajax_test.module
+++ b/core/modules/system/tests/modules/ajax_test/ajax_test.module
@@ -120,7 +120,7 @@ function ajax_test_dialog() {
),
);
- // Dialog behavior applied to links rendered by theme_links().
+ // Dialog behavior applied to links rendered by links.html.twig.
$build['links'] = array(
'#theme' => 'links',
'#links' => array(
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
index 05c11cc..61022f0 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
@@ -962,7 +962,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
break;
}
- // Create an array of actions to pass to theme_links
+ // Create an array of actions to pass to links template.
$actions = array();
$count_handlers = count($executable->display_handler->getHandlers($type));