diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 012dec4f21..8bfc538ed9 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -5,6 +5,7 @@ use Drupal\Component\Plugin\DependentPluginInterface; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableDependencyInterface; @@ -2072,14 +2073,45 @@ public function renderPager() { */ public function renderMoreLink() { if ($this->isMoreEnabled() && ($this->useMoreAlways() || (!empty($this->view->pager) && $this->view->pager->hasMoreRecords()))) { - // If the user has supplied a custom "More" link path, replace any - // argument tokens and use that for the URL. - if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) { - $tokens = $this->getArgumentsTokens(); - $path = $this->viewsTokenReplace($override_path, $tokens); + // 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')) { + // Parse the $path. + $parts = UrlHelper::parse($path); + } + + if ($tokens = $this->getArgumentsTokens() && ($this->getOption('link_display') == 'custom_url' && $path = $this->getOption('link_url'))) { + // 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) { + if (is_array($value)) { + // Handle query parameters where the key in the form of array. + // for example, f[0] for facets. + foreach ($value as $key => $val) { + $parts['query'][$name][$key] = $this->viewsTokenReplace($val, $tokens); + } + } + else { + $parts['query'][$name] = $this->viewsTokenReplace($value, $tokens); + } + } + } + } + + if ($tokens = $this->getArgumentsTokens() || ($this->getOption('link_display') == 'custom_url' && $path = $this->getOption('link_url'))) { + // 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 = Url::fromUserInput('/' . $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 { @@ -2089,11 +2121,10 @@ public function renderMoreLink() { // If a URL is available (either from the display or a custom path), // render the "More" link. if ($url) { - $url_options = []; + // Merge the exposed query parameters. if (!empty($this->view->exposed_raw_input)) { - $url_options['query'] = $this->view->exposed_raw_input; + $url->mergeOptions(['query' => $this->view->exposed_raw_input]); } - $url->setOptions($url_options); return [ '#type' => 'more_link',