diff -u b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php --- b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -2068,24 +2068,31 @@ if ($this->isMoreEnabled() && ($this->useMoreAlways() || (!empty($this->view->pager) && $this->view->pager->hasMoreRecords()))) { // If the user has supplied a custom "More" link path, use that for the URL. if ($this->getOption('link_display') == 'custom_url' && $path = $this->getOption('link_url')) { - // Replace any argument tokens. + // Parse the $path. + $parts = UrlHelper::parse($path); + if ($tokens = $this->getArgumentsTokens()) { - // \Drupal\views\Plugin\views\PluginBase::viewsTokenReplace will - // replace '&' in the $path. In order to keep '&', we first replace it - // with a different temporary placeholder. - $query_replacements = 0; - $path = preg_replace("/&(?!amp;)/", "##", $path, -1, $query_replacements); - $path = $this->viewsTokenReplace($path, $tokens); - - // Replace the temporary placeholder. - if ($query_replacements > 0) { - $path = str_replace('##', '&', $path); + // Replace any argument tokens in path. + $parts['path'] = $this->viewsTokenReplace($parts['path'], $tokens); + + // Replace any argument tokens in fragment. + $parts['fragment'] = $this->viewsTokenReplace($parts['fragment'], $tokens); + + // Replace any argument tokens in query. + if (isset($parts['query'])) { + foreach ($parts['query'] as $name => $value) { + $parts['query'][$name] = $this->viewsTokenReplace($value, $tokens); + } } } + // Get options. + $options = array_diff_key($parts, array_flip(['path'])); + + // Create url. // @todo Views should expect and store a leading /. See: // https://www.drupal.org/node/2423913 - $url = UrlHelper::isExternal($path) ? Url::fromUri($path) : Url::fromUserInput('/' . ltrim($path, '/')); + $url = UrlHelper::isExternal($parts['path']) ? Url::fromUri($parts['path'], $options) : Url::fromUserInput('/' . ltrim($parts['path'], '/'), $options); } // Otherwise, use the URL for the display. else { diff -u b/core/modules/views/src/Tests/Plugin/DisplayTest.php b/core/modules/views/src/Tests/Plugin/DisplayTest.php --- b/core/modules/views/src/Tests/Plugin/DisplayTest.php +++ b/core/modules/views/src/Tests/Plugin/DisplayTest.php @@ -326,6 +326,24 @@ $output = $renderer->renderRoot($output); $this->setRawContent($output); $this->assertLinkByHref('/node?date=22&foo=bar', 0, 'The read more link with href "/node?date=22&foo=bar" was found.'); + + // Test more link with arguments in path. + $view->display_handler->setOption('link_url', 'node/{{ raw_arguments.age }}?date={{ raw_arguments.age }}&foo=bar'); + $view->setArguments(array(22)); + $this->executeView($view); + $output = $view->preview(); + $output = $renderer->renderRoot($output); + $this->setRawContent($output); + $this->assertLinkByHref('/node/22?date=22&foo=bar', 0, 'The read more link with href "/node/22?date=22&foo=bar" was found.'); + + // Test more link with arguments in fragment. + $view->display_handler->setOption('link_url', 'node?date={{ raw_arguments.age }}&foo=bar#{{ raw_arguments.age }}'); + $view->setArguments(array(22)); + $this->executeView($view); + $output = $view->preview(); + $output = $renderer->renderRoot($output); + $this->setRawContent($output); + $this->assertLinkByHref('/node?date=22&foo=bar#22', 0, 'The read more link with href "/node?date=22&foo=bar#22" was found.'); } /**