diff --git a/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml b/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml
index d615b14..bacfa46 100644
--- a/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml
+++ b/core/modules/aggregator/config/optional/views.view.aggregator_sources.yml
@@ -1,6 +1,9 @@
 langcode: en
 status: true
 dependencies:
+  config:
+    - core.entity_view_mode.aggregator_feed.summary
+    - system.menu.tools
   module:
     - aggregator
     - user
@@ -133,6 +136,12 @@ display:
       empty: {  }
       relationships: {  }
       arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+      cacheable: false
   feed_1:
     display_plugin: feed
     id: feed_1
@@ -193,8 +202,21 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
-          display_as_link: false
-          plugin_id: aggregator_title_link
+          click_sort_column: value
+          type: aggregator_title
+          settings:
+            display_as_link: false
+          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
+          plugin_id: field
           entity_type: aggregator_feed
           entity_field: title
         url:
@@ -371,6 +393,12 @@ display:
         default: '0'
       title: 'OPML feed'
       sitename_title: true
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+      cacheable: false
   page_1:
     display_plugin: page
     id: page_1
@@ -385,3 +413,9 @@ display:
         weight: 0
         context: '0'
         menu_name: tools
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+      cacheable: false
diff --git a/core/modules/aggregator/config/schema/aggregator.schema.yml b/core/modules/aggregator/config/schema/aggregator.schema.yml
index 85710b8..eb6c006 100644
--- a/core/modules/aggregator/config/schema/aggregator.schema.yml
+++ b/core/modules/aggregator/config/schema/aggregator.schema.yml
@@ -47,3 +47,11 @@ block.settings.aggregator_feed_block:
     feed:
       type: string
       label: 'Feed'
+
+field.formatter.settings.aggregator_title:
+  type: mapping
+  label: 'Formatter settings'
+  mapping:
+    display_as_link:
+      type: boolean
+      label: 'Display as link'
diff --git a/core/modules/aggregator/config/schema/aggregator.views.schema.yml b/core/modules/aggregator/config/schema/aggregator.views.schema.yml
index 23cc642..b729a5a 100644
--- a/core/modules/aggregator/config/schema/aggregator.views.schema.yml
+++ b/core/modules/aggregator/config/schema/aggregator.views.schema.yml
@@ -8,14 +8,6 @@ views.argument.aggregator_iid:
   type: views.argument.numeric
   label: 'Aggregator item ID'
 
-views.field.aggregator_title_link:
-  type: views_field
-  label: 'Title link'
-  mapping:
-    display_as_link:
-      type: boolean
-      label: 'Display as link'
-
 views.field.aggregator_xss:
   type: views.field.xss
   label: 'Aggregator XSS'
