diff --git a/metatag.module b/metatag.module
index 1c42b85..52e2b09 100644
--- a/metatag.module
+++ b/metatag.module
@@ -259,6 +259,38 @@ function metatag_get_route_entity() {
 }
 
 /**
+ * Returns the display for the view from the current route.
+ *
+ * @return \Drupal\views\Plugin\views\display\DisplayPluginBase|null
+ *  The Display entity for the current view
+ */
+function metatag_get_route_view() {
+  // Get the route name
+  $route_match = \Drupal::routeMatch();
+  $route_name = $route_match->getRouteName();
+
+  // Check if the route name is generated by the view
+  if(strpos($route_name, 'view.') !== FALSE) {
+    // Get basic info about the view
+    $params = $route_match->getParameters();
+    $view_id = $params->get('view_id');
+    $display_id = $params->get('display_id');
+    // If view_id or display_id are not set something is wrong.
+    if(!$view_id || !$display_id) {
+      return NULL;
+    }
+    // Get the view display object for current view and return it.
+    $view = \Drupal\views\Views::getView($view_id);
+    $view->setDisplay($display_id);
+    $display = $view->getDisplay();
+
+    return $display;
+  }
+
+  return NULL;
+}
+
+/**
  * Implements template_preprocess_html().
  */
 function metatag_preprocess_html(&$variables) {
@@ -318,6 +350,28 @@ function metatag_get_tags_from_route() {
     }
   }
 
+  // Check if the Views integration is enabled and find settings for that
+  // @TODO: Might be a good idea to allow modules to hook into this process.
+  if (\Drupal::moduleHandler()->moduleExists('metatag_views')) {
+    // Get the view display from route
+    $display = metatag_get_route_view();
+    if($display) {
+      // And get the list of extenders for this display.
+      $extenders = $display->getExtenders();
+      if (!isset($extenders['metatag_display_extender'])) {
+        // If the id of our plugin is not in the list something is wrong.
+        return;
+      }
+      // Retrieve the settings of our plugins using method from metatag views module
+      $tags = $extenders['metatag_display_extender']->getMetatags();
+      // Account for our future lanuage handling
+      $tags = !empty($tags) ? $tags[\Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED] : array();
+      $metatags = array_merge($metatags, $tags);
+      // Pass the view as the entity.
+      $entity = $display->view;
+    }
+  }
+
   return $metatag_manager->generateElements($metatags, $entity);
 }
 
diff --git a/metatag.services.yml b/metatag.services.yml
index ab98d77..c55377f 100644
--- a/metatag.services.yml
+++ b/metatag.services.yml
@@ -13,4 +13,4 @@ services:
 
   metatag.manager:
     class: Drupal\metatag\MetatagManager
-    arguments: ['@plugin.manager.metatag.group', '@plugin.manager.metatag.tag', '@metatag.token', '@logger.factory']
+    arguments: ['@plugin.manager.metatag.group', '@plugin.manager.metatag.tag', '@metatag.token', '@logger.factory', '@entity_type.manager']
diff --git a/metatag_views/config/schema/metatag_views.views.schema.yml b/metatag_views/config/schema/metatag_views.views.schema.yml
new file mode 100644
index 0000000..a176aae
--- /dev/null
+++ b/metatag_views/config/schema/metatag_views.views.schema.yml
@@ -0,0 +1,2 @@
+views.display_extender.metatag_display_extender:
+  type: views_display_extender
\ No newline at end of file
diff --git a/metatag_views/metatag_views.info.yml b/metatag_views/metatag_views.info.yml
new file mode 100644
index 0000000..398ff2a
--- /dev/null
+++ b/metatag_views/metatag_views.info.yml
@@ -0,0 +1,8 @@
+name: 'Metatag: Views'
+type: module
+description: Provides views integration for metatags.
+core: 8.x
+package: SEO
+dependencies:
+  - metatag
+  - views
diff --git a/metatag_views/metatag_views.install b/metatag_views/metatag_views.install
new file mode 100644
index 0000000..5d57f86
--- /dev/null
+++ b/metatag_views/metatag_views.install
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Implements hook_install().
+ */
+function metatag_views_install() {
+  // Enable metatag_display_extender plugin.
+  $config = \Drupal::service('config.factory')->getEditable('views.settings');
+  $display_extenders = $config->get('display_extenders') ?: array();
+  $display_extenders[] = 'metatag_display_extender';
+  $config->set('display_extenders', $display_extenders);
+  $config->save();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function metatag_views_uninstall() {
+  // Disable metatag_display_extender plugin.
+  $config = \Drupal::service('config.factory')->getEditable('views.settings');
+  $display_extenders = $config->get('display_extenders') ?: array();
+
+  $key = array_search('metatag_display_extender', $display_extenders);
+  if ($key !== FALSE) {
+    unset($display_extenders[$key]);
+    $config->set('display_extenders', $display_extenders);
+    $config->save();
+  }
+}
\ No newline at end of file
diff --git a/metatag_views/metatag_views.links.action.yml b/metatag_views/metatag_views.links.action.yml
new file mode 100644
index 0000000..6c2d4c3
--- /dev/null
+++ b/metatag_views/metatag_views.links.action.yml
@@ -0,0 +1,5 @@
+metatag_views.metatags.add:
+  route_name: 'metatag_views.metatags.add'
+  title: 'Add views meta tags'
+  appears_on:
+    - metatag_views.metatags.list
\ No newline at end of file
diff --git a/metatag_views/metatag_views.links.task.yml b/metatag_views/metatag_views.links.task.yml
new file mode 100644
index 0000000..7261c9a
--- /dev/null
+++ b/metatag_views/metatag_views.links.task.yml
@@ -0,0 +1,9 @@
+metatag_views.defaults:
+  title: 'Defaults'
+  route_name: entity.metatag_defaults.collection
+  base_route: entity.metatag_defaults.collection
+  weight: 0
+metatag_views.tab_views:
+  title: 'Views'
+  route_name: metatag_views.metatags.list
+  base_route: entity.metatag_defaults.collection
\ No newline at end of file
diff --git a/metatag_views/metatag_views.routing.yml b/metatag_views/metatag_views.routing.yml
new file mode 100644
index 0000000..b7a9d3b
--- /dev/null
+++ b/metatag_views/metatag_views.routing.yml
@@ -0,0 +1,59 @@
+metatag_views.metatags.list:
+  path: 'admin/config/search/metatag/views'
+  defaults:
+    _controller: '\Drupal\metatag_views\Controller\MetatagViewsController::listViews'
+    _title: 'Views metatags'
+  requirements:
+    _permission: 'administer meta tags'
+  options:
+    _admin_route: TRUE
+
+metatag_views.metatags.edit:
+  path: 'admin/config/search/metatag/views/{view_id}/{display_id}/edit'
+  defaults:
+    _form: '\Drupal\metatag_views\Form\MetatagViewsEditForm'
+    _title: 'Edit metatags for a view'
+  requirements:
+    _permission: 'administer meta tags'
+  options:
+    _admin_route: TRUE
+
+metatag_views.metatags.translate:
+  path: 'admin/config/search/metatag/views/{view_id}/{display_id}/translate'
+  defaults:
+    _controller: '\Drupal\metatag_views\Controller\MetatagViewsTranslationController::itemPage'
+    _title: 'Translate metatags for a view'
+  requirements:
+    _permission: 'administer meta tags'
+  options:
+    _admin_route: TRUE
+
+metatag_views.metatags.translate_langcode:
+  path: 'admin/config/search/metatag/views/{view_id}/{display_id}/translate/{langcode}'
+  defaults:
+    _form: '\Drupal\metatag_views\Form\MetatagViewsTranslationForm'
+    _title: 'Translate metatags for a view'
+  requirements:
+    _permission: 'administer meta tags'
+  options:
+    _admin_route: TRUE
+
+metatag_views.metatags.revert:
+  path: 'admin/config/search/metatag/views/{view_id}/{display_id}/revert'
+  defaults:
+    _form: '\Drupal\metatag_views\Form\MetatagViewsRevertForm'
+    _title: 'Revert metatags for a view'
+  requirements:
+    _permission: 'administer meta tags'
+  options:
+    _admin_route: TRUE
+
+metatag_views.metatags.add:
+  path: 'admin/config/search/metatag/views/add'
+  defaults:
+    _form: '\Drupal\metatag_views\Form\MetatagViewsAddForm'
+    _title: 'Add metatags for a view'
+  requirements:
+    _permission: 'administer meta tags'
+  options:
+    _admin_route: TRUE
diff --git a/metatag_views/src/Controller/MetatagViewsController.php b/metatag_views/src/Controller/MetatagViewsController.php
new file mode 100644
index 0000000..349a7ab
--- /dev/null
+++ b/metatag_views/src/Controller/MetatagViewsController.php
@@ -0,0 +1,200 @@
+<?php
+
+namespace Drupal\metatag_views\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Url;
+use Drupal\metatag\MetatagManagerInterface;
+use Drupal\metatag_views\Plugin\views\display_extender\MetatagDisplayExtender;
+use Drupal\views\Plugin\views\display\DisplayPluginInterface;
+use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase;
+use Drupal\views\ViewEntityInterface;
+use Drupal\views\ViewExecutable;
+use Drupal\views\Views;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class MetatagViewsController
+ * @package Drupal\metatag_views\Controller
+ */
+class MetatagViewsController extends ControllerBase {
+
+  /** @var EntityStorageInterface  */
+  protected $viewStorage;
+
+  /** @var MetatagManagerInterface  */
+  protected $metatagManager;
+
+  /** @var array  associative array of labels */
+  protected $viewLabels;
+
+  public function __construct(EntityStorageInterface $viewStorage,
+                              MetatagManagerInterface $metatagManager) {
+    $this->viewStorage = $viewStorage;
+    $this->metatagManager = $metatagManager;
+
+    // Generate the labels for views and displays.
+    $this->labels = $this->getViewsAndDisplaysLabels();
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity_type.manager')->getStorage('view'),
+      $container->get('metatag.manager')
+    );
+  }
+
+  /**
+   * Main controller function. Generates the renderable array for views
+   * metatags UI.
+   *
+   * @return array
+   */
+  public function listViews() {
+    // Get metatags for all of the views / displays that have them set.
+    $metataged_views = $this->metatagManager->getMetatagedViews();
+    $elements = [];
+
+    $elements['header'] = [
+      '#markup' => '<p>' . t("To view a list of displays with meta tags set up, click on a view name. To view a summary of meta tags configuration for a particular display, click on the display name. If you need to set metatags for a specific view, choose Add views meta tags. Reverting the meta tags removes the specific configuration and falls back to defaults.") . '</p>',
+    ];
+
+    // Iterate over the values and build the whole UI.
+    // 1. Top level is a collapsible fieldset with a view name (details)
+    // 2. Inside each fieldset we have 2 columns -> Display and Operations.
+    //    Display contains point 3.
+    //    Operations contain edit and revert
+    // 3. In each display there is a table that has 2 columns: tag name and tag
+    //    value.
+    foreach($metataged_views as $view_id => $displays) {
+      $elements[$view_id] = [
+        '#type' => 'details',
+        '#title' => $this->t($this->viewLabels[$view_id]['#label']),
+        'details' => $this->buildViewDetails($view_id, $displays),
+      ];
+    }
+
+    return $elements;
+  }
+
+  /**
+   * Builds the second "level" of the UI - table with display fieldset and operations.
+   *
+   * @param $view_id
+   * @param $displays
+   * @return array
+   */
+  protected function buildViewDetails($view_id, $displays) {
+    $element = [
+      '#type' => 'table',
+      '#collapsible' => TRUE,
+      '#header' => [ $this->t('Display'), $this->t('Operations') ]
+    ];
+
+    foreach($displays as $display_id => $metatags) {
+      $metatags = array_filter($metatags);
+
+      $element[$display_id]['details'] = [
+        '#type' => 'details',
+        '#title' => $this->viewLabels[$view_id][$display_id],
+      ];
+
+      $params = [ 'view_id' => $view_id, 'display_id' => $display_id ];
+
+      // Generate the operations.
+      $element[$display_id]['ops'] = [
+        '#type' => 'operations',
+        '#links' => [
+          'edit' => [
+            'title' => t('Edit'),
+            'url' => Url::fromRoute('metatag_views.metatags.edit', $params),
+          ],
+          'translate' => [
+            'title' => t('Translate'),
+            'url' => Url::fromRoute('metatag_views.metatags.translate', $params),
+          ],
+          'revert' => [
+            'title' => t('Revert'),
+            'url' => Url::fromRoute('metatag_views.metatags.revert', $params),
+          ],
+        ],
+      ];
+
+      // Build the rows for each of the metatag types.
+      $element[$display_id]['details']['table'] = $this->buildDisplayDetailsTable($metatags);
+    }
+
+    return $element;
+  }
+
+  /**
+   * Build the table with metatags values summary.
+   *
+   * @param $tags
+   * @return array
+   */
+  protected function buildDisplayDetailsTable($tags) {
+    $element = [
+      '#type' => 'table',
+    ];
+
+    $i = 0;
+    foreach($tags as $tag_name => $tag_value) {
+      // This is for the case where we have a subarray.
+      $tag_value = $this->prepareTagValue($tag_value);
+      if(!$tag_value) { continue; }
+
+      $element[$i]['tag_name'] = [
+        '#type' => 'markup',
+        '#markup' => $tag_name,
+      ];
+
+      $element[$i]['tag_value'] = [
+        '#type' => 'markup',
+        '#markup' => $tag_value,
+      ];
+      $i++;
+    }
+
+    return $element;
+  }
+
+  /**
+   * Massage the tag value. Returns an imploded string for metatags that
+   * are nested (ex. robots).
+   *
+   * @param $value
+   * @return string
+   */
+  protected function prepareTagValue($value) {
+    if(is_array($value)) {
+      $value = implode(', ', array_filter($value));
+    }
+
+    return $value;
+  }
+
+  /**
+   * Gets label values for the views and their displays.
+   */
+  protected function getViewsAndDisplaysLabels() {
+    /** @var ViewEntityInterface[] $views */
+    $views = $this->viewStorage->loadByProperties(['status' => 1]);
+
+    $labels = [];
+
+    foreach($views as $view_id => $view) {
+      $displays = $view->get('display');
+      $labels[$view_id]['#label'] = $view->get('label');
+      foreach(array_keys($displays) as $display_id) {
+        $labels[$view_id][$display_id] = $displays[$display_id]['display_title'];
+      }
+    }
+
+    $this->viewLabels = $labels;
+  }
+}
\ No newline at end of file
diff --git a/metatag_views/src/Controller/MetatagViewsTranslationController.php b/metatag_views/src/Controller/MetatagViewsTranslationController.php
new file mode 100644
index 0000000..c7b40e2
--- /dev/null
+++ b/metatag_views/src/Controller/MetatagViewsTranslationController.php
@@ -0,0 +1,143 @@
+<?php
+
+namespace Drupal\metatag_views\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Url;
+use Drupal\metatag\MetatagManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class MetatagViewsTranslationController extends ControllerBase {
+
+
+  /** @var EntityStorageInterface  */
+  protected $viewStorage;
+  protected $viewsManager;
+
+  /** @var MetatagManagerInterface */
+  protected $metatagManager;
+
+  /**
+   * The language manager.
+   *
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   */
+  protected $languageManager;
+
+
+  /**
+   * MetatagViewsTranslationController constructor.
+   *
+   * @param EntityStorageInterface $viewStorage
+   * @param MetatagManagerInterface $metatagManager
+   * @param LanguageManagerInterface $languageManager
+   * @param EntityTypeManagerInterface $entity_manager
+   */
+  public function __construct (EntityStorageInterface $viewStorage,
+                               MetatagManagerInterface $metatagManager,
+                               LanguageManagerInterface $languageManager,
+                               EntityTypeManagerInterface $entity_manager)
+  {
+    $this->viewStorage = $viewStorage;
+    $this->metatagManager = $metatagManager;
+    $this->languageManager = $languageManager;
+    $this->viewsManager = $entity_manager->getStorage('view');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create (ContainerInterface $container) {
+    return new static(
+      $container->get('entity_type.manager')->getStorage('view'),
+      $container->get('metatag.manager'),
+      $container->get('language_manager'),
+      $container->get('entity_type.manager')
+    );
+  }
+
+  /**
+   * Language translations overview page for a views.
+   *
+   * @return array
+   *   Page render array.
+   */
+  public function itemPage () {
+
+    $view_id = \Drupal::request()->get('view_id');
+    $display_id = \Drupal::request()->get('display_id');
+
+    $languages = $this->languageManager->getLanguages();
+
+    $original_langcode = $this->languageManager->getDefaultLanguage()->getId();
+    $operations_access = TRUE;
+
+    if (!isset($languages[$original_langcode])) {
+      // If the language is not configured on the site, create a dummy language
+      // object for this listing only to ensure the user gets useful info.
+      $language_name = $this->languageManager->getLanguageName($original_langcode);
+      $languages[$original_langcode] = new Language(array('id' => $original_langcode, 'name' => $language_name));
+    }
+
+    $page['languages'] = array(
+      '#type' => 'table',
+      '#header' => array($this->t('Language'), $this->t('Operations')),
+    );
+
+    $metatags = $this->metatagManager->tagsFromViewDisplay($this->viewsManager->load($view_id), $display_id);
+
+    foreach ($languages as $language) {
+      $langcode = $language->getId();
+
+      // Prepare the language name and the operations depending on whether this
+      // is the original language or not.
+      if ($langcode == $original_langcode) {
+        $language_name = '<strong>' . $this->t('@language (original)', array('@language' => $language->getName())) . '</strong>';
+
+        // Build list of operations.
+        $operations = array();
+        $operations['edit'] = array(
+          'title' => $this->t('Edit'),
+          'url' => Url::fromRoute('metatag_views.metatags.edit', ['view_id' => $view_id, 'display_id' => $display_id]),
+        );
+      } else {
+        $language_name = $language->getName();
+
+        $operations = array();
+        // If no translation exists for this language, link to add one.
+        if (!array_key_exists($langcode, $metatags)) {
+          $operations['add'] = array(
+            'title' => $this->t('Add'),
+            'url' => Url::fromRoute('metatag_views.metatags.translate_langcode', ['view_id' => $view_id, 'display_id' => $display_id, 'langcode' => $langcode]),
+          );
+        }
+        else {
+          // Otherwise, link to edit the existing translation.
+          $operations['edit'] = array(
+            'title' => $this->t('Edit'),
+            'url' => Url::fromRoute('metatag_views.metatags.translate_langcode', ['view_id' => $view_id, 'display_id' => $display_id, 'langcode' => $langcode]),
+          );
+
+          //TODO: operations delete.
+        }
+      }
+
+      $page['languages'][$langcode]['language'] = array(
+        '#markup' => $language_name,
+      );
+
+      $page['languages'][$langcode]['operations'] = array(
+        '#type' => 'operations',
+        '#links' => $operations,
+        // Even if the mapper contains multiple language codes, the source
+        // configuration can still be edited.
+        '#access' => ($langcode == $original_langcode) || $operations_access,
+      );
+    }
+      return $page;
+  }
+}
\ No newline at end of file
diff --git a/metatag_views/src/Form/MetatagViewsAddForm.php b/metatag_views/src/Form/MetatagViewsAddForm.php
new file mode 100644
index 0000000..fc25bea
--- /dev/null
+++ b/metatag_views/src/Form/MetatagViewsAddForm.php
@@ -0,0 +1,158 @@
+<?php
+
+namespace Drupal\metatag_views\Form;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\metatag\MetatagManagerInterface;
+use Drupal\metatag_views\MetatagViewsValuesCleanerTrait;
+use Drupal\views\ViewEntityInterface;
+use Drupal\views\Views;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class MetatagViewsAddForm.
+ *
+ * @package Drupal\metatag_views\Form
+ */
+class MetatagViewsAddForm extends FormBase {
+  use MetatagViewsOptionsSubmitTrait;
+  use MetatagViewsValuesCleanerTrait;
+  /**
+   * Drupal\metatag\MetatagManager definition.
+   *
+   * @var \Drupal\metatag\MetatagManagerInterface
+   */
+  protected $metatagManager;
+
+  /**
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $viewsManager;
+
+
+  public function __construct(
+    MetatagManagerInterface $metatag_manager,
+    EntityTypeManagerInterface $entity_manager
+  ) {
+    $this->metatagManager = $metatag_manager;
+    $this->viewsManager = $entity_manager->getStorage('view');
+  }
+
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('metatag.manager'),
+      $container->get('entity_type.manager')
+    );
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'metatag_views_add_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    // Get views list as options.
+    $in_use = $this->metatagManager->getMetatagedViews();
+    $opts = Views::getViewsAsOptions(FALSE, 'enabled', NULL, TRUE, TRUE);
+    // Get only the views that do not have the metatags set yet.
+    $filtered = $this->filterViewList($in_use, $opts);
+
+    // Build/inject the Metatag form. Use defaults.
+    $metatags = $this->metatagManager->getDefaultMetatags();
+
+    $form['metatags'] = $this->metatagManager->form( $metatags, $form, [ 'view' ] );
+    $form['metatags']['#title'] = t('Metatags');
+    $form['metatags']['#type'] = 'fieldset';
+
+    // Need to create that AFTER the $form['metatags'] as the whole form
+    // is passed to the $metatagManager->form() which causes duplicated field.
+    $form['view'] = [
+      '#type' => 'select',
+      '#options' => $filtered,
+      '#title' => t('Choose a view'),
+      '#weight' => -100,
+    ];
+
+    $form['submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Submit'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * Filters the options array to unset the views that already have metatag
+   * display extender configured.
+   *
+   * @param $used
+   *  Views to exclude
+   * @param $all
+   *  Views to exclude from
+   * @return mixed
+   *  An associative array of views and display ids.
+   */
+  protected function filterViewList($used, $all) {
+    foreach ($used as $view_id => $displays) {
+      foreach(array_keys($displays) as $display_id) {
+        $id = $view_id . ':' . $display_id;
+        if(isset($all[$view_id][$id])) {
+          unset($all[$view_id][$id]);
+        }
+      }
+      if(empty($all[$view_id])) {
+        unset($all[$view_id]);
+      }
+    }
+    return $all;
+  }
+
+  /**
+    * {@inheritdoc}
+    */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    parent::validateForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    // Get the values
+    $metatags = $form_state->getValues();
+    $view_option = $form_state->getValue('view');
+    // Remove the unnecessary entry from values.
+    unset($metatags['view']);
+
+    list($view_id, $display_id) = explode(':', $view_option);
+
+    /** @var ViewEntityInterface $view */
+    $view = $this->viewsManager->load($view_id);
+
+    // Clear the unneeded elements.
+    $metatags = $this->clearMetatagViewsDisallowedValues($metatags);
+
+    // Save the display extender options and the view itself.
+    $this->setMetatagDisplayExtenderValues($view, $display_id, $metatags);
+
+    // Redirect back to the views list.
+    $form_state->setRedirect($this->redirectRoute);
+
+    $display = $view->getDisplay($display_id);
+
+    $params = [
+      '@view' => $view->get('label'),
+      '@display' => $display['display_title']
+    ];
+
+    drupal_set_message($this->t('Metatags for @view : @display have been added.', $params));
+  }
+}
diff --git a/metatag_views/src/Form/MetatagViewsEditForm.php b/metatag_views/src/Form/MetatagViewsEditForm.php
new file mode 100644
index 0000000..fde9d8d
--- /dev/null
+++ b/metatag_views/src/Form/MetatagViewsEditForm.php
@@ -0,0 +1,178 @@
+<?php
+
+namespace Drupal\metatag_views\Form;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\metatag\MetatagManagerInterface;
+use Drupal\metatag_views\MetatagViewsValuesCleanerTrait;
+use Drupal\views\ViewEntityInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class MetatagViewsEditForm.
+ *
+ * @package Drupal\metatag_views\Form
+ */
+class MetatagViewsEditForm extends FormBase {
+  use MetatagViewsOptionsSubmitTrait;
+  use MetatagViewsValuesCleanerTrait;
+
+  /**
+   * Drupal\metatag\MetatagManager definition.
+   *
+   * @var \Drupal\metatag\MetatagManager
+   */
+  protected $metatagManager;
+
+  /**
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $viewsManager;
+
+  /**
+   * Array of display settings as returned from getDisplay of ViewEntityInterface
+   *
+   * @var  array
+   */
+  protected $display;
+
+  /**
+   * View entity object
+   *
+   * @var  ViewEntityInterface
+   */
+  protected $view;
+
+  public function __construct(
+    MetatagManagerInterface $metatag_manager,
+    EntityTypeManagerInterface $entity_manager
+  ) {
+    $this->metatagManager = $metatag_manager;
+    $this->viewsManager = $entity_manager->getStorage('view');
+  }
+
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('metatag.manager'),
+      $container->get('entity_type.manager')
+    );
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'metatag_views_edit_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    // Get the parameters from request.
+    $view_id = \Drupal::request()->get('view_id');
+    $display_id = \Drupal::request()->get('display_id');
+
+    $metatags = [];
+
+    /** @var ViewEntityInterface $view */
+    $this->view = $this->viewsManager->load($view_id);
+    // Array representing the display settings.
+    $this->display = $this->view->getDisplay($display_id);
+
+    // Get metatags from the view entity.
+    $metatags = $this->metatagManager->tagsFromViewDisplay($this->view, $display_id);
+
+    $form['metatags'] = $this->metatagManager->form( $metatags, $form, ['view'] );
+    $form['metatags']['#title'] = t('Metatags');
+    $form['metatags']['#type'] = 'fieldset';
+
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Submit'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $values, array $element, array $token_types = [], array $included_groups = NULL, array $included_tags = NULL) {
+
+    // Add the outer fieldset.
+    $element += [
+      '#type' => 'details',
+    ];
+
+    $element += $this->tokenService->tokenBrowser($token_types);
+
+    $groups_and_tags = $this->sortedGroupsWithTags();
+
+    $first = TRUE;
+    foreach ($groups_and_tags as $group_id => $group) {
+      // Only act on groups that have tags and are in the list of included
+      // groups (unless that list is null).
+      if (isset($group['tags']) && (is_null($included_groups) || in_array($group_id, $included_groups))) {
+        // Create the fieldset.
+        $element[$group_id]['#type'] = 'details';
+        $element[$group_id]['#title'] = $group['label'];
+        $element[$group_id]['#description'] = $group['description'];
+        $element[$group_id]['#open'] = $first;
+        $first = FALSE;
+
+        foreach ($group['tags'] as $tag_id => $tag) {
+          // Only act on tags in the included tags list, unless that is null.
+          if (is_null($included_tags) || in_array($tag_id, $included_tags)) {
+            // Make an instance of the tag.
+            $tag = $this->tagPluginManager->createInstance($tag_id);
+
+            // Set the value to the stored value, if any.
+            $tag_value = isset($values[$tag_id]) ? $values[$tag_id] : NULL;
+            $tag->setValue($tag_value);
+
+            // Create the bit of form for this tag.
+            $element[$group_id][$tag_id] = $tag->form($element);
+          }
+        }
+      }
+    }
+
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    parent::validateForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    // Get the values.
+    $metatags = $form_state->getValues();
+
+    // Clear the unneeded elements.
+    $metatags = $this->clearMetatagViewsDisallowedValues($metatags);
+
+    // Save the display extender options and the view itself.
+    $this->setMetatagDisplayExtenderValues($this->view, $this->display['id'], $metatags);
+
+    // Redirect back to the views list.
+    $form_state->setRedirect($this->redirectRoute);
+
+    $params = [
+      '@view' => $this->view->get('label'),
+      '@display' => $this->display['display_title']
+    ];
+
+    drupal_set_message($this->t('Metatags for @view : @display have been updated.', $params));
+  }
+
+}
diff --git a/metatag_views/src/Form/MetatagViewsOptionsSubmitTrait.php b/metatag_views/src/Form/MetatagViewsOptionsSubmitTrait.php
new file mode 100644
index 0000000..d8da865
--- /dev/null
+++ b/metatag_views/src/Form/MetatagViewsOptionsSubmitTrait.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\metatag_views\Form;
+
+use Drupal\views\ViewEntityInterface;
+
+
+trait MetatagViewsOptionsSubmitTrait {
+  // Default route to redirect after the form submission.
+  protected $redirectRoute = 'metatag_views.metatags.list';
+
+  /**
+   * Sets the metatag display extender options. Unsets if NULL
+   *
+   * @param ViewEntityInterface $view
+   *  View object to act upon.
+   * @param $display_id
+   *  Display id to set / reset.
+   * @param array|null $values
+   *  Values to set. Unsets the values if NULL given.
+   */
+  public function setMetatagDisplayExtenderValues(ViewEntityInterface $view, $display_id, $values = NULL) {
+    /** @var array $displays An array of displays */
+    $displays = $view->get('display');
+    // Set proper values for the display extender.
+    $element = is_null($values) ? [] : [ 'metatags' => $values ];
+
+    $element['metatags'] = array_merge($displays[$display_id]['display_options']['display_extenders']['metatag_display_extender']['metatags'], $element['metatags']);
+
+    $displays[$display_id]['display_options']['display_extenders']['metatag_display_extender'] = $element;
+
+    // Set the displays back to the view
+    $view->set('display', $displays);
+    // Save the views.
+    $view->save();
+  }
+}
\ No newline at end of file
diff --git a/metatag_views/src/Form/MetatagViewsRevertForm.php b/metatag_views/src/Form/MetatagViewsRevertForm.php
new file mode 100644
index 0000000..5f1ba6b
--- /dev/null
+++ b/metatag_views/src/Form/MetatagViewsRevertForm.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace Drupal\metatag_views\Form;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+use Drupal\views\ViewEntityInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines a confirmation form for deleting mymodule data.
+ */
+class MetatagViewsRevertForm extends ConfirmFormBase {
+  use MetatagViewsOptionsSubmitTrait;
+  /**
+   * Entity manager for views entities.
+   *
+   * @var EntityTypeManagerInterface
+   */
+  protected $viewsManager;
+
+  protected $view;
+  protected $display;
+
+  public function __construct(
+    EntityTypeManagerInterface $entity_manager
+  ) {
+    $this->viewsManager = $entity_manager->getStorage('view');
+  }
+
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity_type.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'metatag_views_revert_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return $this->t('Do you want to revert metatags for @view_name : @display_name?',
+      [ '@view_name' => $this->view->label(),
+        '@display_name' => $this->display['display_title']
+      ]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    return new Url('metatag_views.metatags.list');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->t('This reverts the override metatags for a selected view. This action cannot be undone.');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return $this->t('Revert');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelText() {
+    return $this->t('Forget it');
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @param int $id
+   *   (optional) The ID of the item to be deleted.
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, $view_id = NULL, $display_id = NUL) {
+    /** @var ViewEntityInterface view */
+    $this->view = $this->viewsManager->load($view_id);
+    /** @var array display */
+    $this->display = $this->view->getDisplay($display_id);
+
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    // Call set function in a reset mode (explicitly set the third argument to NULL).
+    $this->setMetatagDisplayExtenderValues($this->view, $this->display['id'], NULL);
+
+    // Redirect back to the views list.
+    $form_state->setRedirect($this->redirectRoute);
+
+    drupal_set_message($this->t('Reverted metatags for @view_name : @display_name',
+      [ '@view_name' => $this->view->label(),
+        '@display_name' => $this->display['display_title']
+      ]));
+  }
+
+}
diff --git a/metatag_views/src/Form/MetatagViewsTranslationForm.php b/metatag_views/src/Form/MetatagViewsTranslationForm.php
new file mode 100644
index 0000000..9558641
--- /dev/null
+++ b/metatag_views/src/Form/MetatagViewsTranslationForm.php
@@ -0,0 +1,200 @@
+<?php
+
+namespace Drupal\metatag_views\Form;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\metatag\MetatagManagerInterface;
+use Drupal\metatag\MetatagTagPluginManager;
+use Drupal\metatag\MetatagToken;
+use Drupal\metatag_views\MetatagViewsValuesCleanerTrait;
+use Drupal\views\ViewEntityInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Class MetatagViewsEditForm.
+ *
+ * @package Drupal\metatag_views\Form
+ */
+class MetatagViewsTranslationForm extends FormBase {
+  use MetatagViewsOptionsSubmitTrait;
+  use MetatagViewsValuesCleanerTrait;
+
+  /**
+   * Drupal\metatag\MetatagManager definition.
+   *
+   * @var \Drupal\metatag\MetatagManager
+   */
+  protected $metatagManager;
+
+  /**
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $viewsManager;
+
+  /**
+   * Array of display settings as returned from getDisplay of ViewEntityInterface
+   *
+   * @var  array
+   */
+  protected $display;
+
+  protected $tokenService;
+
+  protected $tagPluginManager;
+
+  /**
+   * View entity object
+   *
+   * @var  ViewEntityInterface
+   */
+  protected $view;
+
+  public function __construct(
+    MetatagManagerInterface $metatag_manager,
+    EntityTypeManagerInterface $entity_manager,
+    MetatagToken $token,
+    MetatagTagPluginManager $tagPluginManager
+  ) {
+    $this->metatagManager = $metatag_manager;
+    $this->viewsManager = $entity_manager->getStorage('view');
+    $this->tokenService = $token;
+    $this->tagPluginManager = $tagPluginManager;
+  }
+
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('metatag.manager'),
+      $container->get('entity_type.manager'),
+      $container->get('metatag.token'),
+      $container->get('plugin.manager.metatag.tag')
+    );
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'metatag_views_translate_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    // Get the parameters from request.
+    $view_id = \Drupal::request()->get('view_id');
+    $display_id = \Drupal::request()->get('display_id');
+    $langcode = \Drupal::request()->get('langcode');
+
+    /** @var ViewEntityInterface $view */
+    $this->view = $this->viewsManager->load($view_id);
+    // Array representing the display settings.
+    $this->display = $this->view->getDisplay($display_id);
+
+    // Get metatags from the view entity.
+    $metatags = $this->metatagManager->tagsFromViewDisplay($this->view, $display_id);
+
+    $metatags = array_filter($metatags, function($value) {
+      if(is_array($value)) {
+        return count(array_filter($value)) > 0;
+      }
+      else {
+        return $value !== '';
+      }
+    });
+    $form['#tree'] = TRUE;
+    $form['#attached']['library'][] = 'config_translation/drupal.config_translation.admin';
+
+    $form['metatags'] = $this->form($metatags, $form, ['view'], $langcode );
+    $form['metatags']['#title'] = t('Metatags');
+    $form['metatags']['#type'] = 'fieldset';
+
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Submit'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $values, array $element, array $token_types = [], $langcode) {
+    $translation = $values[$langcode];
+    $values = $this->clearMetatagViewsDisallowedValues($values);
+
+    // Add the outer fieldset.
+    $element += [
+      '#type' => 'details',
+    ];
+
+    $element += $this->tokenService->tokenBrowser($token_types);
+
+    foreach ($values as $tag_id => $value) {
+      $tag = $this->tagPluginManager->createInstance($tag_id);
+
+      $tag->setValue($translation[$tag_id]);
+
+      $form_element = $tag->form($element);
+
+      $element[$tag_id] = [
+        '#theme' => 'config_translation_manage_form_element',
+        'source' => [
+          '#type' => 'item',
+          '#title' => $form_element['#title'],
+          '#markup' => $value
+        ],
+        'translation' => $form_element,
+      ];
+    }
+
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    parent::validateForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    //Get langcode for object
+    $langcode = \Drupal::request()->get('langcode');
+
+    //Params for redirect
+    $view_id = \Drupal::request()->get('view_id');
+    $display_id = \Drupal::request()->get('display_id');
+
+    // Get the values of metatags.
+    $metatags_values = $form_state->getValue('metatags');
+
+    $metatags = [];
+
+    //Array of metatags translations.
+    foreach($metatags_values as $key => $value) {
+      $metatags[$key] = $value['translation'];
+    }
+
+    // Save the display extender options and the view itself.
+    $this->setMetatagDisplayExtenderValues($this->view, $this->display['id'], [$langcode => $metatags]);
+
+    // Redirect back to the views list.
+    $form_state->setRedirect('metatag_views.metatags.translate', ['view_id' => $view_id, 'display_id' => $display_id]);
+
+    $params = [
+      '@view' => $this->view->get('label'),
+      '@display' => $this->display['display_title']
+    ];
+
+    drupal_set_message($this->t('Metatags for @view : @display have been updated.', $params));
+  }
+
+}
diff --git a/metatag_views/src/MetatagViewsValuesCleanerTrait.php b/metatag_views/src/MetatagViewsValuesCleanerTrait.php
new file mode 100644
index 0000000..e4eb1af
--- /dev/null
+++ b/metatag_views/src/MetatagViewsValuesCleanerTrait.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\metatag_views;
+
+use Drupal\views\ViewEntityInterface;
+
+
+trait MetatagViewsValuesCleanerTrait {
+  /**
+   * Clears the metatag form state values from illegal elements.
+   *
+   * @param array $metatags
+   *  Array of values to submit.
+   *
+   * @return array
+   *  Filtered metatg array.
+   */
+  public function clearMetatagViewsDisallowedValues($metatags) {
+    // Get all legal tags.
+    $tags = $this->metatagManager->sortedTags();
+
+    // Return only common elements.
+    $metatags = array_intersect_key($metatags, $tags);
+
+    return $metatags;
+  }
+
+  public function clearMetatagViewsDisallowedTranslationValues($metatags, $langcode) {
+    // Get all legal tags.
+    $tags = $this->metatagManager->sortedTags();
+
+    // Return only common elements.
+    $metatags = array_intersect_key($metatags[$langcode], $tags);
+
+    return $metatags;
+  }
+}
\ No newline at end of file
diff --git a/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php b/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php
new file mode 100644
index 0000000..4308966
--- /dev/null
+++ b/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\metatag_views\Plugin\views\display_extender\MetatagDisplayExtender.
+ */
+
+namespace Drupal\metatag_views\Plugin\views\display_extender;
+
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\metatag\MetatagManagerInterface;
+use Drupal\metatag_views\MetatagViewsValuesCleanerTrait;
+use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Metatag display extender plugin.
+ *
+ * @ingroup views_display_extender_plugins
+ *
+ * @ViewsDisplayExtender(
+ *   id = "metatag_display_extender",
+ *   title = @Translation("Metatag display extender"),
+ *   help = @Translation("Metatag settings for this view."),
+ *   no_ui = FALSE
+ * )
+ */
+class MetatagDisplayExtender extends DisplayExtenderPluginBase {
+  use MetatagViewsValuesCleanerTrait;
+  /** @var  MetatagManagerInterface */
+  protected $metatagManager;
+
+  /**
+   * Provide a form to edit options for this plugin.
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+
+    if ($form_state->get('section') == 'metatags') {
+      $form['#title'] .= t('The meta tags for this display');
+      $metatags = $this->getMetatags();
+      $metatags = !empty($metatags) ? $metatags[LanguageInterface::LANGCODE_NOT_SPECIFIED] : array();
+
+      // Build/inject the Metatag form.
+      $this->metatagManager = \Drupal::service('metatag.manager');
+      $form['metatags'] = $this->metatagManager->form( $metatags, $form, [ 'view' ] );
+    }
+  }
+
+  /**
+   * Validate the options form.
+   */
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
+  }
+
+  /**
+   * Handle any special handling on the validate form.
+   */
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
+    if ($form_state->get('section') == 'metatags') {
+      $metatags = $form_state->getValues();
+      // Remove the unnecessary elements from values array.
+      $metatags = $this->clearMetatagViewsDisallowedValues($metatags);
+      $this->options['metatags'] = $metatags;
+    }
+  }
+
+  /**
+   * Set up any variables on the view prior to execution.
+   */
+  public function preExecute() {
+  }
+
+  /**
+   * Inject anything into the query that the display_extender handler needs.
+   */
+  public function query() {
+  }
+
+  /**
+   * Provide the default summary for options in the views UI.
+   *
+   * This output is returned as an array.
+   */
+  public function optionsSummary(&$categories, &$options) {
+    $categories['metatags'] = array(
+      'title' => t('Meta tags'),
+      'column' => 'second',
+    );
+    $options['metatags'] = array(
+      'category' => 'metatags',
+      'title' => t('Meta tags'),
+      'value' => $this->hasMetatags() ? t('Overridden') : t('Using defaults'),
+    );
+  }
+
+  /**
+   * Static member function to list which sections are defaultable
+   * and what items each section contains.
+   */
+  public function defaultableSections(&$sections, $section = NULL) {
+  }
+
+  /**
+   * Identify whether or not the current display has custom meta tags defined.
+   */
+  protected function hasMetatags() {
+    $metatags = $this->getMetatags();
+    return !empty($metatags[LanguageInterface::LANGCODE_NOT_SPECIFIED]);
+
+  }
+
+  /**
+   * Get the Metatag configuration for this display.
+   *
+   * @return array
+   *   The meta tag values, keys by language (default LanguageInterface::LANGCODE_NOT_SPECIFIED).
+   */
+  public function getMetatags($language = NULL) {
+    $metatags = $this->options['metatags'];
+
+    $language = is_null($language) ? LanguageInterface::LANGCODE_NOT_SPECIFIED : $language;
+    // Leave some possibility for future versions to support translation.
+    if (empty($metatags)) {
+      $metatags = array($language => array());
+    }
+    if (!isset($metatags[$language])) {
+      $metatags = array($language => $metatags);
+    }
+
+    return $metatags;
+  }
+
+  public function setMetatags($metatags) {
+    $this->options['metatags'] = $metatags;
+  }
+}
diff --git a/metatag_views/templates/config_translation_manage_form_element.html.twig b/metatag_views/templates/config_translation_manage_form_element.html.twig
new file mode 100644
index 0000000..4c1459b
--- /dev/null
+++ b/metatag_views/templates/config_translation_manage_form_element.html.twig
@@ -0,0 +1,23 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a form element in config_translation.
+ *
+ * Available variables:
+ * - element: Array that represents the element shown in the form.
+ *   - source: The source of the translation.
+ *   - translation: The translation for the target language.
+ *
+ * @see template_preprocess()
+ *
+ * @ingroup themeable
+ */
+#}
+<div class="translation-set clearfix">
+  <div class="layout-column layout-column--half translation-set__source">
+    {{ element.source }}
+  </div>
+  <div class="layout-column layout-column--half translation-set__translated">
+    {{ element.translation }}
+  </div>
+</div>
diff --git a/src/MetatagManager.php b/src/MetatagManager.php
index 9123713..8844ed0 100644
--- a/src/MetatagManager.php
+++ b/src/MetatagManager.php
@@ -4,9 +4,12 @@ namespace Drupal\metatag;
 
 use Drupal\Component\Render\PlainTextOutput;
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\field\Entity\FieldConfig;
+use Drupal\views\ViewEntityInterface;
+use Drupal\views\ViewExecutable;
 
 /**
  * Class MetatagManager.
@@ -17,6 +20,8 @@ class MetatagManager implements MetatagManagerInterface {
 
   protected $groupPluginManager;
   protected $tagPluginManager;
+  protected $defaultMetatagsManager;
+  protected $viewStorage;
 
   protected $tokenService;
 
@@ -34,13 +39,17 @@ class MetatagManager implements MetatagManagerInterface {
    * @param MetatagTagPluginManager $tagPluginManager
    * @param MetatagToken $token
    * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $channelFactory
+   * @param EntityTypeManagerInterface $entityTypeManager
    */
   public function __construct(MetatagGroupPluginManager $groupPluginManager,
                               MetatagTagPluginManager $tagPluginManager,
                               MetatagToken $token,
-                              LoggerChannelFactoryInterface $channelFactory) {
+                              LoggerChannelFactoryInterface $channelFactory,
+                              EntityTypeManagerInterface $entityTypeManager) {
     $this->groupPluginManager = $groupPluginManager;
     $this->tagPluginManager = $tagPluginManager;
+    $this->defaultMetatagsManager = $entityTypeManager->getStorage('metatag_defaults');
+    $this->viewStorage = $entityTypeManager->getStorage('view');
     $this->tokenService = $token;
     $this->logger = $channelFactory->get('metatag');
   }
@@ -63,6 +72,53 @@ class MetatagManager implements MetatagManagerInterface {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function tagsFromViewDisplay(ViewEntityInterface $view, $display_id = NULL) {
+    $tags = [];
+
+    if(is_null($display_id)) {
+      $displays = $view->get('display');
+      foreach(array_keys($displays) as $display_id) {
+        $metatags = $this->tagsFromViewDisplay($view, $display_id);
+        if(!empty($metatags)) {
+          $tags[$display_id] = $metatags;
+        }
+      }
+      return $tags;
+    }
+
+    $display = $view->getDisplay($display_id);
+    $tags = isset($display['display_options']['display_extenders']['metatag_display_extender']['metatags']) ? $display['display_options']['display_extenders']['metatag_display_extender']['metatags'] : NULL;
+
+    return $tags;
+  }
+
+  /**
+   * This returns metatag values for each view id and display id.
+   *
+   * @return array - associative array of metatags keyed by display id
+   */
+  public function getMetatagedViews() {
+    /** @var ViewEntityInterface[] $views */
+    $views = $this->viewStorage->loadByProperties(['status' => 1]);
+
+    $metataged_views = [];
+
+    // Iterate over views and get metatags for each of them creating array
+    // where the values are not empty.
+    foreach($views as $view_id => $view) {
+      $tags = $this->tagsFromViewDisplay($view);
+      if(empty($tags)) {
+        continue;
+      }
+      $metataged_views[$view_id] = $tags;
+    }
+
+    return $metataged_views;
+  }
+
+  /**
    * Gets the group plugin definitions.
    *
    * @return array
@@ -207,6 +263,8 @@ class MetatagManager implements MetatagManagerInterface {
     return $element;
   }
 
+
+
   /**
    * Returns a list of the metatag fields on an entity.
    */
@@ -254,6 +312,77 @@ class MetatagManager implements MetatagManagerInterface {
     return $tags;
   }
 
+  public function getDefaultMetatags(ContentEntityInterface $entity = NULL) {
+    // Get general global metatags
+    $metatags = $this->getGlobalMetatags();
+    // If that is empty something went wrong.
+    if (!$metatags) {
+      return;
+    }
+
+    // Check if this is a special page.
+    $special_metatags = $this->getSpecialMetatags();
+
+    // Merge with all globals defaults.
+    if ($special_metatags) {
+      $metatags->set('tags', array_merge($metatags->get('tags'), $special_metatags->get('tags')));
+    }
+    // Next check if there is this page is an entity that has meta tags.
+    // @TODO: Think about using other defaults - ex. views. Maybe utilize plugins?
+    else {
+      if(is_null($entity)) {
+        $entity = metatag_get_route_entity();
+      }
+
+      if (!empty($entity)) {
+        // Get default metatags for a given entity.
+        $entity_defaults = $this->getEntityDefaultMetatags($entity);
+        if($entity_defaults != NULL) {
+          $metatags->set('tags', array_merge($metatags->get('tags'), $entity_defaults));
+        }
+      }
+    }
+
+    return $metatags->get('tags');
+  }
+
+  public function getGlobalMetatags() {
+    return $this->defaultMetatagsManager->load('global');
+  }
+
+  public function getSpecialMetatags() {
+    if (\Drupal::service('path.matcher')->isFrontPage()) {
+      return $this->defaultMetatagsManager->load('front');
+    }
+    elseif (\Drupal::service('current_route_match')->getRouteName() == 'system.403') {
+      return $this->defaultMetatagsManager->load('403');
+    }
+    elseif (\Drupal::service('current_route_match')->getRouteName() == 'system.404') {
+      return $this->defaultMetatagsManager->load('404');
+    }
+
+    return;
+  }
+
+
+  public function getEntityDefaultMetatags(ContentEntityInterface $entity) {
+    $entity_metatags = $this->defaultMetatagsManager->load($entity->getEntityTypeId());
+    $metatags = [];
+    if ($entity_metatags != NULL) {
+      // Merge with global defaults.
+      $metatags = array_merge($metatags, $entity_metatags->get('tags'));
+    }
+
+    // Finally, check if we should apply bundle overrides.
+    $bundle_metatags = $this->defaultMetatagsManager->load($entity->getEntityTypeId() . '__' . $entity->bundle());
+    if ($bundle_metatags != NULL) {
+      // Merge with existing defaults.
+      $metatags = array_merge($metatags, $bundle_metatags->get('tags'));
+    }
+
+    return $metatags;
+  }
+
   /**
    * Generate the elements that go in the attached array in
    * hook_page_attachments.
@@ -266,9 +395,28 @@ class MetatagManager implements MetatagManagerInterface {
    *   Render array with tag elements.
    */
   public function generateElements($tags, $entity = NULL) {
-    $metatag_tags = $this->tagPluginManager->getDefinitions();
     $elements = [];
 
+    $tags = $this->generateRawElements($tags, $entity);
+
+    foreach($tags as $name => $tag) {
+      if (!empty($tag)) {
+        $elements['#attached']['html_head'][] = [
+          $tag,
+          $name
+        ];
+      }
+
+    }
+
+    return $elements;
+  }
+
+  public function generateRawElements($tags, $entity = NULL) {
+    $metatag_tags = $this->tagPluginManager->getDefinitions();
+
+    $rawTags = [];
+
     // Each element of the $values array is a tag with the tag plugin name
     // as the key.
     foreach ($tags as $tag_name => $value) {
@@ -280,7 +428,15 @@ class MetatagManager implements MetatagManagerInterface {
         // Render any tokens in the value.
         $token_replacements = [];
         if ($entity) {
-          $token_replacements = [$entity->getEntityTypeId() => $entity];
+          // Check if our entity is a view and react appropriately.
+          // @TODO: Probably this needs a better way of discovering the context
+          // @TODO: This should be an EntityConfigInterface actually...
+          if($entity instanceof ViewExecutable) {
+            $token_replacements = ['view' => $entity];
+          }
+          else {
+            $token_replacements = [$entity->getEntityTypeId() => $entity];
+          }
         }
 
         // Set the value as sometimes the data needs massaging, such as when
@@ -289,6 +445,7 @@ class MetatagManager implements MetatagManagerInterface {
         // @see @Robots::setValue().
         $tag->setValue($value);
         $langcode = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
+
         if ($tag->type() === 'image') {
           $processed_value = $this->tokenService->replace($tag->value(), $token_replacements, ['langcode' => $langcode]);
         }
@@ -302,16 +459,14 @@ class MetatagManager implements MetatagManagerInterface {
         // Have the tag generate the output based on the value we gave it.
         $output = $tag->output();
 
-        if (!empty($output)) {
-          $elements['#attached']['html_head'][] = [
-            $output,
-            $tag_name
-          ];
+        if(!empty($output)) {
+          $rawTags[$tag_name] = $output;
         }
+
       }
     }
 
-    return $elements;
+    return $rawTags;
   }
 
   /**
diff --git a/src/MetatagManagerInterface.php b/src/MetatagManagerInterface.php
index 03aaa2f..ea429f5 100644
--- a/src/MetatagManagerInterface.php
+++ b/src/MetatagManagerInterface.php
@@ -3,6 +3,7 @@
 namespace Drupal\metatag;
 
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\views\ViewEntityInterface;
 
 /**
  * Class MetatagManager.
@@ -23,6 +24,20 @@ interface MetatagManagerInterface {
   public function tagsFromEntity(ContentEntityInterface $entity);
 
   /**
+   * Extracts all tags of a given view.
+   *
+   * @param \Drupal\views\ViewEntityInterface $view
+   *   The view to extract metatags from.
+   * @param string|null $display_id
+   *   The id of the display to extract metatags from.
+   *
+   * @return array
+   *   Array of metatags for a given display id of a view. Array is keyed by
+   *   display_id when null is passed.
+   */
+  public function tagsFromViewDisplay(ViewEntityInterface $view, $display_id = NULL);
+
+  /**
    * Returns an array of group plugin information sorted by weight.
    *
    * @return array
