From f1aa6b3e1cfeb40e8246fa02290b1829cc9e2292 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Wed, 4 Oct 2017 15:59:17 +0100
Subject: [PATCH] Issue #2810097 by Lendude, larowlan, jp.stacey, Meenakshi
 Gupta, rachel_norfolk, dawehner, alexpott: Allow views to provide the
 canonical entity URL of all entities, not just nodes

---
 core/modules/node/src/NodeViewsData.php       |   8 -
 .../node/src/Plugin/views/field/Path.php      |   4 +
 .../src/Functional/Views/PathPluginTest.php   |   8 +-
 .../config/schema/views.field.schema.yml      |   6 +
 .../src/Plugin/views/field/EntityLink.php     |  43 +++-
 .../Update/EntityLinkOutputUrlUpdateTest.php  |  41 ++++
 .../update/entity-link-output-url.php         |  19 ++
 .../views.view.node_link_update_test.yml      | 226 ++++++++++++++++++
 .../views.view.test_entity_test_link.yml      | 106 ++++++++
 .../Kernel/Handler/FieldEntityLinkTest.php    |  36 ++-
 core/modules/views/views.module               |  38 +++
 core/modules/views/views.post_update.php      |  43 ++++
 12 files changed, 564 insertions(+), 14 deletions(-)
 create mode 100644 core/modules/views/src/Tests/Update/EntityLinkOutputUrlUpdateTest.php
 create mode 100644 core/modules/views/tests/fixtures/update/entity-link-output-url.php
 create mode 100644 core/modules/views/tests/fixtures/update/views.view.node_link_update_test.yml

diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php
index b5aebf48fa22..a122203d6f8f 100644
--- a/core/modules/node/src/NodeViewsData.php
+++ b/core/modules/node/src/NodeViewsData.php
@@ -58,14 +58,6 @@ public function getViewsData() {
     $data['node_field_data']['sticky']['filter']['type'] = 'yes-no';
     $data['node_field_data']['sticky']['sort']['help'] = $this->t('Whether or not the content is sticky. To list sticky content first, set this to descending.');
 
-    $data['node']['path'] = [
-      'field' => [
-        'title' => $this->t('Path'),
-        'help' => $this->t('The aliased path to this content.'),
-        'id' => 'node_path',
-      ],
-    ];
-
     $data['node']['node_bulk_form'] = [
       'title' => $this->t('Node operations bulk form'),
       'help' => $this->t('Add a form element that lets you run operations on multiple nodes.'),
diff --git a/core/modules/node/src/Plugin/views/field/Path.php b/core/modules/node/src/Plugin/views/field/Path.php
index c1c74ab658a7..5e55a4aa78b0 100644
--- a/core/modules/node/src/Plugin/views/field/Path.php
+++ b/core/modules/node/src/Plugin/views/field/Path.php
@@ -1,6 +1,7 @@
 <?php
 
 namespace Drupal\node\Plugin\views\field;
+@trigger_error('Drupal\node\Plugin\views\field\Path is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Use @ViewsField("entity_link") with \'output_url_as_text\' set.', E_USER_DEPRECATED);
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
@@ -14,6 +15,9 @@
  * @ingroup views_field_handlers
  *
  * @ViewsField("node_path")
+ *
+ * @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0.
+ *  Use @ViewsField("entity_link") with 'output_url_as_text' set.
  */
 class Path extends FieldPluginBase {
 
diff --git a/core/modules/node/tests/src/Functional/Views/PathPluginTest.php b/core/modules/node/tests/src/Functional/Views/PathPluginTest.php
index 3cb4e372c9c0..d8d088d978ac 100644
--- a/core/modules/node/tests/src/Functional/Views/PathPluginTest.php
+++ b/core/modules/node/tests/src/Functional/Views/PathPluginTest.php
@@ -58,12 +58,18 @@ protected function setUp($import_test_views = TRUE) {
   }
 
   /**
-   * Tests the node path plugin.
+   * Tests the node path plugin functionality when converted to entity link.
    */
   public function testPathPlugin() {
     /** @var \Drupal\Core\Render\RendererInterface $renderer */
     $renderer = $this->container->get('renderer');
     $view = Views::getView('test_node_path_plugin');
+
+    // The configured deprecated node path plugin should be converted to the
+    // entity link plugin.
+    $field = $view->getHandler('page_1', 'field', 'path');
+    $this->assertEqual('entity_link', $field['plugin_id']);
+
     $view->initDisplay();
     $view->setDisplay('page_1');
     $view->initStyle();
diff --git a/core/modules/views/config/schema/views.field.schema.yml b/core/modules/views/config/schema/views.field.schema.yml
index 562e8ca4d14c..48b6ef8907e5 100644
--- a/core/modules/views/config/schema/views.field.schema.yml
+++ b/core/modules/views/config/schema/views.field.schema.yml
@@ -191,6 +191,12 @@ views.field.entity_link:
     text:
       type: label
       label: 'Text to display'
+    output_url_as_text:
+      type: boolean
+      label: 'Output the URL as text'
+    absolute:
+      type: boolean
+      label: 'Output an absolute link'
 
 views.field.entity_link_delete:
   type: views.field.entity_link
diff --git a/core/modules/views/src/Plugin/views/field/EntityLink.php b/core/modules/views/src/Plugin/views/field/EntityLink.php
index 2cd402cd0070..75b8da394949 100644
--- a/core/modules/views/src/Plugin/views/field/EntityLink.php
+++ b/core/modules/views/src/Plugin/views/field/EntityLink.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -20,12 +21,22 @@ public function render(ResultRow $row) {
     return $this->getEntity($row) ? parent::render($row) : [];
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function renderLink(ResultRow $row) {
+    if ($this->options['output_url_as_text']) {
+      return $this->getUrlInfo($row)->toString();
+    }
+    return parent::renderLink($row);
+  }
+
   /**
    * {@inheritdoc}
    */
   protected function getUrlInfo(ResultRow $row) {
     $template = $this->getEntityLinkTemplate();
-    return $this->getEntity($row)->urlInfo($template);
+    return $this->getEntity($row)->toUrl($template)->setAbsolute($this->options['absolute']);
   }
 
   /**
@@ -45,4 +56,34 @@ protected function getDefaultLabel() {
     return $this->t('view');
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['output_url_as_text'] = ['default' => FALSE];
+    $options['absolute'] = ['default' => FALSE];
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+    $form['output_url_as_text'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Output the URL as text'),
+      '#default_value' => $this->options['output_url_as_text'],
+    ];
+    $form['absolute'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Use absolute link (begins with "http://")'),
+      '#default_value' => $this->options['absolute'],
+      '#description' => $this->t('Enable this option to output an absolute link. Required if you want to use the path as a link destination.'),
+    ];
+    parent::buildOptionsForm($form, $form_state);
+    // Only show the 'text' field if we don't want to output the raw URL.
+    $form['text']['#states']['visible'][':input[name="options[output_url_as_text]"]'] = ['checked' => FALSE];
+  }
+
 }
diff --git a/core/modules/views/src/Tests/Update/EntityLinkOutputUrlUpdateTest.php b/core/modules/views/src/Tests/Update/EntityLinkOutputUrlUpdateTest.php
new file mode 100644
index 000000000000..1e990926fed2
--- /dev/null
+++ b/core/modules/views/src/Tests/Update/EntityLinkOutputUrlUpdateTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\views\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+use Drupal\views\Entity\View;
+
+/**
+ * Tests that the additional settings are added to the entity link field.
+ *
+ * @see views_post_update_entity_link_url()
+ *
+ * @group Update
+ */
+class EntityLinkOutputUrlUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../tests/fixtures/update/entity-link-output-url.php',
+    ];
+  }
+
+  /**
+   * Tests that the additional settings are added to the config.
+   */
+  public function testViewsPostUpdateEntityLinkUrl() {
+    $this->runUpdates();
+
+    // Load and initialize our test view.
+    $view = View::load('node_link_update_test');
+    $data = $view->toArray();
+    // Check that the field contains the new values.
+    $this->assertIdentical(FALSE, $data['display']['default']['display_options']['fields']['view_node']['output_url_as_text']);
+    $this->assertIdentical(FALSE, $data['display']['default']['display_options']['fields']['view_node']['absolute']);
+  }
+
+}
diff --git a/core/modules/views/tests/fixtures/update/entity-link-output-url.php b/core/modules/views/tests/fixtures/update/entity-link-output-url.php
new file mode 100644
index 000000000000..8d2aabeed421
--- /dev/null
+++ b/core/modules/views/tests/fixtures/update/entity-link-output-url.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Test fixture.
+ */
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Serialization\Yaml;
+
+$connection = Database::getConnection();
+
+$connection->insert('config')
+  ->fields([
+    'collection' => '',
+    'name' => 'views.view.node_link_update_test',
+    'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/fixtures/update/views.view.node_link_update_test.yml'))),
+  ])
+  ->execute();
diff --git a/core/modules/views/tests/fixtures/update/views.view.node_link_update_test.yml b/core/modules/views/tests/fixtures/update/views.view.node_link_update_test.yml
new file mode 100644
index 000000000000..ae6eaa86c6b7
--- /dev/null
+++ b/core/modules/views/tests/fixtures/update/views.view.node_link_update_test.yml
@@ -0,0 +1,226 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+    - user
+id: node_link_update_test
+label: 'node link update test'
+module: views
+description: ''
+tag: ''
+base_table: node_field_data
+base_field: nid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: mini
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          tags:
+            previous: ‹‹
+            next: ››
+      style:
+        type: default
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: true
+          uses_fields: false
+      row:
+        type: fields
+        options:
+          inline: {  }
+          separator: ''
+          hide_empty: false
+          default_field_elements: true
+      fields:
+        title:
+          id: title
+          table: node_field_data
+          field: title
+          entity_type: node
+          entity_field: title
+          label: ''
+          alter:
+            alter_text: false
+            make_link: false
+            absolute: false
+            trim: false
+            word_boundary: false
+            ellipsis: false
+            strip_tags: false
+            html: false
+          hide_empty: false
+          empty_zero: false
+          settings:
+            link_to_entity: true
+          plugin_id: field
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exclude: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+        path:
+          id: path
+          table: node
+          field: path
+          entity_type: node
+          plugin_id: node_path
+        view_node:
+          id: view_node
+          table: node
+          field: view_node
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: view
+          entity_type: node
+          plugin_id: entity_link
+      filters:
+        status:
+          value: '1'
+          table: node_field_data
+          field: status
+          plugin_id: boolean
+          entity_type: node
+          entity_field: status
+          id: status
+          expose:
+            operator: ''
+          group: 1
+      sorts:
+        created:
+          id: created
+          table: node_field_data
+          field: created
+          order: DESC
+          entity_type: node
+          entity_field: created
+          plugin_id: date
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exposed: false
+          expose:
+            label: ''
+          granularity: second
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml
index ca151de45bc3..d549ed0a2398 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_test_link.yml
@@ -296,6 +296,112 @@ display:
           text: 'Delete entity test'
           entity_type: entity_test
           plugin_id: entity_link_delete