diff --git a/core/modules/aggregator/src/AggregatorFeedViewsData.php b/core/modules/aggregator/src/AggregatorFeedViewsData.php
index 70f8684..baa0d60 100644
--- a/core/modules/aggregator/src/AggregatorFeedViewsData.php
+++ b/core/modules/aggregator/src/AggregatorFeedViewsData.php
@@ -35,7 +35,8 @@ public function getViewsData() {
     $data['aggregator_feed']['fid']['filter']['id'] = 'numeric';
 
     $data['aggregator_feed']['title']['help'] = $this->t('The title of the aggregator feed.');
-    $data['aggregator_feed']['title']['field']['id'] = 'aggregator_title_link';
+    $data['aggregator_feed']['title']['field']['default_formatter'] = 'aggregator_title';
+
     $data['aggregator_feed']['argument']['id'] = 'string';
 
     $data['aggregator_feed']['url']['help'] = $this->t('The fully-qualified URL of the feed.');
diff --git a/core/modules/aggregator/src/AggregatorItemViewsData.php b/core/modules/aggregator/src/AggregatorItemViewsData.php
index 2ab9e21..8059e09 100644
--- a/core/modules/aggregator/src/AggregatorItemViewsData.php
+++ b/core/modules/aggregator/src/AggregatorItemViewsData.php
@@ -28,8 +28,7 @@ public function getViewsData() {
     $data['aggregator_item']['iid']['argument']['numeric'] = TRUE;
 
     $data['aggregator_item']['title']['help'] = $this->t('The title of the aggregator item.');
-    $data['aggregator_item']['title']['field']['id'] = 'aggregator_title_link';
-    $data['aggregator_item']['title']['field']['extra'] = 'link';
+    $data['aggregator_item']['title']['field']['default_formatter'] = 'aggregator_title';
 
     $data['aggregator_item']['link']['help'] = $this->t('The link to the original source URL of the item.');
 
diff --git a/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorTitleFormatter.php b/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorTitleFormatter.php
new file mode 100644
index 0000000..6037bd4
--- /dev/null
+++ b/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorTitleFormatter.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\aggregator\Plugin\Field\FieldFormatter\AggregatorTitleFormatter.
+ */
+
+namespace Drupal\aggregator\Plugin\Field\FieldFormatter;
+
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\FormatterBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+
+/**
+ * Plugin implementation of the 'aggregator_title' formatter.
+ *
+ * @FieldFormatter(
+ *   id = "aggregator_title",
+ *   label = @Translation("Aggregator title"),
+ *   description = @Translation("Formats an aggregator item or feed title with an optional link."),
+ *   field_types = {
+ *     "string"
+ *   }
+ * )
+ */
+class AggregatorTitleFormatter extends FormatterBase {
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    $options = parent::defaultSettings();
+
+    $options['display_as_link'] = TRUE;
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form = parent::settingsForm($form, $form_state);
+
+    $form['display_as_link'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Link to URL'),
+      '#default_value' => $this->getSetting('display_as_link'),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewElements(FieldItemListInterface $items) {
+    $elements = [];
+
+    if ($items->getEntity()->getEntityTypeId() == 'aggregator_feed') {
+      $url_string = $items->getEntity()->getUrl();
+    }
+    else {
+      $url_string = $items->getEntity()->getLink();
+    }
+
+    foreach ($items as $delta => $item) {
+        if ($this->getSetting('display_as_link') && $url_string) {
+          $elements[$delta] = [
+            '#type' => 'link',
+            '#title' => $item->value,
+            '#url' => Url::fromUri($url_string),
+          ];
+        }
+        else {
+          $elements[$delta] = ['#markup' => $item->value];
+        }
+      }
+
+    return $elements;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isApplicable(FieldDefinitionInterface $field_definition) {
+    return ($field_definition->getTargetEntityTypeId() === 'aggregator_item' || $field_definition->getTargetEntityTypeId() === 'aggregator_feed' && $field_definition->getName() === 'title');
+  }
+
+}
diff --git a/core/modules/aggregator/src/Plugin/views/field/TitleLink.php b/core/modules/aggregator/src/Plugin/views/field/TitleLink.php
deleted file mode 100644
index ba05199..0000000
--- a/core/modules/aggregator/src/Plugin/views/field/TitleLink.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\aggregator\Plugin\views\field\TitleLink.
- */
-
-namespace Drupal\aggregator\Plugin\views\field;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
-use Drupal\views\Plugin\views\display\DisplayPluginBase;
-use Drupal\views\Plugin\views\field\FieldPluginBase;
-use Drupal\views\ResultRow;
-use Drupal\views\ViewExecutable;
-
-/**
- * Defines a field handler that turns an item's title into a clickable link.
- *
- * The link refers to the original source article.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("aggregator_title_link")
- */
-class TitleLink extends FieldPluginBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
-    parent::init($view, $display, $options);
-
-    $this->additional_fields['link'] = 'link';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-
-    $options['display_as_link'] = array('default' => TRUE);
-
-    return $options;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
-    $form['display_as_link'] = array(
-      '#title' => $this->t('Display as link'),
-      '#type' => 'checkbox',
-      '#default_value' => !empty($this->options['display_as_link']),
-    );
-    parent::buildOptionsForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render(ResultRow $values) {
-    $value = $this->getValue($values);
-    return $this->renderLink($this->sanitizeValue($value), $values);
-  }
-
-  /**
-   * Renders aggregator item's title as link.
-   *
-   * @param string $data
-   *   The XSS safe string for the link text.
-   * @param \Drupal\views\ResultRow $values
-   *   The values retrieved from a single row of a view's query result.
-   *
-   * @return string
-   *   Returns a string for the link text.
-   */
-  protected function renderLink($data, ResultRow $values) {
-    $link = $this->getValue($values, 'link');
-    if (!empty($this->options['display_as_link'])) {
-      $this->options['alter']['make_link'] = TRUE;
-      // Note: $link is an external URI, pointing to the feed itself.
-      $this->options['alter']['url'] = Url::fromUri($link);
-      $this->options['alter']['html'] = TRUE;
-      $this->options['alter']['absolute'] = TRUE;
-    }
-
-    return $data;
-  }
-
-}
diff --git a/core/modules/aggregator/src/Tests/AggregatorTitleTest.php b/core/modules/aggregator/src/Tests/AggregatorTitleTest.php
new file mode 100644
index 0000000..cfa9975
--- /dev/null
+++ b/core/modules/aggregator/src/Tests/AggregatorTitleTest.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\aggregator\Tests\AggregatorTitleTest.
+ */
+
+namespace Drupal\aggregator\Tests;
+
+use Drupal\aggregator\Entity\Feed;
+use Drupal\aggregator\Entity\Item;
+use Drupal\simpletest\KernelTestBase;
+
+
+/**
+ * Tests the aggregator_title formatter.
+ *
+ * @group field
+ */
+class AggregatorTitleTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('file', 'field', 'options', 'aggregator', 'entity_reference');
+
+  /**
+   * The field name that is tested.
+   *
+   * @var string
+   */
+  protected $fieldName;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installConfig(['field']);
+    $this->installEntitySchema('aggregator_feed');
+    $this->installEntitySchema('aggregator_item');
+
+    $this->fieldName = 'title';
+  }
+
+  /*
+   * Tests the formatter output.
+   */
+  public function testStringFormatter() {
+    // Create an aggregator feed.
+    $aggregator_feed = Feed::create([
+      'title' => 'testing title',
+      'url' => 'http://www.example.com',
+    ]);
+    $aggregator_feed->save();
+
+    // Create an aggregator feed item.
+    $aggregator_item = Item::create([
+      'title' => 'test title',
+      'fid' => $aggregator_feed->id(),
+      'link' => 'http://www.example.com',
+      ]);
+    $aggregator_item->save();
+
+    // Verify aggregator feed title with and without links.
+    $build = $aggregator_feed->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => TRUE]]);
+    $result = $this->render($build);
+
+    $this->assertTrue(strpos($result, 'testing title'));
+    $this->assertTrue(strpos($result, 'href="' . $aggregator_feed->getUrl()) . '"');
+
+    $build = $aggregator_feed->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => FALSE]]);
+    $result = $this->render($build);
+    $this->assertTrue(strpos($result, 'testing title') === 0);
+    $this->assertTrue(strpos($result, $aggregator_feed->getUrl()) === FALSE);
+
+    // Verify aggregator item title with and without links.
+    $build = $aggregator_item->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' =>TRUE]]);
+    $result = $this->render($build);
+
+    $this->assertTrue(strpos($result, 'test title'));
+    $this->assertTrue(strpos($result, 'href="' . $aggregator_item->getLink()) . '"');
+
+    $build = $aggregator_item->{$this->fieldName}->view(['type' => 'aggregator_title', 'settings' => ['display_as_link' => FALSE]]);
+    $result = $this->render($build);
+    $this->assertTrue(strpos($result, 'test title') === 0);
+    $this->assertTrue(strpos($result, $aggregator_item->getLink()) === FALSE);
+  }
+
+}
diff --git a/core/modules/aggregator/tests/modules/aggregator_test_views/test_views/views.view.test_aggregator_items.yml b/core/modules/aggregator/tests/modules/aggregator_test_views/test_views/views.view.test_aggregator_items.yml
index 8e5673f..0a2657b 100644
--- a/core/modules/aggregator/tests/modules/aggregator_test_views/test_views/views.view.test_aggregator_items.yml
+++ b/core/modules/aggregator/tests/modules/aggregator_test_views/test_views/views.view.test_aggregator_items.yml
@@ -44,7 +44,8 @@ display:
           table: aggregator_item
           field: title
           id: title
-          plugin_id: aggregator_title_link
+          plugin_id: field
+          type: aggregator_title
           alter:
             alter_text: false
             text: ''
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml
index e601365..6c631b3 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml
@@ -83,8 +83,21 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
-          display_as_link: false
-          plugin_id: aggregator_title_link
+          click_sort_column: value
+          type: aggregator_title
+          settings:
+            display_as_link: false
+          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
+          plugin_id: field
           entity_type: aggregator_feed
           entity_field: title
         url:
