install(array('views'));
// Create two taxonomy terms and set term2 as the parent of term1.
$term1 = $this->createTerm($this->vocabulary);
$term2 = $this->createTerm($this->vocabulary);
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
index 04bbf6c..546b312 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
@@ -302,6 +302,7 @@ function testTermAutocompletion() {
* Save, edit and delete a term using the user interface.
*/
function testTermInterface() {
+ \Drupal::moduleHandler()->install(array('views'));
$edit = array(
'name[0][value]' => $this->randomName(12),
'description[0][value]' => $this->randomName(100),
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 69bb530..6d9e128 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -16,6 +16,7 @@
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\Component\Utility\String;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/**
* Denotes that no term in the vocabulary has a parent.
@@ -66,8 +67,8 @@ function taxonomy_help($path, $arg) {
$output .= '' . t('Before you can use a new vocabulary to classify your content, a new Taxonomy term field must be added to a content type on its manage fields page. When adding a taxonomy field, you choose a widget to use to enter the taxonomy information on the content editing page: a select list, checkboxes, radio buttons, or an auto-complete field (to build a free-tagging vocabulary). After choosing the field type and widget, on the subsequent field settings page you can choose the desired vocabulary, whether one or multiple terms can be chosen from the vocabulary, and other settings. The same vocabulary can be added to multiple content types, by using the "Re-use existing field" section on the manage fields page.', array('@ctedit' => url('admin/structure/types'))) . '';
$output .= '' . t('Classifying content') . '';
$output .= '' . t('After the vocabulary is assigned to the content type, you can start classifying content. The field with terms will appear on the content editing screen when you edit or add new content.', array('@addnode' => url('node/add'))) . '';
- $output .= '' . t('Viewing listings and RSS feeds by term') . '';
- $output .= '' . t("Each taxonomy term automatically provides a page listing content that has its classification, and a corresponding RSS feed. For example, if the taxonomy term country rock has the ID 123 (you can see this by looking at the URL when hovering on the linked term, which you can click to navigate to the listing page), then you will find this list at the path taxonomy/term/123. The RSS feed will use the path taxonomy/term/123/feed (the RSS icon for this term's listing will automatically display in your browser's address bar when viewing the listing page).") . '';
+ $output .= '' . t('Viewing listings') . '';
+ $output .= '' . t("Each taxonomy term automatically provides a page listing content that has its classificatio. For example, if the taxonomy term country rock has the ID 123 (you can see this by looking at the URL when hovering on the linked term, which you can click to navigate to the listing page), then you will find this list at the path taxonomy/term/123.") . '';
$output .= '' . t('Extending Taxonomy module') . '';
$output .= '' . t('There are many contributed modules that extend the behavior of the Taxonomy module for both display and organization of terms.', array('@taxcontrib' => 'http://drupal.org/project/modules?filters=tid:71&solrsort=sis_project_release_usage%20desc'));
$output .= '';
@@ -134,6 +135,37 @@ function taxonomy_term_uri($term) {
}
/**
+ * Implements hook_page_build().
+ */
+function taxonomy_page_build(&$page) {
+ $request = \Drupal::request();
+ if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'taxonomy.term_page') {
+ $term = $request->attributes->get('taxonomy_term');
+ foreach ($term->uriRelationships() as $rel) {
+ // Set the term path as the canonical URL to prevent duplicate content.
+ $page['#attached']['drupal_add_html_head_link'][] = array(
+ array(
+ 'rel' => $rel,
+ 'href' => $term->url($rel),
+ ),
+ TRUE,
+ );
+
+ if ($rel == 'canonical') {
+ // Set the non-aliased canonical path as a default shortlink.
+ $page['#attached']['drupal_add_html_head_link'][] = array(
+ array(
+ 'rel' => 'shortlink',
+ 'href' => $term->url($rel, array('alias' => TRUE)),
+ ),
+ TRUE,
+ );
+ }
+ }
+ }
+}
+
+/**
* Return nodes attached to a term across all field instances.
*
* This function requires taxonomy module to be maintaining its own tables,
diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc
deleted file mode 100644
index 294dabb..0000000
--- a/core/modules/taxonomy/taxonomy.pages.inc
+++ /dev/null
@@ -1,81 +0,0 @@
-id() . '/feed', 'RSS - ' . $term->getName());
-
- foreach ($term->uriRelationships() as $rel) {
- // Set the term path as the canonical URL to prevent duplicate content.
- $build['#attached']['drupal_add_html_head_link'][] = array(
- array(
- 'rel' => $rel,
- 'href' => $term->url($rel),
- ),
- TRUE,
- );
-
- if ($rel == 'canonical') {
- // Set the non-aliased canonical path as a default shortlink.
- $build['#attached']['drupal_add_html_head_link'][] = array(
- array(
- 'rel' => 'shortlink',
- 'href' => $term->url($rel, array('alias' => TRUE)),
- ),
- TRUE,
- );
- }
- }
-
- $build['taxonomy_terms'] = taxonomy_term_view_multiple(array($term->id() => $term));
- if ($nids = taxonomy_select_nodes($term->id(), TRUE, \Drupal::config('node.settings')->get('items_per_page'))) {
- $nodes = node_load_multiple($nids);
- $build['nodes'] = node_view_multiple($nodes);
- $build['pager'] = array(
- '#theme' => 'pager',
- '#weight' => 5,
- );
- }
- else {
- $build['no_content'] = array(
- '#prefix' => '',
- '#markup' => t('There is currently no content classified with this term.'),
- '#suffix' => '
',
- );
- }
- return $build;
-}
-
-/**
- * Generate the content feed for a taxonomy term.
- *
- * @param \Drupal\taxonomy\Entity\Term $term
- * The taxonomy term entity.
- *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- * Use \Drupal\taxonomy\Controller\TaxonomyController::termFeed().
- */
-function taxonomy_term_feed(Term $term) {
- $channel['link'] = url('taxonomy/term/' . $term->id(), array('absolute' => TRUE));
- $channel['title'] = \Drupal::config('system.site')->get('name') . ' - ' . $term->getName();
- // Only display the description if we have a single term, to avoid clutter and confusion.
- // HTML will be removed from feed description.
- $channel['description'] = $term->description->processed;
- $nids = taxonomy_select_nodes($term->id(), FALSE, \Drupal::config('system.rss')->get('items.limit'));
-
- return node_feed($nids, $channel);
-}
diff --git a/core/modules/taxonomy/taxonomy.routing.yml b/core/modules/taxonomy/taxonomy.routing.yml
index 1182589..3f49299 100644
--- a/core/modules/taxonomy/taxonomy.routing.yml
+++ b/core/modules/taxonomy/taxonomy.routing.yml
@@ -91,16 +91,7 @@ taxonomy.overview_terms:
taxonomy.term_page:
path: '/taxonomy/term/{taxonomy_term}'
defaults:
- _content: '\Drupal\taxonomy\Controller\TaxonomyController::termPage'
- _title: 'Taxonomy term'
- _title_callback: '\Drupal\taxonomy\Controller\TaxonomyController::termTitle'
- requirements:
- _entity_access: 'taxonomy_term.view'
-
-taxonomy.term_feed:
- path: '/taxonomy/term/{taxonomy_term}/feed'
- defaults:
- _content: '\Drupal\taxonomy\Controller\TaxonomyController::termFeed'
+ _entity_view: 'taxonomy_term.full'
_title: 'Taxonomy term'
_title_callback: '\Drupal\taxonomy\Controller\TaxonomyController::termTitle'
requirements:
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
index bf4e008..b815be2 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
@@ -249,7 +249,7 @@ public function alterRoutes(RouteCollection $collection) {
// We assume that the numeric ids of the parameters match the one from
// the view argument handlers.
foreach ($parameters as $position => $parameter_name) {
- $path = str_replace('arg_' . $position, $parameter_name, $path);
+ $path = str_replace('{arg_' . $position . '}', '{' . $parameter_name . '}', $path);
$argument_map['arg_' . $position] = $parameter_name;
}
// Set the corrected path and the mapping to the route object.
diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php
index 95f140e..549a913 100644
--- a/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php
+++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php
@@ -214,7 +214,7 @@ public function testCollectRoutesWithNamedParameters() {
}
/**
- * Tests alter routes with parameters in the overriding route.
+ * Tests altering routes with parameters in the overridden route.
*/
public function testAlterRoutesWithParameters() {
$collection = new RouteCollection();
@@ -222,7 +222,7 @@ public function testAlterRoutesWithParameters() {
list($view) = $this->setupViewExecutableAccessPlugin();
- // Manually setup an argument handler.
+ // Manually set up an argument handler.
$argument = $this->getMockBuilder('Drupal\views\Plugin\views\argument\ArgumentPluginBase')
->disableOriginalConstructor()
->getMock();
@@ -250,6 +250,40 @@ public function testAlterRoutesWithParameters() {
}
/**
+ * Tests altering routes with optional parameters in the overridden route.
+ */
+ public function testAlterRoutesWithOptionalParameters() {
+ $collection = new RouteCollection();
+ $collection->add('test_route', new Route('test_route/{parameter}', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content')));
+
+ list($view) = $this->setupViewExecutableAccessPlugin();
+
+ $display = array();
+ $display['display_plugin'] = 'page';
+ $display['id'] = 'page_1';
+ $display['display_options'] = array(
+ 'path' => 'test_route/%',
+ );
+ $display['display_options']['arguments'] = array(
+ 'test_id' => array(),
+ 'test_id2' => array(),
+ );
+ $this->pathPlugin->initDisplay($view, $display);
+
+ $view_route_names = $this->pathPlugin->alterRoutes($collection);
+ $this->assertEquals(array('test_id.page_1' => 'test_route'), $view_route_names);
+
+ // Ensure that the test_route is overridden.
+ $route = $collection->get('test_route');
+ $this->assertInstanceOf('\Symfony\Component\Routing\Route', $route);
+ $this->assertEquals('test_id', $route->getDefault('view_id'));
+ $this->assertEquals('page_1', $route->getDefault('display_id'));
+ // Ensure that the path did not changed and placeholders are respected.
+ $this->assertEquals('/test_route/{parameter}/{arg_1}', $route->getPath());
+ $this->assertEquals(array('arg_0' => 'parameter'), $route->getOption('_view_argument_map'));
+ }
+
+ /**
* Returns some mocked view entity, view executable, and access plugin.
*/
protected function setupViewExecutableAccessPlugin() {