+        canonical_entity_test:
+          id: canonical_entity_test
+          table: entity_test
+          field: view_entity_test
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: ''
+          output_url_as_text: true
+          absolute: false
+          entity_type: entity_test
+          plugin_id: entity_link
+        absolute_entity_test:
+          id: absolute_entity_test
+          table: entity_test
+          field: view_entity_test
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          text: ''
+          output_url_as_text: true
+          absolute: true
+          entity_type: entity_test
+          plugin_id: entity_link
       filters: {  }
       sorts:
         id:
diff --git a/core/modules/views/tests/src/Kernel/Handler/FieldEntityLinkTest.php b/core/modules/views/tests/src/Kernel/Handler/FieldEntityLinkTest.php
index 874f03d4fccf..a7f5116f35ac 100644
--- a/core/modules/views/tests/src/Kernel/Handler/FieldEntityLinkTest.php
+++ b/core/modules/views/tests/src/Kernel/Handler/FieldEntityLinkTest.php
@@ -67,11 +67,11 @@ protected function setUpFixtures() {
    */
   public function testEntityLink() {
     // Anonymous users cannot see edit/delete links.
-    $expected_results = ['canonical' => TRUE, 'edit-form' => FALSE, 'delete-form' => FALSE];
+    $expected_results = ['canonical' => TRUE, 'edit-form' => FALSE, 'delete-form' => FALSE, 'canonical_raw' => TRUE, 'canonical_raw_absolute' => TRUE];
     $this->doTestEntityLink(\Drupal::currentUser(), $expected_results);
 
     // Admin users cannot see all links.
-    $expected_results = ['canonical' => TRUE, 'edit-form' => TRUE, 'delete-form' => TRUE];
+    $expected_results = ['canonical' => TRUE, 'edit-form' => TRUE, 'delete-form' => TRUE, 'canonical_raw' => TRUE, 'canonical_raw_absolute' => TRUE];
     $this->doTestEntityLink($this->adminUser, $expected_results);
   }
 
@@ -94,16 +94,39 @@ protected function doTestEntityLink(AccountInterface $account, $expected_results
         'label' => 'View entity test',
         'field_id' => 'view_entity_test',
         'destination' => FALSE,
+        'link' => TRUE,
+        'options' => [],
+        'relationship' => 'canonical',
       ],
       'edit-form' => [
         'label' => 'Edit entity test',
         'field_id' => 'edit_entity_test',
         'destination' => TRUE,
+        'link' => TRUE,
+        'options' => [],
+        'relationship' => 'edit-form',
       ],
       'delete-form' => [
         'label' => 'Delete entity test',
         'field_id' => 'delete_entity_test',
         'destination' => TRUE,
+        'link' => TRUE,
+        'options' => [],
+        'relationship' => 'delete-form',
+      ],
+      'canonical_raw' => [
+        'field_id' => 'canonical_entity_test',
+        'destination' => FALSE,
+        'link' => FALSE,
+        'options' => [],
+        'relationship' => 'canonical',
+      ],
+      'canonical_raw_absolute' => [
+        'field_id' => 'absolute_entity_test',
+        'destination' => FALSE,
+        'link' => FALSE,
+        'options' => ['absolute' => TRUE],
+        'relationship' => 'canonical',
       ],
     ];
 
@@ -112,9 +135,14 @@ protected function doTestEntityLink(AccountInterface $account, $expected_results
       foreach ($expected_results as $template => $expected_result) {
         $expected_link = '';
         if ($expected_result) {
-          $path = $entity->url($template);
+          $path = $entity->url($info[$template]['relationship'], $info[$template]['options']);
           $destination = $info[$template]['destination'] ? '?destination=/' : '';
-          $expected_link = '<a href="' . $path . $destination . '" hreflang="en">' . $info[$template]['label'] . '</a>';
+          if ($info[$template]['link']) {
+            $expected_link = '<a href="' . $path . $destination . '" hreflang="en">' . $info[$template]['label'] . '</a>';
+          }
+          else {
+            $expected_link = $path;
+          }
         }
         $link = $view->style_plugin->getField($index, $info[$template]['field_id']);
         $this->assertEqual($link, $expected_link);
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 8b707644d343..f484f1833a84 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -13,6 +13,7 @@
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Drupal\views\Plugin\Derivative\ViewsLocalTask;
+use Drupal\views\ViewEntityInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Entity\View;
 use Drupal\views\Render\ViewsRenderPipelineMarkup;
@@ -861,3 +862,40 @@ function views_view_delete(EntityInterface $entity) {
     }
   }
 }
+
+/**
+ * Implements hook_view_presave().
+ *
+ * Provides a BC layer for modules providing old configurations.
+ */
+function views_view_presave(ViewEntityInterface $view) {
+  $displays = $view->get('display');
+  $changed = FALSE;
+  foreach ($displays as $display_name => &$display) {
+    if (isset($display['display_options']['fields'])) {
+      foreach ($display['display_options']['fields'] as $field_name => &$field) {
+        if (isset($field['plugin_id']) && $field['plugin_id'] === 'entity_link') {
+          // Add any missing settings for entity_link.
+          if (!isset($field['output_url_as_text'])) {
+            $field['output_url_as_text'] = FALSE;
+            $changed = TRUE;
+          }
+          if (!isset($field['absolute'])) {
+            $field['absolute'] = FALSE;
+            $changed = TRUE;
+          }
+        }
+        elseif (isset($field['plugin_id']) && $field['plugin_id'] === 'node_path') {
+          // Convert the use of node_path to entity_link.
+          $field['plugin_id'] = 'entity_link';
+          $field['field'] = 'view_node';
+          $field['output_url_as_text'] = TRUE;
+          $changed = TRUE;
+        }
+      }
+    }
+  }
+  if ($changed) {
+    $view->set('display', $displays);
+  }
+}
diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php
index e09159e7e01c..0f84d7b55a7c 100644
--- a/core/modules/views/views.post_update.php
+++ b/core/modules/views/views.post_update.php
@@ -213,3 +213,46 @@ function views_post_update_revision_metadata_fields() {
     $view->save();
   });
 }
+
+/**
+ * Add additional settings to the entity link field and convert node_path usage
+ * to entity_link.
+ */
+function views_post_update_entity_link_url() {
+  // Load all views.
+  $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
+
+  /* @var \Drupal\views\Entity\View[] $views */
+  foreach ($views as $view) {
+    $displays = $view->get('display');
+    $changed = FALSE;
+    foreach ($displays as $display_name => &$display) {
+      if (isset($display['display_options']['fields'])) {
+        foreach ($display['display_options']['fields'] as $field_name => &$field) {
+          if (isset($field['plugin_id']) && $field['plugin_id'] === 'entity_link') {
+            // Add any missing settings for entity_link.
+            if (!isset($field['output_url_as_text'])) {
+              $field['output_url_as_text'] = FALSE;
+              $changed = TRUE;
+            }
+            if (!isset($field['absolute'])) {
+              $field['absolute'] = FALSE;
+              $changed = TRUE;
+            }
+          }
+          elseif (isset($field['plugin_id']) && $field['plugin_id'] === 'node_path') {
+            // Convert the use of node_path to entity_link.
+            $field['plugin_id'] = 'entity_link';
+            $field['field'] = 'view_node';
+            $field['output_url_as_text'] = TRUE;
+            $changed = TRUE;
+          }
+        }
+      }
+    }
+    if ($changed) {
+      $view->set('display', $displays);
+      $view->save();
+    }
+  }
+}
-- 
GitLab