diff --git a/core/modules/views/src/Form/ViewsExposedForm.php b/core/modules/views/src/Form/ViewsExposedForm.php
index 72f754b..04f854d 100644
--- a/core/modules/views/src/Form/ViewsExposedForm.php
+++ b/core/modules/views/src/Form/ViewsExposedForm.php
@@ -115,7 +115,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#id' => drupal_html_id('edit-submit-' . $view->storage->id()),
     );
 
-    $form['#action'] = _url($view->display_handler->getUrl());
+    $form['#action'] = $view->getUrl()->toString();
     $form['#theme'] = $view->buildThemeFunctions('views_exposed_form');
     $form['#id'] = Html::cleanCssIdentifier('views_exposed_form-' . String::checkPlain($view->storage->id()) . '-' . String::checkPlain($display['id']));
 
diff --git a/core/modules/views/src/Form/ViewsForm.php b/core/modules/views/src/Form/ViewsForm.php
index c1296b2..8ad7c2d 100644
--- a/core/modules/views/src/Form/ViewsForm.php
+++ b/core/modules/views/src/Form/ViewsForm.php
@@ -133,7 +133,7 @@ public function buildForm(array $form, FormStateInterface $form_state, ViewExecu
     $query = $this->requestStack->getCurrentRequest()->query->all();
     $query = UrlHelper::filterQueryParameters($query, array(), '');
 
-    $form['#action'] = $this->urlGenerator->generateFromPath($view->getUrl(), array('query' => $query));
+    $form['#action'] = $view->getUrl()->setOption('query', $query)->toString();
     // Tell the preprocessor whether it should hide the header, footer, pager...
     $form['show_view_elements'] = array(
       '#type' => 'value',
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 61c9e84..1171a86 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -25,30 +25,9 @@
 use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException;
 
 /**
- * @defgroup views_display_plugins Views display plugins
- * @{
- * Plugins to handle the overall display of views.
- *
- * Display plugins are responsible for controlling where a view is rendered;
- * that is, how it is exposed to other parts of Drupal. 'Page' and 'block' are
- * the most commonly used display plugins. Each view also has a 'master' (or
- * 'default') display that includes information shared between all its
- * displays (see \Drupal\views\Plugin\views\display\DefaultDisplay).
- *
- * Display plugins extend \Drupal\views\Plugin\views\display\DisplayPluginBase.
- * They must be annotated with \Drupal\views\Annotation\ViewsDisplay
- * annotation, and they must be in namespace directory Plugin\views\display.
- *
- * @ingroup views_plugins
- *
- * @see plugin_api
- * @see views_display_extender_plugins
- */
-
-/**
  * Base class for views display plugins.
  */
-abstract class DisplayPluginBase extends PluginBase {
+abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInterface {
 
   /**
    * The top object of a view.
@@ -156,6 +135,9 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
     parent::__construct(array(), $plugin_id, $plugin_definition);
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function initDisplay(ViewExecutable $view, array &$display, array &$options = NULL) {
     $this->view = $view;
 
@@ -228,6 +210,9 @@ public function initDisplay(ViewExecutable $view, array &$display, array &$optio
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function destroy() {
     parent::destroy();
 
@@ -249,14 +234,12 @@ public function destroy() {
   }
 
   /**
-   * Determines if this display is the 'default' display.
-   *
-   * 'Default' display contains fallback settings.
+   * {@inheritdoc}
    */
   public function isDefaultDisplay() { return FALSE; }
 
   /**
-   * Determines if this display uses exposed filters.
+   * {@inheritdoc}
    */
   public function usesExposed() {
     if (!isset($this->has_exposed)) {
@@ -281,29 +264,21 @@ public function usesExposed() {
   }
 
   /**
-   * Determines if this display should display the exposed filters widgets.
-   *
-   * Regardless of what this function
-   * returns, exposed filters will not be used nor
-   * displayed unless usesExposed() returns TRUE.
+   * {@inheritdoc}
    */
   public function displaysExposed() {
     return TRUE;
   }
 
   /**
-   * Whether the display allows the use of AJAX or not.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function usesAJAX() {
     return $this->usesAJAX;
   }
 
   /**
-   * Whether the display is actually using AJAX or not.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function ajaxEnabled() {
     if ($this->usesAJAX()) {
@@ -313,29 +288,21 @@ public function ajaxEnabled() {
   }
 
   /**
-   * Whether the display is enabled.
-   *
-   * @return bool
-   *   Returns TRUE if the display is marked as enabled, else FALSE.
+   * {@inheritdoc}
    */
   public function isEnabled() {
     return (bool) $this->getOption('enabled');
   }
 
   /**
-   * Whether the display allows the use of a pager or not.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
-
   public function usesPager() {
     return $this->usesPager;
   }
 
   /**
-   * Whether the display is using a pager or not.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function isPagerEnabled() {
     if ($this->usesPager()) {
@@ -348,18 +315,14 @@ public function isPagerEnabled() {
   }
 
   /**
-   * Whether the display allows the use of a 'more' link or not.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function usesMore() {
     return $this->usesMore;
   }
 
   /**
-   * Whether the display is using the 'more' link or not.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function isMoreEnabled() {
     if ($this->usesMore()) {
@@ -369,14 +332,14 @@ public function isMoreEnabled() {
   }
 
   /**
-   * Does the display have groupby enabled?
+   * {@inheritdoc}
    */
   public function useGroupBy() {
     return $this->getOption('group_by');
   }
 
   /**
-   * Should the enabled display more link be shown when no more items?
+   * {@inheritdoc}
    */
   public function useMoreAlways() {
     if ($this->usesMore()) {
@@ -386,7 +349,7 @@ public function useMoreAlways() {
   }
 
   /**
-   * Does the display have custom link text?
+   * {@inheritdoc}
    */
   public function useMoreText() {
     if ($this->usesMore()) {
@@ -396,9 +359,7 @@ public function useMoreText() {
   }
 
   /**
-   * Determines whether this display can use attachments.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function acceptAttachments() {
     // To be able to accept attachments this display have to be able to use
@@ -419,38 +380,26 @@ public function acceptAttachments() {
   }
 
   /**
-   * Returns whether the display can use attachments.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function usesAttachments() {
     return $this->usesAttachments;
   }
 
   /**
-   * Returns whether the display can use areas.
-   *
-   * @return bool
-   *   TRUE if the display can use areas, or FALSE otherwise.
+   * {@inheritdoc}
    */
   public function usesAreas() {
     return $this->usesAreas;
   }
 
   /**
-   * Allows displays to attach to other views.
-   *
-   * @param \Drupal\views\ViewExecutable $view
-   *   The views executable.
-   * @param string $display_id
-   *   The display to attach to.
-   * @param array $build
-   *   The parent view render array.
+   * {@inheritdoc}
    */
   public function attachTo(ViewExecutable $view, $display_id, array &$build) { }
 
   /**
-   * Lists the 'defaultable' sections and what items each section contains.
+   * {@inheritdoc}
    */
   public function defaultableSections($section = NULL) {
     $sections = array(
@@ -722,40 +671,22 @@ protected function defineOptions() {
   }
 
   /**
-   * Checks to see if the display has a 'path' field.
-   *
-   * This is a pure function and not just a setting on the definition
-   * because some displays (such as a panel pane) may have a path based
-   * upon configuration.
-   *
-   * By default, displays do not have a path.
+   * {@inheritdoc}
    */
   public function hasPath() { return FALSE; }
 
   /**
-   * Checks to see if the display has some need to link to another display.
-   *
-   * For the most part, displays without a path will use a link display.
-   * However, sometimes displays that have a path might also need to link to
-   * another display. This is true for feeds.
+   * {@inheritdoc}
    */
   public function usesLinkDisplay() { return !$this->hasPath(); }
 
   /**
-   * Checks to see if the display can put the exposed form in a block.
-   *
-   * By default, displays that do not have a path cannot disconnect
-   * the exposed form and put it in a block, because the form has no
-   * place to go and Views really wants the forms to go to a specific
-   * page.
+   * {@inheritdoc}
    */
   public function usesExposedFormInBlock() { return $this->hasPath(); }
 
   /**
-   * Find out all displays which are attached to this display.
-   *
-   * The method is just using the pure storage object to avoid loading of the
-   * sub displays which would kill lazy loading.
+   * {@inheritdoc}
    */
   public function getAttachedDisplays() {
     $current_display_id = $this->display['id'];
@@ -775,7 +706,7 @@ public function getAttachedDisplays() {
   }
 
   /**
-   * Returns the ID of the display to use when making links.
+   * {@inheritdoc}
    */
   public function getLinkDisplay() {
     $display_id = $this->getOption('link_display');
@@ -794,10 +725,7 @@ public function getLinkDisplay() {
   }
 
   /**
-   * Returns the base path to use for this display.
-   *
-   * This can be overridden for displays that do strange things
-   * with the path.
+   * {@inheritdoc}
    */
   public function getPath() {
     if ($this->hasPath()) {
@@ -810,22 +738,22 @@ public function getPath() {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getUrl() {
-    return $this->view->getUrl();
+    return $this->view->getUrl(NULL, $this->display['id']);
   }
 
   /**
-   * Determines if an option is set to use the default or current display.
-   *
-   * @return
-   *   TRUE for the default display.
+   * {@inheritdoc}
    */
   public function isDefaulted($option) {
     return !$this->isDefaultDisplay() && !empty($this->default_display) && !empty($this->options['defaults'][$option]);
   }
 
   /**
-   * Gets an option, from this display or the default display.
+   * {@inheritdoc}
    */
   public function getOption($option) {
     if ($this->isDefaulted($option)) {
@@ -838,21 +766,14 @@ public function getOption($option) {
   }
 
   /**
-   * Determines if the display's style uses fields.
-   *
-   * @return bool
+   * {@inheritdoc}
    */
   public function usesFields() {
     return $this->getPlugin('style')->usesFields();
   }
 
   /**
-   * Get the instance of a plugin, for example style or row.
-   *
-   * @param string $type
-   *   The type of the plugin.
-   *
-   * @return \Drupal\views\Plugin\views\ViewsPluginInterface
+   * {@inheritdoc}
    */
   public function getPlugin($type) {
     // Look up the plugin name to use for this instance.
@@ -886,7 +807,7 @@ public function getPlugin($type) {
   }
 
   /**
-   * Get the handler object for a single handler.
+   * {@inheritdoc}
    */
   public function &getHandler($type, $id) {
     if (!isset($this->handlers[$type])) {
@@ -903,9 +824,7 @@ public function &getHandler($type, $id) {
   }
 
   /**
-   * Get a full array of handlers for $type. This caches them.
-   *
-   * @return \Drupal\views\Plugin\views\ViewsHandlerInterface[]
+   * {@inheritdoc}
    */
   public function &getHandlers($type) {
     if (!isset($this->handlers[$type])) {
@@ -967,16 +886,7 @@ public function &getHandlers($type) {
   }
 
   /**
-   * Retrieves a list of fields for the current display.
-   *
-   * This also takes into account any associated relationships, if they exist.
-   *
-   * @param bool $groupable_only
-   *   (optional) TRUE to only return an array of field labels from handlers
-   *   that support the useStringGroupBy method, defaults to FALSE.
-   *
-   * @return array
-   *   An array of applicable field options, keyed by ID.
+   * {@inheritdoc}
    */
   public function getFieldLabels($groupable_only = FALSE) {
     $options = array();
@@ -1003,7 +913,7 @@ public function getFieldLabels($groupable_only = FALSE) {
   }
 
   /**
-   * Sets an option, on this display or the default display.
+   * {@inheritdoc}
    */
   public function setOption($option, $value) {
     if ($this->isDefaulted($option)) {
@@ -1018,7 +928,7 @@ public function setOption($option, $value) {
   }
 
   /**
-   * Set an option and force it to be an override.
+   * {@inheritdoc}
    */
   public function overrideOption($option, $value) {
     $this->setOverride($option, FALSE);
@@ -1026,10 +936,7 @@ public function overrideOption($option, $value) {
   }
 
   /**
-   * Returns a link to a section of a form.
-   *
-   * Because forms may be split up into sections, this provides an easy URL
-   * to exactly the right section. Don't override this.
+   * {@inheritdoc}
    */
   public function optionLink($text, $section, $class = '', $title = '') {
     if (!empty($class)) {
@@ -1048,10 +955,7 @@ public function optionLink($text, $section, $class = '', $title = '') {
   }
 
   /**
-   * Returns to tokens for arguments.
-   *
-   * This function is similar to views_handler_field::getRenderTokens()
-   * but without fields tokens.
+   * {@inheritdoc}
    */
   public function getArgumentsTokens() {
     $tokens = array();
@@ -1075,9 +979,7 @@ public function getArgumentsTokens() {
   }
 
   /**
-   * Provides the default summary for options in the views UI.
-   *
-   * This output is returned as an array.
+   * {@inheritdoc}
    */
   public function optionsSummary(&$categories, &$options) {
     $categories = array(
@@ -1399,7 +1301,7 @@ public function optionsSummary(&$categories, &$options) {
   }
 
   /**
-   * Provides the default form for setting options.
+   * {@inheritdoc}
    */
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
@@ -1891,7 +1793,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Validates the options form.
+   * {@inheritdoc}
    */
   public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     $section = $form_state->get('section');
@@ -1943,9 +1845,7 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Performs any necessary changes to the form values prior to storage.
-   *
-   * There is no need for this function to actually store the data.
+   * {@inheritdoc}
    */
   public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     // Not sure I like this being here, but it seems (?) like a logical place.
@@ -2057,21 +1957,14 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * If override/revert was clicked, perform the proper toggle.
+   * {@inheritdoc}
    */
   public function optionsOverride($form, FormStateInterface $form_state) {
     $this->setOverride($form_state->get('section'));
   }
 
   /**
-   * Flip the override setting for the given section.
-   *
-   * @param string $section
-   *   Which option should be marked as overridden, for example "filters".
-   * @param bool $new_state
-   *   Select the new state of the option:
-   *   - TRUE: Revert new state option to default.
-   *   - FALSE: Mark it as overridden.
+   * {@inheritdoc}
    */
   public function setOverride($section, $new_state = NULL) {
     $options = $this->defaultableSections($section);
@@ -2101,7 +1994,7 @@ public function setOverride($section, $new_state = NULL) {
   }
 
   /**
-   * Injects anything into the query that the display handler needs.
+   * {@inheritdoc}
    */
   public function query() {
     foreach ($this->extenders as $extender) {
@@ -2110,45 +2003,42 @@ public function query() {
   }
 
   /**
-   * Does nothing (obsolete function).
-   *
-   * @todo This function no longer seems to be used.
+   * {@inheritdoc}
    */
   public function renderFilters() { }
 
   /**
-   * Checks to see if the display plugins support pager rendering.
+   * {@inheritdoc}
    */
   public function renderPager() {
     return TRUE;
   }
 
   /**
-   * Renders the 'more' link.
+   * {@inheritdoc}
    */
   public function renderMoreLink() {
     if ($this->isMoreEnabled() && ($this->useMoreAlways() || (!empty($this->view->pager) && $this->view->pager->hasMoreRecords()))) {
-      $path = $this->getPath();
-
       if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) {
         $tokens = $this->getArgumentsTokens();
         $path = $this->viewsTokenReplace($override_path, $tokens);
+        $url = Url::fromUri('user-path:' . $path);
+      }
+      else {
+        $url = $this->view->getUrl(NULL, $this->display['id']);
       }
 
-      if ($path) {
-        if (empty($override_path)) {
-          $path = $this->view->getUrl(NULL, $path);
-        }
+      if ($url) {
         $url_options = array();
         if (!empty($this->view->exposed_raw_input)) {
           $url_options['query'] = $this->view->exposed_raw_input;
         }
+        $url->setOptions($url_options);
         $theme = $this->view->buildThemeFunctions('views_more');
-        $path = check_url(_url($path, $url_options));
 
         return array(
           '#theme' => $theme,
-          '#more_url' => $path,
+          '#more_url' => $url->toString(),
           '#link_text' => String::checkPlain($this->useMoreText()),
           '#view' => $this->view,
         );
@@ -2157,19 +2047,14 @@ public function renderMoreLink() {
   }
 
   /**
-   * Gets menu links, if this display provides some.
-   *
-   * @return array
-   *   The menu links registers for this display.
-   *
-   * @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
+   * {@inheritdoc}
    */
   public function getMenuLinks() {
     return array();
   }
 
   /**
-   * Renders this display.
+   * {@inheritdoc}
    */
   public function render() {
     $rows = (!empty($this->view->result) || $this->view->style_plugin->evenEmpty()) ? $this->view->style_plugin->render($this->view->result) : array();
@@ -2190,15 +2075,7 @@ public function render() {
   }
 
   /**
-   * #pre_render callback for view display rendering.
-   *
-   * @see self::render()
-   *
-   * @param array $element
-   *   The element to #pre_render
-   *
-   * @return array
-   *   The processed element.
+   * {@inheritdoc}
    */
   public function elementPreRender(array $element) {
     $view = $element['#view'];
@@ -2259,16 +2136,7 @@ public function elementPreRender(array $element) {
   }
 
   /**
-   * Renders one of the available areas.
-   *
-   * @param string $area
-   *   Identifier of the specific area to render.
-   * @param bool $empty
-   *   (optional) Indicator whether or not the view result is empty. Defaults to
-   *   FALSE
-   *
-   * @return array
-   *   A render array for the given area.
+   * {@inheritdoc}
    */
   public function renderArea($area, $empty = FALSE) {
     $return = array();
@@ -2278,9 +2146,8 @@ public function renderArea($area, $empty = FALSE) {
     return $return;
   }
 
-
   /**
-   * Determines if the user has access to this display of the view.
+   * {@inheritdoc}
    */
   public function access(AccountInterface $account = NULL) {
     if (!isset($account)) {
@@ -2298,10 +2165,7 @@ public function access(AccountInterface $account = NULL) {
   }
 
   /**
-   * Sets up any variables on the view prior to execution.
-   *
-   * These are separated from execute because they are extremely common
-   * and unlikely to be overridden on an individual display.
+   * {@inheritdoc}
    */
   public function preExecute() {
     $this->view->setAjaxEnabled($this->ajaxEnabled());
@@ -2320,12 +2184,7 @@ public function preExecute() {
   }
 
   /**
-   * Calculates the display's cache metadata by inspecting each handler/plugin.
-   *
-   * @return array
-   *   Returns an array:
-   *   - first value: (boolean) Whether the display is cacheable.
-   *   - second value: (string[]) The cache contexts the display varies by.
+   * {@inheritdoc}
    */
   public function calculateCacheMetadata () {
     $is_cacheable = TRUE;
@@ -2364,20 +2223,12 @@ public function calculateCacheMetadata () {
   }
 
   /**
-   * Executes the view and returns data in the format required.
-   *
-   * The base class cannot be executed.
+   * {@inheritdoc}
    */
   public function execute() { }
 
   /**
-   * Builds a renderable array of the view.
-   *
-   * Note: This does not yet contain the executed view, but just the loaded view
-   * executable.
-   *
-   * @return array
-   *   The render array of a view.
+   * {@inheritdoc}
    */
   public function buildRenderable(array $args = []) {
     return [
@@ -2392,9 +2243,7 @@ public function buildRenderable(array $args = []) {
   }
 
   /**
-   * Renders the display for the purposes of a live preview.
-   *
-   * Also might be used for some other AJAXy reason.
+   * {@inheritdoc}
    */
   function preview() {
     return $this->view->render();
@@ -2418,11 +2267,7 @@ protected function getType() {
   }
 
   /**
-   * Make sure the display and all associated handlers are valid.
-   *
-   * @return
-   *   Empty array if the display is valid; an array of error strings if it is
-   *   not.
+   * {@inheritdoc}
    */
   public function validate() {
     $errors = array();
@@ -2477,15 +2322,13 @@ public function validate() {
   }
 
   /**
-   * Reacts on adding a display.
-   *
-   * @see \Drupal\views\Entity\View::newDisplay()
+   * {@inheritdoc}
    */
   public function newDisplay() {
   }
 
   /**
-   * Reacts on deleting a display.
+   * {@inheritdoc}
    */
   public function remove() {
     $menu_links = $this->getMenuLinks();
@@ -2497,16 +2340,7 @@ public function remove() {
   }
 
   /**
-   * Checks if the provided identifier is unique.
-   *
-   * @param string $id
-   *   The id of the handler which is checked.
-   * @param string $identifier
-   *   The actual get identifier configured in the exposed settings.
-   *
-   * @return bool
-   *   Returns whether the identifier is unique on all handlers.
-   *
+   * {@inheritdoc}
    */
   public function isIdentifierUnique($id, $identifier) {
     foreach (ViewExecutable::getHandlerTypes() as $type => $info) {
@@ -2529,13 +2363,7 @@ public function isIdentifierUnique($id, $identifier) {
   }
 
   /**
-   * Is the output of the view empty.
-   *
-   * If a view has no result and neither the empty, nor the footer nor the header
-   * does show anything return FALSE.
-   *
-   * @return bool
-   *   Returns TRUE if the output is empty, else FALSE.
+   * {@inheritdoc}
    */
   public function outputIsEmpty() {
     if (!empty($this->view->result)) {
@@ -2557,7 +2385,7 @@ public function outputIsEmpty() {
   }
 
   /**
-   * Provides the block system with any exposed widget blocks for this display.
+   * {@inheritdoc}
    */
   public function getSpecialBlocks() {
     $blocks = array();
@@ -2575,10 +2403,7 @@ public function getSpecialBlocks() {
   }
 
   /**
-   * Renders the exposed form as block.
-   *
-   * @return string|null
-   *  The rendered exposed form as string or NULL otherwise.
+   * {@inheritdoc}
    */
   public function viewExposedFormBlocks() {
     // Avoid interfering with the admin forms.
@@ -2595,17 +2420,7 @@ public function viewExposedFormBlocks() {
   }
 
   /**
-   * Provides help text for the arguments.
-   *
-   * @return array
-   *   Returns an array which contains text for the argument fieldset:
-   *   - filter value present: The title of the fieldset in the argument
-   *     where you can configure what should be done with a given argument.
-   *   - filter value not present: The title of the fieldset in the argument
-   *     where you can configure what should be done if the argument does not
-   *     exist.
-   *   - description: A description about how arguments are passed
-   *     to the display. For example blocks can't get arguments from url.
+   * {@inheritdoc}
    */
   public function getArgumentText() {
     return array(
@@ -2616,15 +2431,7 @@ public function getArgumentText() {
   }
 
   /**
-   * Provides help text for pagers.
-   *
-   * @return array
-   *   Returns an array which contains text for the items_per_page form
-   *   element:
-   *   - items per page title: The title text for the items_per_page form
-   *     element.
-   *   - items per page description: The description text for the
-   *     items_per_page form element.
+   * {@inheritdoc}
    */
   public function getPagerText() {
     return array(
@@ -2634,7 +2441,7 @@ public function getPagerText() {
   }
 
   /**
-   * Merges default values for all plugin types.
+   * {@inheritdoc}
    */
   public function mergeDefaults() {
     $defined_options = $this->defineOptions();
@@ -2693,9 +2500,7 @@ protected function mergeHandler($type) {
   }
 
   /**
-   * Gets the display extenders.
-   *
-   * @return \Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase[]
+   * {@inheritdoc}
    */
   public function getExtenders() {
     return $this->extenders;
diff --git a/core/modules/views/src/Plugin/views/display/DisplayRouterInterface.php b/core/modules/views/src/Plugin/views/display/DisplayRouterInterface.php
index 70eb191..6223c52 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayRouterInterface.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayRouterInterface.php
@@ -15,7 +15,7 @@
  * In addition to implementing the interface, specify 'uses_routes' in the
  * plugin definition.
  */
-interface DisplayRouterInterface {
+interface DisplayRouterInterface extends DisplayPluginInterface {
 
   /**
    * Adds the route entry of a view to the collection.
diff --git a/core/modules/views/src/Plugin/views/display/Feed.php b/core/modules/views/src/Plugin/views/display/Feed.php
index 67171ab..268b75a 100644
--- a/core/modules/views/src/Plugin/views/display/Feed.php
+++ b/core/modules/views/src/Plugin/views/display/Feed.php
@@ -268,7 +268,7 @@ public function attachTo(ViewExecutable $clone, $display_id, array &$build) {
     $clone->setDisplay($this->display['id']);
     $clone->buildTitle();
     if ($plugin = $clone->display_handler->getPlugin('style')) {
-      $plugin->attachTo($build, $display_id, $this->getPath(), $clone->getTitle());
+      $plugin->attachTo($build, $display_id, $clone->getTitle());
       foreach ($clone->feedIcons as $feed_icon) {
         $this->view->feedIcons[] = $feed_icon;
       }
diff --git a/core/modules/views/src/Plugin/views/row/RssFields.php b/core/modules/views/src/Plugin/views/row/RssFields.php
index 6d0ae5b..6e7a2bc 100644
--- a/core/modules/views/src/Plugin/views/row/RssFields.php
+++ b/core/modules/views/src/Plugin/views/row/RssFields.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\row;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 
 /**
  * Renders an RSS item based on fields.
@@ -143,7 +144,7 @@ public function render($row) {
     // Create the RSS item object.
     $item = new \stdClass();
     $item->title = $this->getField($row_index, $this->options['title_field']);
-    $item->link = _url($this->getField($row_index, $this->options['link_field']), array('absolute' => TRUE));
+    $item->link = Url::fromUri('user-path:' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString();
     $item->description = $this->getField($row_index, $this->options['description_field']);
     $item->elements = array(
       array('key' => 'pubDate', 'value' => $this->getField($row_index, $this->options['date_field'])),
@@ -157,7 +158,7 @@ public function render($row) {
     $item_guid = $this->getField($row_index, $this->options['guid_field_options']['guid_field']);
     if ($this->options['guid_field_options']['guid_field_is_permalink']) {
       $guid_is_permalink_string = 'true';
-      $item_guid = _url($item_guid, array('absolute' => TRUE));
+      $item_guid = Url::fromUri('user-path:' . $item_guid)->setAbsolute()->toString();
     }
     $item->elements[] = array(
       'key' => 'guid',
diff --git a/core/modules/views/src/Plugin/views/style/Opml.php b/core/modules/views/src/Plugin/views/style/Opml.php
index f41378f..2cbaac7 100644
--- a/core/modules/views/src/Plugin/views/style/Opml.php
+++ b/core/modules/views/src/Plugin/views/style/Opml.php
@@ -32,7 +32,7 @@ class Opml extends StylePluginBase {
   /**
    * {@inheritdoc}
    */
-  public function attachTo(array &$build, $display_id, $path, $title) {
+  public function attachTo(array &$build, $display_id, $title) {
     $display = $this->view->displayHandlers->get($display_id);
     $url_options = array();
     $input = $this->view->getExposedInput();
@@ -41,7 +41,7 @@ public function attachTo(array &$build, $display_id, $path, $title) {
     }
     $url_options['absolute'] = TRUE;
 
-    $url = _url($this->view->getUrl(NULL, $path), $url_options);
+    $url = $this->view->getUrl(NULL, $display_id)->setOptions($url_options)->toString();
     if ($display->hasPath()) {
       if (empty($this->preview)) {
         $build['#attached']['feed'][] = array($url, $title);
diff --git a/core/modules/views/src/Plugin/views/style/Rss.php b/core/modules/views/src/Plugin/views/style/Rss.php
index f597116..f8ac810 100644
--- a/core/modules/views/src/Plugin/views/style/Rss.php
+++ b/core/modules/views/src/Plugin/views/style/Rss.php
@@ -32,7 +32,7 @@ class Rss extends StylePluginBase {
    */
   protected $usesRowPlugin = TRUE;
 
-  public function attachTo(array &$build, $display_id, $path, $title) {
+  public function attachTo(array &$build, $display_id, $title) {
     $url_options = array();
     $input = $this->view->getExposedInput();
     if ($input) {
@@ -40,7 +40,7 @@ public function attachTo(array &$build, $display_id, $path, $title) {
     }
     $url_options['absolute'] = TRUE;
 
-    $url = _url($this->view->getUrl(NULL, $path), $url_options);
+    $url = $this->view->getUrl(NULL, $display_id)->setOptions($url_options)->toString();
 
     // Add the RSS icon to the view.
     $this->view->feedIcons[] = [
diff --git a/core/modules/views/src/Tests/ViewExecutableTest.php b/core/modules/views/src/Tests/ViewExecutableTest.php
index 8492790..c5a1bc4 100644
--- a/core/modules/views/src/Tests/ViewExecutableTest.php
+++ b/core/modules/views/src/Tests/ViewExecutableTest.php
@@ -319,18 +319,6 @@ public function testPropertyMethods() {
     $view->override_path = $override_path;
     $this->assertEqual($view->getPath(), $override_path);
 
-    // Test the getUrl method().
-    $url = 'foo';
-    $this->assertEqual($view->getUrl(NULL, $url), $url);
-    // Test with arguments.
-    $arg1 = 'bar';
-    $arg2 = 12345;
-    $this->assertEqual($view->getUrl(array($arg1, $arg2), $url), "$url/$arg1/$arg2");
-    // Test the override_url property override.
-    $override_url = 'baz';
-    $view->override_url = $override_url;
-    $this->assertEqual($view->getUrl(NULL, $url), $override_url);
-
     // Test the title methods.
     $title = $this->randomString();
     $view->setTitle($title);
diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php
index 64ba659..c6248ec 100644
--- a/core/modules/views/src/ViewExecutable.php
+++ b/core/modules/views/src/ViewExecutable.php
@@ -10,7 +10,9 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Form\FormState;
+use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
 use Drupal\views\Plugin\views\display\DisplayRouterInterface;
 use Drupal\views\Plugin\views\query\QueryPluginBase;
 use Drupal\views\ViewEntityInterface;
@@ -239,9 +241,9 @@ class ViewExecutable {
   /**
    * Allow to override the url of the current view.
    *
-   * @var string
+   * @var \Drupal\Core\Url
    */
-  public $override_url = NULL;
+  public $override_url;
 
   /**
    * Allow to override the path used for generated urls.
@@ -426,6 +428,13 @@ class ViewExecutable {
   protected $viewsData;
 
   /**
+   * The route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface
+   */
+  protected $routeProvider;
+
+  /**
    * Constructs a new ViewExecutable object.
    *
    * @param \Drupal\views\ViewEntityInterface $storage
@@ -434,13 +443,16 @@ class ViewExecutable {
    *   The current user.
    * @param \Drupal\views\ViewsData $views_data
    *   The views data.
+   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
+   *   The route provider.
    */
-  public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data) {
+  public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data, RouteProviderInterface $route_provider) {
     // Reference the storage and the executable to each other.
     $this->storage = $storage;
     $this->storage->set('executable', $this);
     $this->user = $user;
     $this->viewsData = $views_data;
+    $this->routeProvider = $route_provider;
 
     // Add the default css for a view.
     $this->element['#attached']['library'][] = 'views/views.module';
@@ -1696,15 +1708,28 @@ public function buildTitle() {
    * Get the URL for the current view.
    *
    * This URL will be adjusted for arguments.
+   *
+   * @param array $args
+   *   (optional) Passed in arguments.
+   * @param string $display_id
+   *   (optional) Specify the display ID to link to, fallback to the current ID.
+   *
+   * @return \Drupal\Core\Url
    */
-  public function getUrl($args = NULL, $path = NULL) {
+  public function getUrl($args = NULL, $display_id = NULL) {
     if (!empty($this->override_url)) {
       return $this->override_url;
     }
 
+    $display_handler = $this->displayHandlers->get($display_id ?: $this->current_display);
+    if (!$display_handler instanceof DisplayRouterInterface) {
+      throw new \InvalidArgumentException('You cannot create a URL to a display without routes.');
+    }
+
     if (!isset($path)) {
       $path = $this->getPath();
     }
+
     if (!isset($args)) {
       $args = $this->args;
 
@@ -1721,41 +1746,41 @@ public function getUrl($args = NULL, $path = NULL) {
     }
     // Don't bother working if there's nothing to do:
     if (empty($path) || (empty($args) && strpos($path, '%') === FALSE)) {
-      return $path;
+      return $display_handler->getUrlInfo();
     }
 
-    $pieces = array();
     $argument_keys = isset($this->argument) ? array_keys($this->argument) : array();
     $id = current($argument_keys);
-    foreach (explode('/', $path) as $piece) {
-      if ($piece != '%') {
-        $pieces[] = $piece;
-      }
-      else {
-        if (empty($args)) {
-          // Try to never put % in a url; use the wildcard instead.
-          if ($id && !empty($this->argument[$id]->options['exception']['value'])) {
-            $pieces[] = $this->argument[$id]->options['exception']['value'];
-          }
-          else {
-            $pieces[] = '*'; // gotta put something if there just isn't one.
-          }
 
+    /** @var \Drupal\Core\Url $url */
+    $url = $display_handler->getUrlInfo();
+    $route = $this->routeProvider->getRouteByName($url->getRouteName());
+
+    $variables = $route->compile()->getVariables();
+    $parameters = $url->getRouteParameters();
+
+    foreach ($variables as $variable_name) {
+      if (empty($args)) {
+        // Try to never put % in a url; use the wildcard instead.
+        if ($id && !empty($this->argument[$id]->options['exception']['value'])) {
+          $parameters[$variable_name] = $this->argument[$id]->options['exception']['value'];
         }
         else {
-          $pieces[] = array_shift($args);
+          // Gotta put something if there just isn't one.
+          $parameters[$variable_name] = '*';
         }
+      }
+      else {
+        $parameters[$variable_name] = array_shift($args);
+      }
 
-        if ($id) {
-          $id = next($argument_keys);
-        }
+      if ($id) {
+        $id = next($argument_keys);
       }
     }
 
-    if (!empty($args)) {
-      $pieces = array_merge($pieces, $args);
-    }
-    return implode('/', $pieces);
+    $url->setRouteParameters($parameters);
+    return $url;
   }
 
   /**
diff --git a/core/modules/views/src/ViewExecutableFactory.php b/core/modules/views/src/ViewExecutableFactory.php
index 04f6196..0975a48 100644
--- a/core/modules/views/src/ViewExecutableFactory.php
+++ b/core/modules/views/src/ViewExecutableFactory.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views;
 
+use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\ViewEntityInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -38,6 +39,13 @@ class ViewExecutableFactory {
   protected $viewsData;
 
   /**
+   * The route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface
+   */
+  protected $routeProvider;
+
+  /**
    * Constructs a new ViewExecutableFactory
    *
    * @param \Drupal\Core\Session\AccountInterface $user
@@ -46,11 +54,14 @@ class ViewExecutableFactory {
    *   The request stack.
    * @param \Drupal\views\ViewsData $views_data
    *   The views data.
+   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
+   *   The route provider.
    */
-  public function __construct(AccountInterface $user, RequestStack $request_stack, ViewsData $views_data) {
+  public function __construct(AccountInterface $user, RequestStack $request_stack, ViewsData $views_data, RouteProviderInterface $route_provider) {
     $this->user = $user;
     $this->requestStack = $request_stack;
     $this->viewsData = $views_data;
+    $this->routeProvider = $route_provider;
   }
 
   /**
@@ -63,7 +74,7 @@ public function __construct(AccountInterface $user, RequestStack $request_stack,
    *   A ViewExecutable instance.
    */
   public function get(ViewEntityInterface $view) {
-    $view = new ViewExecutable($view, $this->user, $this->viewsData);
+    $view = new ViewExecutable($view, $this->user, $this->viewsData, $this->routeProvider);
     $view->setRequest($this->requestStack->getCurrentRequest());
     return $view;
   }
diff --git a/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php b/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php
index e82468e..17b61c8 100644
--- a/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php
+++ b/core/modules/views/tests/src/Unit/ViewExecutableFactoryTest.php
@@ -54,6 +54,13 @@ class ViewExecutableFactoryTest extends UnitTestCase {
   protected $viewsData;
 
   /**
+   * The mocked route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $routeProvider;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -65,7 +72,8 @@ protected function setUp() {
     $this->viewsData = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
       ->getMock();
-    $this->viewExecutableFactory = new ViewExecutableFactory($this->user, $this->requestStack, $this->viewsData);
+    $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
+    $this->viewExecutableFactory = new ViewExecutableFactory($this->user, $this->requestStack, $this->viewsData, $this->routeProvider);
   }
 
   /**
diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml
index f98ad1c..1a01543 100644
--- a/core/modules/views/views.services.yml
+++ b/core/modules/views/views.services.yml
@@ -64,7 +64,7 @@ services:
     arguments: ['@views.views_data']
   views.executable:
     class: Drupal\views\ViewExecutableFactory
-    arguments: ['@current_user', '@request_stack', '@views.views_data']
+    arguments: ['@current_user', '@request_stack', '@views.views_data', '@router.route_provider']
   views.analyzer:
     class: Drupal\views\Analyzer
     arguments: ['@module_handler']
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 0e70dd4..dc317e2 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -294,6 +294,7 @@ function template_preprocess_views_view_field(&$variables) {
  *   - rows: The raw row data.
  */
 function template_preprocess_views_view_summary(&$variables) {
+  /** @var \Drupal\views\ViewExecutable $view */
   $view = $variables['view'];
   $argument = $view->argument[$view->build_info['summary_level']];
 
@@ -331,11 +332,16 @@ function template_preprocess_views_view_summary(&$variables) {
     $args = $view->args;
     $args[$argument->position] = $row_args[$id];
 
-    $base_path = NULL;
     if (!empty($argument->options['summary_options']['base_path'])) {
       $base_path = $argument->options['summary_options']['base_path'];
+      $tokens = $this->getArgumentsTokens();
+      $base_path = $this->viewsTokenReplace($base_path, $tokens);
+      $url = Url::fromUri('user-path:' . $base_path);
     }
-    $variables['rows'][$id]->url = _url($view->getUrl($args, $base_path), $url_options);
+    else {
+      $url = $view->getUrl($args)->setOptions($url_options);
+    }
+    $variables['rows'][$id]->url = $url->toString();
     $variables['rows'][$id]->count = intval($row->{$argument->count_alias});
     if (isset($active_urls[$variables['rows'][$id]->url])) {
       $variables['rows'][$id]->attributes['class'][] = 'active';
@@ -395,11 +401,16 @@ function template_preprocess_views_view_summary_unformatted(&$variables) {
     $args = $view->args;
     $args[$argument->position] = $row_args[$id];
 
-    $base_path = NULL;
     if (!empty($argument->options['summary_options']['base_path'])) {
       $base_path = $argument->options['summary_options']['base_path'];
+      $tokens = $this->getArgumentsTokens();
+      $base_path = $this->viewsTokenReplace($base_path, $tokens);
+      $url = Url::fromUri('user-path:' . $base_path);
+    }
+    else {
+      $url = $view->getUrl($args)->setOptions($url_options);
     }
-    $variables['rows'][$id]->url = _url($view->getUrl($args, $base_path), $url_options);
+    $variables['rows'][$id]->url = $url->toString();
     $variables['rows'][$id]->count = intval($row->{$argument->count_alias});
     if (isset($active_urls[$variables['rows'][$id]->url])) {
       $variables['rows'][$id]->attributes['class'][] = 'active';
@@ -891,11 +902,11 @@ function template_preprocess_views_view_rss(&$variables) {
   // there isn't one, use the global $base_url
   $link_display_id = $view->display_handler->getLinkDisplay();
   if ($link_display_id && $display = $view->displayHandlers->get($link_display_id)) {
-    $path = $view->displayHandlers->get($link_display_id)->getPath();
+    $url = $view->getUrl(NULL, $link_display_id);
   }
 
-  if ($path) {
-    $path = $view->getUrl(NULL, $path);
+  /** @var \Drupal\Core\Url $url */
+  if ($url) {
     $url_options = array('absolute' => TRUE);
     if (!empty($view->exposed_raw_input)) {
       $url_options['query'] = $view->exposed_raw_input;
@@ -903,11 +914,12 @@ function template_preprocess_views_view_rss(&$variables) {
 
     // Compare the link to the default home page; if it's the default home page,
     // just use $base_url.
-    if ($path == $config->get('page.front')) {
-      $path = '';
+    $url_string = $url->setOptions($url_options)->toString();
+    if ($url_string === Url::fromUri('user-path:' . $config->get('page.front'))) {
+      $url_string = Url::fromRoute('<front>')->setAbsolute()->toString();
     }
 
-    $variables['link'] = check_url(_url($path, $url_options));
+    $variables['link'] = $url_string;
   }
 
   $variables['langcode'] = String::checkPlain(\Drupal::languageManager()->getCurrentLanguage()->getId());
@@ -935,7 +947,7 @@ function template_preprocess_views_view_row_rss(&$variables) {
   $item = $variables['row'];
 
   $variables['title'] = String::checkPlain($item->title);
-  $variables['link'] = check_url($item->link);
+  $variables['link'] = $item->link;
   $variables['description'] = String::checkPlain($item->description);
   $variables['item_elements'] = empty($item->elements) ? '' : format_xml_elements($item->elements);
 }
diff --git a/core/modules/views/views.tokens.inc b/core/modules/views/views.tokens.inc
index 4160d85..85f6ec0 100644
--- a/core/modules/views/views.tokens.inc
+++ b/core/modules/views/views.tokens.inc
@@ -80,6 +80,7 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
   $replacements = array();
 
   if ($type == 'view' && !empty($data['view'])) {
+    /** @var \Drupal\views\ViewExecutable $view */
     $view = $data['view'];
 
     foreach ($tokens as $name => $original) {
@@ -102,8 +103,8 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
           break;
 
         case 'url':
-          if ($path = $view->getUrl()) {
-            $replacements[$original] = _url($path, $url_options);
+          if ($url = $view->getUrl()) {
+            $replacements[$original] = $url->setOptions($url_options)->toString();
           }
           break;
         case 'base-table':
@@ -132,7 +133,7 @@ function views_tokens($type, $tokens, array $data = array(), array $options = ar
     // [view:url:*] nested tokens. This only works if Token module is installed.
     if ($url_tokens = $token_service->findWithPrefix($tokens, 'url')) {
       if ($path = $view->getUrl()) {
-        $replacements += $token_service->generate('url', $url_tokens, array('path' => $path), $options);
+        $replacements += $token_service->generate('url', $url_tokens, array('path' => $url->getInternalPath()), $options);
       }
     }
   }
