diff --git a/core/modules/file/config/optional/views.view.files.yml b/core/modules/file/config/optional/views.view.files.yml
index 8a9cdf0..5d83195 100644
--- a/core/modules/file/config/optional/views.view.files.yml
+++ b/core/modules/file/config/optional/views.view.files.yml
@@ -1019,7 +1019,7 @@ display:
             title_enable: false
             title: All
           title_enable: true
-          title: 'File usage information for %1'
+          title: 'File usage information for {{ arguments.fid }}'
           default_argument_type: fixed
           default_argument_options:
             argument: ''
diff --git a/core/modules/node/config/optional/views.view.archive.yml b/core/modules/node/config/optional/views.view.archive.yml
index 56ae50e..c30650b 100644
--- a/core/modules/node/config/optional/views.view.archive.yml
+++ b/core/modules/node/config/optional/views.view.archive.yml
@@ -87,7 +87,7 @@ display:
           exception:
             title_enable: true
           title_enable: true
-          title: '%1'
+          title: '{{ arguments.created_year_month }}'
           default_argument_type: fixed
           summary:
             sort_order: desc
@@ -186,7 +186,7 @@ display:
           exception:
             title_enable: true
           title_enable: true
-          title: '%1'
+          title: '{{ arguments.created_year_month }}'
           default_argument_type: fixed
           summary:
             format: default_summary
diff --git a/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml b/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
index e1086d1..7a32583 100644
--- a/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
+++ b/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml
@@ -105,7 +105,7 @@ display:
             title_enable: false
             title: All
           title_enable: true
-          title: '%1'
+          title: '{{ arguments.tid }}'
           default_argument_type: fixed
           default_argument_options:
             argument: ''
@@ -231,7 +231,7 @@ display:
           admin_label: ''
           empty: true
           tokenize: true
-          target: '!1'
+          target: '{{ raw_arguments.tid }}'
           view_mode: full
           bypass_access: false
           plugin_id: entity
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_roles_rid.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_roles_rid.yml
index 71c0a4d..65f2fe3 100644
--- a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_roles_rid.yml
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_roles_rid.yml
@@ -169,7 +169,7 @@ display:
             title_enable: false
             title: All
           title_enable: true
-          title: '%1'
+          title: '{{ arguments.roles_target_id }}'
           default_argument_type: fixed
           default_argument_options:
             argument: ''
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_uid_argument.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_uid_argument.yml
index fefcc42..4ff201c 100644
--- a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_uid_argument.yml
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_user_uid_argument.yml
@@ -28,7 +28,7 @@ display:
           table: users_field_data
           field: uid
           title_enable: true
-          title: '%1'
+          title: '{{ arguments.uid }}'
           plugin_id: user_uid
           entity_type: user
           entity_field: uid
diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php
index 49b7f1d..4dff979 100644
--- a/core/modules/views/src/Plugin/views/PluginBase.php
+++ b/core/modules/views/src/Plugin/views/PluginBase.php
@@ -337,10 +337,6 @@ public function globalTokenReplace($string = '', array $options = array()) {
    * Replaces Views' tokens in a given string. The resulting string will be
    * sanitized with Xss::filterAdmin.
    *
-   * This used to be a simple strtr() scattered throughout the code. Some Views
-   * tokens, such as arguments (e.g.: %1 or !1), still use the old format so we
-   * handle those as well as the new Twig-based tokens (e.g.: {{ field_name }})
-   *
    * @param $text
    *   Unsanitized string with possible tokens.
    * @param $tokens
@@ -357,34 +353,44 @@ protected function viewsTokenReplace($text, $tokens) {
       return Xss::filterAdmin($text);
     }
 
-    // Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
-    // the form of %1).
     $twig_tokens = array();
-    $other_tokens = array();
     foreach ($tokens as $token => $replacement) {
+      // Twig wants a token replacement array stripped of curly-brackets.
+      // Some Views tokens come with curly-braces, others do not.
+      //@todo: https://www.drupal.org/node/2544392
       if (strpos($token, '{{') !== FALSE) {
         // Twig wants a token replacement array stripped of curly-brackets.
-        $token = trim(str_replace(array('{', '}'), '', $token));
+        $token = trim(str_replace(['{{', '}}'], '', $token));
+      }
 
+      // Check for arrays in Twig tokens. Internally these are passed as
+      // dot-delimited strings, but need to be turned into associative arrays
+      // for parsing.
+      if (strpos($token, '.') === FALSE) {
         // We need to validate tokens are valid Twig variables. Twig uses the
         // same variable naming rules as PHP.
         // @see http://php.net/manual/en/language.variables.basics.php
         assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $token) === 1', 'Tokens need to be valid Twig variables.');
-
         $twig_tokens[$token] = $replacement;
       }
       else {
-        $other_tokens[$token] = $replacement;
+        $parts = explode('.', $token);
+        $top = array_shift($parts);
+        assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $top) === 1', 'Tokens need to be valid Twig variables.');
+        $token_array = array(array_pop($parts) => $replacement);
+        foreach(array_reverse($parts) as $key) {
+          assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $key) === 1', 'Tokens need to be valid Twig variables.');
+          $token_array = array($key => $token_array);
+        }
+        $twig_tokens[$top] = $token_array;
       }
     }
 
-    // Non-Twig tokens are a straight string replacement, Twig tokens get run
-    // through an inline template for rendering and replacement.
-    $text = strtr($text, $other_tokens);
     if ($twig_tokens) {
       // Use the unfiltered text for the Twig template, then filter the output.
       // Otherwise, Xss::filterAdmin could remove valid Twig syntax before the
       // template is parsed.
+
       $build = array(
         '#type' => 'inline_template',
         '#template' => $text,
@@ -396,10 +402,14 @@ function ($children, $elements) {
         ],
       );
 
-      return (string) $this->getRenderer()->render($build);
+      // Currently you cannot attach assets to tokens with
+      // Renderer::renderPlain(). This may be unnecessarily limiting. Consider
+      // using Renderer::executeInRenderContext() instead.
+      // @todo: https://www.drupal.org/node/2566621
+      return (string) $this->getRenderer()->renderPlain($build);
     }
     else {
-      return $text;
+      return Xss::filterAdmin($text);
     }
   }
 
diff --git a/core/modules/views/src/Plugin/views/area/Entity.php b/core/modules/views/src/Plugin/views/area/Entity.php
index df5e25e..3234f88 100644
--- a/core/modules/views/src/Plugin/views/area/Entity.php
+++ b/core/modules/views/src/Plugin/views/area/Entity.php
@@ -113,7 +113,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // display the entity ID to the admin form user.
     // @todo Use a method to check for tokens in
     //   https://www.drupal.org/node/2396607.
-    if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
+    if (strpos($this->options['target'], '{{') === FALSE) {
       // @todo If the entity does not exist, this will will show the config
       //   target identifier. Decide if this is the correct behavior in
       //   https://www.drupal.org/node/2415391.
@@ -146,7 +146,7 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     // @todo Use a method to check for tokens in
     //   https://www.drupal.org/node/2396607.
     $options = $form_state->getValue('options');
-    if (strpos($options['target'], '{{') === FALSE && strpos($options['target'], '!') === FALSE && strpos($options['target'], '%') === FALSE && strpos($options['target'], '[') === FALSE) {
+    if (strpos($options['target'], '{{') === FALSE) {
       if ($entity = $this->entityManager->getStorage($this->entityType)->load($options['target'])) {
         $options['target'] = $entity->getConfigTarget();
       }
@@ -161,7 +161,7 @@ public function render($empty = FALSE) {
     if (!$empty || !empty($this->options['empty'])) {
       // @todo Use a method to check for tokens in
       //   https://www.drupal.org/node/2396607.
-      if (strpos($this->options['target'], '{{') !== FALSE || strpos($this->options['target'], '!') !== FALSE || strpos($this->options['target'], '%') !== FALSE || strpos($this->options['target'], '[') !== FALSE) {
+      if (strpos($this->options['target'], '{{') !== FALSE) {
         $target_id = $this->tokenizeValue($this->options['target']);
         if ($entity = $this->entityManager->getStorage($this->entityType)->load($target_id)) {
           $target_entity = $entity;
@@ -190,7 +190,7 @@ public function calculateDependencies() {
     // Ensure that we don't add dependencies for placeholders.
     // @todo Use a method to check for tokens in
     //   https://www.drupal.org/node/2396607.
-    if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
+    if (strpos($this->options['target'], '{{') === FALSE) {
       if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
         $dependencies[$this->entityManager->getDefinition($this->entityType)->getConfigDependencyKey()][] = $entity->getConfigDependencyName();
       }
diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
index 82bb51d..4460a9a 100644
--- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
+++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
@@ -53,13 +53,12 @@ public function tokenForm(&$form, FormStateInterface $form_state) {
     // Get a list of the available fields and arguments for token replacement.
     $options = array();
     foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) {
-      $options[t('Fields')]["[$field]"] = $handler->adminLabel();
+      $options[(string) t('Fields')]["{{ $field }}"] = $handler->adminLabel();
     }
 
-    $count = 0; // This lets us prepare the key as we want it printed.
-    foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
-      $options[t('Arguments')]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
-      $options[t('Arguments')]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
+    foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
+      $options[(string) t('Arguments')]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
+      $options[(string) t('Arguments')]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
     }
 
     if (!empty($options)) {
@@ -75,7 +74,7 @@ public function tokenForm(&$form, FormStateInterface $form_state) {
         ),
       );
       $form['tokens']['help'] = array(
-        '#markup' => '<p>' . $this->t('The following tokens are available. If you would like to have the characters \'[\' and \']\' use the HTML entity codes \'%5B\' or  \'%5D\' or they will get replaced with empty space.') . '</p>',
+        '#markup' => '<p>' . $this->t('The following tokens are available. You may use Twig syntax in this field.') . '</p>',
       );
       foreach (array_keys($options) as $type) {
         if (!empty($options[$type])) {
diff --git a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
index a1f1c5e..b179245 100644
--- a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
@@ -211,7 +211,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#title_display' => 'invisible',
       '#size' => 20,
       '#default_value' => $this->options['exception']['title'],
-      '#description' => $this->t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+      '#description' => $this->t('Override the view and other argument titles. You may use Twig syntax in this field as well as the "arguments" and "raw_arguments" arrays.'),
       '#states' => array(
         'visible' => array(
           ':input[name="options[exception][title_enable]"]' => array('checked' => TRUE),
@@ -249,7 +249,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#title' => $this->t('Provide title'),
       '#title_display' => 'invisible',
       '#default_value' => $this->options['title'],
-      '#description' => $this->t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+      '#description' => $this->t('Override the view and other argument titles. You may use Twig syntax in this field.'),
       '#states' => array(
         'visible' => array(
           ':input[name="options[title_enable]"]' => array('checked' => TRUE),
@@ -258,6 +258,23 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#fieldset' => 'argument_present',
     );
 
+    $output = $this->getTokenHelp();
+    $form['token_help'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Replacement patterns'),
+      '#value' => $output,
+      '#states' => [
+        'visible' => [
+          [
+            ':input[name="options[title_enable]"]' => ['checked' => TRUE],
+          ],
+          [
+            ':input[name="options[exception][title_enable]"]' => ['checked' => TRUE],
+          ],
+        ],
+      ],
+    ];
+
     $form['specify_validation'] = array(
       '#type' => 'checkbox',
       '#title' => $this->t('Specify validation criteria'),
@@ -348,6 +365,45 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     );
   }
 
+  /**
+   * Provide token help information for the argument.
+   *
+   * @return array
+   *   A render array.
+   */
+  protected function getTokenHelp() {
+    $output = [];
+
+    foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
+      /** @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase $handler */
+      $options[(string) t('Arguments')]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
+      $options[(string) t('Arguments')]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
+    }
+
+    // We have some options, so make a list.
+    if (!empty($options)) {
+      $output[] = [
+        '#markup' => '<p>' . $this->t("The following replacement tokens are available for this argument.") . '</p>',
+      ];
+      foreach (array_keys($options) as $type) {
+        if (!empty($options[$type])) {
+          $items = array();
+          foreach ($options[$type] as $key => $value) {
+            $items[] = $key . ' == ' . $value;
+          }
+          $item_list = array(
+            '#theme' => 'item_list',
+            '#items' => $items,
+          );
+          $output[] = $item_list;
+        }
+      }
+    }
+
+    return $output;
+  }
+
+
   public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     $option_values = &$form_state->getValue('options');
     if (empty($option_values)) {
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 35e9b92..835935d 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -1725,17 +1725,23 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
         );
 
         $options = array();
-        $count = 0; // This lets us prepare the key as we want it printed.
-        foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
-          $options[t('Arguments')]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
-          $options[t('Arguments')]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
+        foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
+          $options[(string) t('Arguments')]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
+          $options[(string) t('Arguments')]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
         }
 
         // Default text.
         // We have some options, so make a list.
-        $output = '';
+        $description = [];
+        $description[] = [
+          '#markup' => $this->t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.'),
+        ];
         if (!empty($options)) {
-          $output = $this->t('<p>The following tokens are available for this link.</p>');
+          $description[] = [
+            '#prefix' => '<p>',
+            '#markup' => $this->t('The following tokens are available for this link. You may use Twig syntax in this field.'),
+            '#suffix' => '</p>',
+          ];
           foreach (array_keys($options) as $type) {
             if (!empty($options[$type])) {
               $items = array();
@@ -1745,9 +1751,8 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
               $item_list = array(
                 '#theme' => 'item_list',
                 '#items' => $items,
-                '#list_type' => $type,
               );
-              $output .= drupal_render($item_list);
+              $description[] = $item_list;
             }
           }
         }
@@ -1756,7 +1761,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
           '#type' => 'textfield',
           '#title' => $this->t('Custom URL'),
           '#default_value' => $this->getOption('link_url'),
-          '#description' => $this->t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.') . $output,
+          '#description' => $description,
           '#states' => array(
             'visible' => array(
               ':input[name="link_display"]' => array('value' => 'custom_url'),
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index 152d4e9..fd3f150 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -333,7 +333,7 @@ public function elementClasses($row_index = NULL) {
    * {@inheritdoc}
    */
   public function tokenizeValue($value, $row_index = NULL) {
-    if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
+    if (strpos($value, '{{') !== FALSE) {
       $fake_item = array(
         'alter_text' => TRUE,
         'text' => $value,
@@ -868,10 +868,9 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       // Add the field to the list of options.
       $options[t('Fields')]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2 );
 
-      $count = 0; // This lets us prepare the key as we want it printed.
       foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
-        $options[t('Arguments')]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
-        $options[t('Arguments')]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
+        $options[(string) t('Arguments')]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
+        $options[(string) t('Arguments')]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
       }
 
       $this->documentSelfTokens($options[t('Fields')]);
@@ -896,7 +895,6 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
             $item_list = array(
               '#theme' => 'item_list',
               '#items' => $items,
-              '#list_type' => $type,
             );
             $output[] = $item_list;
           }
@@ -1557,7 +1555,7 @@ public function getRenderTokens($item) {
     }
     $count = 0;
     foreach ($this->displayHandler->getHandlers('argument') as $arg => $handler) {
-      $token = '%' . ++$count;
+      $token = "{{ arguments.$arg }}";
       if (!isset($tokens[$token])) {
         $tokens[$token] = '';
       }
@@ -1565,7 +1563,8 @@ public function getRenderTokens($item) {
       // Use strip tags as there should never be HTML in the path.
       // However, we need to preserve special characters like " that
       // were removed by SafeMarkup::checkPlain().
-      $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(Html::decodeEntities($this->view->args[$count - 1])) : '';
+      $tokens["{{ raw_arguments.$arg }}"] = isset($this->view->args[$count]) ? strip_tags(Html::decodeEntities($this->view->args[$count])) : '';
+      $count++;
     }
 
     // Get flattened set of tokens for any array depth in query parameters.
@@ -1661,8 +1660,8 @@ protected function getTokenValuesRecursive(array $array, array $parent_keys = ar
       }
       else {
         // Create a token key based on array element structure.
-        $token_string = !empty($parent_keys) ? implode('_', $parent_keys) . '_' . $param : $param;
-        $tokens['%' . $token_string] = strip_tags(Html::decodeEntities($val));
+        $token_string = !empty($parent_keys) ? implode('.', $parent_keys) . '.' . $param : $param;
+        $tokens['{{ arguments.' . $token_string . ' }}'] = strip_tags(Html::decodeEntities($val));
       }
     }
 
diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
index ccfd1ba..de927cc 100644
--- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php
+++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
@@ -194,7 +194,7 @@ function usesFields() {
   public function usesTokens() {
     if ($this->usesRowClass()) {
       $class = $this->options['row_class'];
-      if (strpos($class, '{{') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) {
+      if (strpos($class, '{{') !== FALSE) {
         return TRUE;
       }
     }
@@ -231,7 +231,7 @@ public function getRowClass($row_index) {
    * Take a value and apply token replacement logic to it.
    */
   public function tokenizeValue($value, $row_index) {
-    if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
+    if (strpos($value, '{{') !== FALSE) {
       // Row tokens might be empty, for example for node row style.
       $tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : array();
       if (!empty($this->view->build_info['substitutions'])) {
diff --git a/core/modules/views/src/Tests/Handler/FieldKernelTest.php b/core/modules/views/src/Tests/Handler/FieldKernelTest.php
index 70940d0..109314b 100644
--- a/core/modules/views/src/Tests/Handler/FieldKernelTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldKernelTest.php
@@ -27,7 +27,7 @@ class FieldKernelTest extends ViewKernelTestBase {
    *
    * @var array
    */
-  public static $testViews = array('test_view', 'test_field_tokens', 'test_field_output');
+  public static $testViews = array('test_view', 'test_field_tokens', 'test_field_argument_tokens', 'test_field_output');
 
   /**
    * Map column names.
@@ -174,6 +174,44 @@ public function testRewrite() {
   }
 
   /**
+   * Tests the arguments tokens on field level.
+   */
+  public function testArgumentTokens() {
+    /** @var \Drupal\Core\Render\RendererInterface $renderer */
+    $renderer = \Drupal::service('renderer');
+
+    $view = Views::getView('test_field_argument_tokens');
+    $this->executeView($view, ['{{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }}']);
+
+    $name_field_0 = $view->field['name'];
+
+    $name_field_0->options['alter']['alter_text'] = TRUE;
+    $name_field_0->options['alter']['text'] = '%1 !1';
+
+    $row = $view->result[0];
+    $output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
+      return $name_field_0->advancedRender($row);
+    });
+
+    $this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
+    $this->assertEqual('%1 !1', (string) $output, "Ensure that old style placeholders aren't replaced");
+
+    // This time use new style tokens but ensure that we still don't allow
+    // arbitrary code execution.
+
+    $name_field_0->options['alter']['alter_text'] = TRUE;
+    $name_field_0->options['alter']['text'] = '{{ arguments.name }} {{ raw_arguments.name }}';
+
+    $row = $view->result[0];
+    $output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
+      return $name_field_0->advancedRender($row);
+    });
+
+    $this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
+    $this->assertEqual(' ', (string) $output, 'Ensure that new style placeholders are replaced');
+  }
+
+  /**
    * Tests the field tokens, row level and field level.
    */
   public function testFieldTokens() {
diff --git a/core/modules/views/src/Tests/Plugin/PluginBaseTest.php b/core/modules/views/src/Tests/Plugin/PluginBaseTest.php
index f4b5c2d..c5d69ab 100644
--- a/core/modules/views/src/Tests/Plugin/PluginBaseTest.php
+++ b/core/modules/views/src/Tests/Plugin/PluginBaseTest.php
@@ -43,6 +43,16 @@ public function testViewsTokenReplace() {
     $this->assertIdentical($result, 'en means English');
   }
 
+  /**
+   * Tests viewsTokenReplace without any twig tokens.
+   */
+  public function testViewsTokenReplaceWithTwigTokens() {
+    $text = 'Just some text';
+    $tokens = [];
+    $result = $this->testPluginBase->viewsTokenReplace($text, $tokens);
+    $this->assertIdentical($result, 'Just some text');
+  }
+
 }
 
 /**
diff --git a/core/modules/views/src/Tests/Update/ArgumentPlaceholderUpdatePathTest.php b/core/modules/views/src/Tests/Update/ArgumentPlaceholderUpdatePathTest.php
new file mode 100644
index 0000000..d123b5d
--- /dev/null
+++ b/core/modules/views/src/Tests/Update/ArgumentPlaceholderUpdatePathTest.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\Update\ArgumentPlaceholderUpdatePathTest.
+ */
+
+namespace Drupal\views\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+use Drupal\views\Entity\View;
+
+/**
+ * Tests the argument placeholder update path.
+ *
+ * @see views_update_8002()
+ *
+ * @group views
+ */
+class ArgumentPlaceholderUpdatePathTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../tests/fixtures/update/argument-placeholder.php'
+    ];
+  }
+
+  /**
+   * Ensures that %1 and !1 are converted to twig tokens in existing views.
+   */
+  public function testArgumentPlaceholderUpdate() {
+    $this->runUpdates();
+    $view = View::load('test_token_view');
+
+    $data = $view->toArray();
+    $this->assertEqual('{{ arguments.nid }}-test-class-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['style']['options']['col_class_custom']);
+    $this->assertEqual('{{ arguments.nid }}-test-class-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['style']['options']['row_class_custom']);
+    $this->assertEqual('{{ arguments.nid }}-custom-text-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['fields']['title']['alter']['text']);
+    $this->assertEqual('test_token_view {{ arguments.nid }} {{ raw_arguments.nid }}', $data['display']['default']['display_options']['title']);
+    $this->assertEqual('{{ arguments.nid }}-custom-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['header']['area_text_custom']['content']);
+    $this->assertEqual('{{ arguments.nid }}-text-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['footer']['area']['content']['value']);
+    $this->assertEqual("Displaying @start - @end of @total\n\n{{ arguments.nid }}-result-{{ raw_arguments.nid }}", $data['display']['default']['display_options']['empty']['result']['content']);
+    $this->assertEqual('{{ arguments.nid }}-title-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['empty']['title']['title']);
+    $this->assertEqual('{{ arguments.nid }} title {{ raw_arguments.nid }}', $data['display']['default']['display_options']['arguments']['nid']['title']);
+    $this->assertEqual('{{ arguments.nid }} exception-title {{ raw_arguments.nid }}', $data['display']['default']['display_options']['arguments']['nid']['exception']['title']);
+    $this->assertEqual('{{ arguments.nid }}-more-text-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['use_more_text']);
+    $this->assertEqual('{{ arguments.nid }}-custom-url-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['link_url']);
+  }
+
+}
diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php
index 2a8145c..3638c9c 100644
--- a/core/modules/views/src/ViewExecutable.php
+++ b/core/modules/views/src/ViewExecutable.php
@@ -1028,8 +1028,8 @@ protected function _buildArguments() {
         }
 
         // Add this argument's substitution
-        $substitutions['%' . ($position + 1)] = $arg_title;
-        $substitutions['!' . ($position + 1)] = strip_tags(Html::decodeEntities($arg));
+        $substitutions["{{ arguments.$id }}"] = $arg_title;
+        $substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($arg));
 
         // Test to see if we should use this argument's title
         if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
diff --git a/core/modules/views/tests/fixtures/update/argument-placeholder.php b/core/modules/views/tests/fixtures/update/argument-placeholder.php
new file mode 100644
index 0000000..2a277be
--- /dev/null
+++ b/core/modules/views/tests/fixtures/update/argument-placeholder.php
@@ -0,0 +1,19 @@
+<?php
+
+$connection = Drupal\Core\Database\Database::getConnection();
+
+$connection->insert('config')
+  ->fields(array(
+    'collection',
+    'name',
+    'data',
+  ))
+  ->values(array(
+    'collection' => '',
+    'name' => 'views.view.test_token_view',
+    'data' => serialize(\Drupal\Component\Serialization\Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml'))),
+  ))
+  ->fields([
+    'collection' => '',
+  ])
+  ->execute();
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_area.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_area.yml
index de5b615..336b043 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_area.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_area.yml
@@ -31,7 +31,7 @@ display:
           field: entity_entity_test
           id: entity_entity_test
           table: views
-          target: '!1'
+          target: '{{ raw_arguments.id }}'
           view_mode: full
           plugin_id: entity
         entity_block:
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_argument_tokens.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_argument_tokens.yml
new file mode 100644
index 0000000..800beaa
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_argument_tokens.yml
@@ -0,0 +1,59 @@
+langcode: en
+status: true
+dependencies: {  }
+id: test_field_argument_tokens
+label: null
+module: views
+description: ''
+tag: ''
+base_table: views_test_data
+base_field: nid
+core: '8'
+display:
+  default:
+    display_options:
+      access:
+        type: none
+      cache:
+        type: tag
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+      query:
+        type: views_query
+      fields:
+        name:
+          id: name
+          table: views_test_data
+          field: name
+          plugin_id: string
+        name_1:
+          id: name_1
+          table: views_test_data
+          field: name
+          plugin_id: string
+        name_2:
+          id: name_2
+          table: views_test_data
+          field: name
+          plugin_id: string
+        job:
+          id: job
+          table: views_test_data
+          field: job
+          plugin_id: string
+      arguments:
+        null:
+          id: null
+          table: views
+          field: null
+          plugin_id: ull
+      style:
+        type: default
+      row:
+        type: fields
+    display_plugin: default
+    display_title: Defaults
+    id: default
+    position: 0
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml
new file mode 100644
index 0000000..aa59852
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml
@@ -0,0 +1,315 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+    - user
+id: test_token_view
+label: test_token_view
+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: full
+        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: '‹ previous'
+            next: 'next ›'
+            first: '« first'
+            last: 'last »'
+          quantity: 9
+      style:
+        type: grid
+        options:
+          grouping: {  }
+          columns: 4
+          automatic_width: true
+          alignment: horizontal
+          col_class_default: true
+          col_class_custom: '%1-test-class-!1'
+          row_class_default: true
+          row_class_custom: '%1-test-class-!1'
+      row:
+        type: fields
+        options:
+          default_field_elements: true
+          inline: {  }
+          separator: ''
+          hide_empty: false
+      fields:
+        title:
+          id: title
+          table: node_field_data
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: true
+            text: '%1-custom-text-!1'
+            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: false
+            ellipsis: false
+            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
+          click_sort_column: value
+          type: string
+          settings:
+            link_to_entity: true
+          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
+          entity_type: node
+          entity_field: title
+          plugin_id: field
+      filters:
+        status:
+          value: true
+          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
+      title: 'test_token_view %1 !1'
+      header:
+        area_text_custom:
+          id: area_text_custom
+          table: views
+          field: area_text_custom
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: false
+          tokenize: false
+          content: '%1-custom-!1'
+          plugin_id: text_custom
+      footer:
+        area:
+          id: area
+          table: views
+          field: area
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: false
+          tokenize: false
+          content:
+            value: '%1-text-!1'
+            format: basic_html
+          plugin_id: text
+      empty:
+        result:
+          id: result
+          table: views
+          field: result
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: true
+          content: "Displaying @start - @end of @total\n\n%1-result-!1"
+          plugin_id: result
+        title:
+          id: title
+          table: views
+          field: title
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: true
+          title: '%1-title-!1'
+          plugin_id: title
+      relationships: {  }
+      arguments:
+        nid:
+          id: nid
+          table: node_field_data
+          field: nid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          default_action: ignore
+          exception:
+            value: all
+            title_enable: true
+            title: '%1 exception-title !1'
+          title_enable: true
+          title: '%1 title !1'
+          default_argument_type: fixed
+          default_argument_options:
+            argument: ''
+          default_argument_skip_url: false
+          summary_options:
+            base_path: ''
+            count: true
+            items_per_page: 25
+            override: false
+          summary:
+            sort_order: asc
+            number_of_records: 0
+            format: default_summary
+          specify_validation: false
+          validate:
+            type: none
+            fail: 'not found'
+          validate_options: {  }
+          break_phrase: false
+          not: false
+          entity_type: node
+          entity_field: nid
+          plugin_id: numeric
+      display_extenders: {  }
+      css_class: ''
+      use_more: true
+      use_more_always: true
+      use_more_text: '%1-more-text-!1'
+      link_url: '%1-custom-url-!1'
+      link_display: custom_url
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      cacheable: false
+  block_1:
+    display_plugin: block
+    id: block_1
+    display_title: Block
+    position: 2
+    display_options:
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      cacheable: false
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: test-token-view
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      cacheable: false
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php
index 0f8feef..5da095a 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/field/FieldTest.php
@@ -46,7 +46,7 @@ public function getTestValue() {
    * Overrides Drupal\views\Plugin\views\field\FieldPluginBase::addSelfTokens().
    */
   protected function addSelfTokens(&$tokens, $item) {
-    $tokens['[test__token]'] = $this->getTestValue();
+    $tokens['{{ test_token }}'] = $this->getTestValue();
   }
 
   /**
diff --git a/core/modules/views/tests/modules/views_test_data/views_test_data.module b/core/modules/views/tests/modules/views_test_data/views_test_data.module
index 1af309c..ecf65b1 100644
--- a/core/modules/views/tests/modules/views_test_data/views_test_data.module
+++ b/core/modules/views/tests/modules/views_test_data/views_test_data.module
@@ -110,3 +110,17 @@ function template_preprocess_views_view_mapping_test(&$variables) {
     }
   }
 }
+
+/**
+ * Test pre_render function.
+ *
+ * @param array $element
+ *   A render array
+ *
+ * @return array
+ *   The changed render array.
+ */
+function views_test_data_test_pre_render_function($element) {
+  $element['#markup'] = 'views_test_data_test_pre_render_function executed';
+  return $element;
+}
diff --git a/core/modules/views/tests/src/Unit/Plugin/area/EntityTest.php b/core/modules/views/tests/src/Unit/Plugin/area/EntityTest.php
index bb89281..0c3ff91 100644
--- a/core/modules/views/tests/src/Unit/Plugin/area/EntityTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/area/EntityTest.php
@@ -130,10 +130,10 @@ protected function setupEntityManager() {
    */
   public function providerTestTokens() {
     return [
-      ['!1', 5],
-      ['%2', 6],
+      ['{{ raw_arguments.test1 }}', 5],
+      ['{{ arguments.test2 }}', 6],
       ['{{ test_render_token }}', 7],
-      ['[test:global_token]', 8],
+      ['{{ test:global_token }}', 8],
     ];
   }
 
diff --git a/core/modules/views/tests/src/Unit/Plugin/field/FieldPluginBaseTest.php b/core/modules/views/tests/src/Unit/Plugin/field/FieldPluginBaseTest.php
index 7b87f22..65471b7 100644
--- a/core/modules/views/tests/src/Unit/Plugin/field/FieldPluginBaseTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/field/FieldPluginBaseTest.php
@@ -449,8 +449,8 @@ public function testRenderAsLinkWithPathAndTokens($path, $tokens, $link_html) {
     ];
 
     $this->renderer->expects($this->once())
-      ->method('render')
-      ->with($build, FALSE)
+      ->method('renderPlain')
+      ->with($build)
       ->willReturn('base:test-path/123');
 
     $result = $field->advancedRender($row);
@@ -497,6 +497,67 @@ protected function setupTestField(array $options = []) {
     return $field;
   }
 
+  /**
+   * @covers ::getRenderTokens
+   */
+  public function testGetRenderTokensWithoutFieldsAndArguments() {
+    $field = $this->setupTestField();
+
+    $this->display->expects($this->any())
+      ->method('getHandlers')
+      ->willReturnMap([
+        ['argument', []],
+        ['field', []],
+      ]);
+
+    $this->assertEquals([], $field->getRenderTokens([]));
+  }
+
+  /**
+   * @covers ::getRenderTokens
+   */
+  public function testGetRenderTokensWithoutArguments() {
+    $field = $this->setupTestField(['id' => 'id']);
+
+    $field->last_render = 'last rendered output';
+    $this->display->expects($this->any())
+      ->method('getHandlers')
+      ->willReturnMap([
+        ['argument', []],
+        ['field', ['id' => $field]],
+      ]);
+
+    $this->assertEquals(['{{ id }}' => 'last rendered output'], $field->getRenderTokens([]));
+  }
+
+  /**
+   * @covers ::getRenderTokens
+   */
+  public function testGetRenderTokensWithArguments() {
+    $field = $this->setupTestField(['id' => 'id']);
+    $field->view->args = ['argument value'];
+    $field->view->build_info['substitutions']['{{ arguments.name }}'] = 'argument value';
+
+    $argument = $this->getMockBuilder('\Drupal\views\Plugin\views\argument\ArgumentPluginBase')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $field->last_render = 'last rendered output';
+    $this->display->expects($this->any())
+      ->method('getHandlers')
+      ->willReturnMap([
+        ['argument', ['name' => $argument]],
+        ['field', ['id' => $field]],
+      ]);
+
+    $expected = [
+      '{{ id }}' => 'last rendered output',
+      '{{ arguments.name }}' => 'argument value',
+      '{{ raw_arguments.name }}' => 'argument value',
+    ];
+    $this->assertEquals($expected, $field->getRenderTokens([]));
+  }
+
 }
 
 class FieldPluginBaseTestField extends FieldPluginBase {
diff --git a/core/modules/views/views.install b/core/modules/views/views.install
index 5615747..dce493d 100644
--- a/core/modules/views/views.install
+++ b/core/modules/views/views.install
@@ -117,5 +117,178 @@ function views_update_8001(&$sandbox) {
 }
 
 /**
+ * Updates %1 and !1 tokens to argument tokens.
+ */
+function views_update_8002() {
+  $config_factory = \Drupal::configFactory();
+  foreach ($config_factory->listAll('views.view.') as $view_config_name) {
+    $view = $config_factory->getEditable($view_config_name);
+
+    $displays = $view->get('display');
+    $argument_map_per_display = _views_update_argument_map($displays);
+
+    $changed = FALSE;
+
+    // Update all the field settings, which support tokens.
+    foreach ($displays as $display_name => &$display) {
+      if (!empty($display['display_options']['fields'])) {
+        $token_values = [
+          'path',
+          'alt',
+          'link_class',
+          'rel',
+          'target',
+          'query',
+          'fragment',
+          'prefix',
+          'suffix',
+          'more_link_text',
+          'more_link_path',
+          'link_attributes',
+          'text',
+        ];
+
+        foreach ($display['display_options']['fields'] as $field_name => &$field) {
+          foreach ($token_values as $token_name) {
+            if (!empty($field['alter'][$token_name])) {
+              if (is_array($field['alter'][$token_name])) {
+                foreach (array_keys($field['alter'][$token_name]) as $key) {
+                  $field['alter'][$token_name][$key] = _views_update_8002_token_update($field['alter'][$token_name][$key], $argument_map_per_display[$display_name]);
+                }
+              }
+              else {
+                $field['alter'][$token_name] = _views_update_8002_token_update($field['alter'][$token_name], $argument_map_per_display[$display_name]);
+              }
+              $changed = TRUE;
+            }
+          }
+        }
+      }
+    }
+
+    // Update the area handlers with tokens.
+    foreach ($displays as $display_name => &$display) {
+      $area_types = ['header', 'footer', 'empty'];
+      foreach ($area_types as $area_type) {
+        if (!empty($display['display_options'][$area_type])) {
+          foreach ($display['display_options'][$area_type] as &$area) {
+            switch ($area['plugin_id']) {
+              case 'title':
+                $area['title'] = _views_update_8002_token_update($area['title'], $argument_map_per_display[$display_name]);
+                break;
+              case 'result':
+                $area['content'] = _views_update_8002_token_update($area['content'], $argument_map_per_display[$display_name]);
+                break;
+              case 'text':
+                $area['content']['value'] = _views_update_8002_token_update($area['content']['value'], $argument_map_per_display[$display_name]);
+                break;
+              case 'text_custom':
+                $area['content'] = _views_update_8002_token_update($area['content'], $argument_map_per_display[$display_name]);
+                break;
+            }
+          }
+          $changed = TRUE;
+        }
+      }
+    }
+
+    // Update the argument title settings.
+    foreach ($displays as $display_name => &$display) {
+      if (!empty($display['display_options']['arguments'])) {
+        foreach ($display['display_options']['arguments'] as &$argument) {
+          if (isset($argument['exception']['title'])) {
+            $argument['exception']['title'] = _views_update_8002_token_update($argument['exception']['title'], $argument_map_per_display[$display_name]);
+          }
+          if (isset($argument['title'])) {
+            $argument['title'] = _views_update_8002_token_update($argument['title'], $argument_map_per_display[$display_name]);
+          }
+        }
+      }
+    }
+
+    // Update the display title settings.
+    // Update the more link text and more link URL.
+    foreach ($displays as $display_name => &$display) {
+      if (!empty($display['display_options']['title'])) {
+        $display['display_options']['title'] = _views_update_8002_token_update($display['display_options']['title'], $argument_map_per_display[$display_name]);
+      }
+      if (!empty($display['display_options']['use_more_text'])) {
+        $display['display_options']['use_more_text'] = _views_update_8002_token_update($display['display_options']['use_more_text'], $argument_map_per_display[$display_name]);
+      }
+      if (!empty($display['display_options']['link_url'])) {
+        $display['display_options']['link_url'] = _views_update_8002_token_update($display['display_options']['link_url'], $argument_map_per_display[$display_name]);
+      }
+    }
+
+    // Update custom classes for row class + grid classes.
+    // Update RSS description field.
+    foreach ($displays as $display_name => &$display) {
+      if (!empty($display['display_options']['style'])) {
+        if (!empty($display['display_options']['style']['options']['row_class_custom'])) {
+          $display['display_options']['style']['options']['row_class_custom'] = _views_update_8002_token_update($display['display_options']['style']['options']['row_class_custom'], $argument_map_per_display[$display_name]);
+        }
+        if (!empty($display['display_options']['style']['options']['col_class_custom'])) {
+          $display['display_options']['style']['options']['col_class_custom'] = _views_update_8002_token_update($display['display_options']['style']['options']['col_class_custom'], $argument_map_per_display[$display_name]);
+        }
+      }
+    }
+
+    if ($changed) {
+      $view->set('display', $displays);
+      $view->save(TRUE);
+    }
+  }
+}
+
+/**
+ * Updates a views configuration string from using %/! to twig tokens.
+ *
+ * @param string $text
+ *   Text in which to search for argument tokens and replace them with their
+ *   twig representation.
+ *
+ * @return string
+ *   The updated value.
+ */
+function _views_update_8002_token_update($text, array $argument_map) {
+  $text = preg_replace_callback('/%(\d)/', function ($match) use ($argument_map) {
+    return "{{ arguments.{$argument_map[$match[1]]} }}";
+  }, $text);
+  $text = preg_replace_callback('/!(\d)/', function ($match) use ($argument_map) {
+    return "{{ raw_arguments.{$argument_map[$match[1]]} }}";
+  }, $text);
+
+  return $text;
+}
+
+/**
+ * Updates argument maps.
+ *
+ * @param array $displays
+ *
+ * @return array
+ *   The argument map.
+ */
+function _views_update_argument_map($displays) {
+  $argument_map = [];
+  foreach ($displays as $display_id => $display) {
+    $argument_map[$display_id] = [];
+    if (isset($display['display_options']['arguments'])) {
+      foreach (array_keys($display['display_options']['arguments']) as $number => $name) {
+        $argument_map[$display_id][$number + 1] = $name;
+      }
+    }
+    elseif (isset($displays['default']['display_options']['arguments'])) {
+      foreach (array_keys($displays['default']['display_options']['arguments']) as $number => $name) {
+        $argument_map[$display_id][$number + 1] = $name;
+      }
+    }
+  }
+
+  return $argument_map;
+}
+
+/**
  * @} End of "addtogroup updates-8.0.0-beta".
  */
+
diff --git a/core/modules/views_ui/src/Tests/AreaEntityUITest.php b/core/modules/views_ui/src/Tests/AreaEntityUITest.php
index 421367d..47e31df 100644
--- a/core/modules/views_ui/src/Tests/AreaEntityUITest.php
+++ b/core/modules/views_ui/src/Tests/AreaEntityUITest.php
@@ -69,8 +69,8 @@ public function testUI() {
     $this->assertFieldByName('options[target]', $entity_test->id());
 
     // Replace the header target entities with argument placeholders.
-    $this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '!1'], 'Apply');
-    $this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '!1'], 'Apply');
+    $this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '{{ raw_arguments.null }}'], 'Apply');
+    $this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '{{ raw_arguments.null }}'], 'Apply');
     $this->drupalPostForm(NULL, [], 'Save');
 
     // Confirm that the argument placeholders are saved.
@@ -78,15 +78,15 @@ public function testUI() {
     $header = $view->getDisplay('default')['display_options']['header'];
     $this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
 
-    $this->assertEqual('!1', $header['entity_block']['target']);
-    $this->assertEqual('!1', $header['entity_entity_test']['target']);
+    $this->assertEqual('{{ raw_arguments.null }}', $header['entity_block']['target']);
+    $this->assertEqual('{{ raw_arguments.null }}', $header['entity_entity_test']['target']);
 
     // Confirm that the argument placeholders are still displayed in the form.
     $this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_block");
-    $this->assertFieldByName('options[target]', '!1');
+    $this->assertFieldByName('options[target]', '{{ raw_arguments.null }}');
 
     $this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test");
-    $this->assertFieldByName('options[target]', '!1');
+    $this->assertFieldByName('options[target]', '{{ raw_arguments.null }}');
 
     // Change the targets for both headers back to the entities.
     $this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => $block->id()], 'Apply');
diff --git a/core/modules/views_ui/src/Tests/FieldUITest.php b/core/modules/views_ui/src/Tests/FieldUITest.php
index 81d2b7e..ff0e382 100644
--- a/core/modules/views_ui/src/Tests/FieldUITest.php
+++ b/core/modules/views_ui/src/Tests/FieldUITest.php
@@ -42,18 +42,18 @@ public function testFieldUI() {
     // Ensure that the expected tokens appear in the UI.
     $edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/age';
     $this->drupalGet($edit_handler_url);
-    $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
+    $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/ul/li');
     $this->assertEqual((string) $result[0], '{{ age }} == Age');
 
     $edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/id';
     $this->drupalGet($edit_handler_url);
-    $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
+    $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/ul/li');
     $this->assertEqual((string) $result[0], '{{ age }} == Age');
     $this->assertEqual((string) $result[1], '{{ id }} == ID');
 
     $edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/name';
     $this->drupalGet($edit_handler_url);
-    $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
+    $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/ul/li');
     $this->assertEqual((string) $result[0], '{{ age }} == Age');
     $this->assertEqual((string) $result[1], '{{ id }} == ID');
     $this->assertEqual((string) $result[2], '{{ name }} == Name');
diff --git a/core/modules/views_ui/src/Tests/XssTest.php b/core/modules/views_ui/src/Tests/XssTest.php
index a847434..33a7fa6 100644
--- a/core/modules/views_ui/src/Tests/XssTest.php
+++ b/core/modules/views_ui/src/Tests/XssTest.php
@@ -29,8 +29,8 @@ public function testViewsUi() {
     $this->assertEscaped('<marquee>test</marquee>', 'Field admin label is properly escaped.');
 
     $this->drupalGet('admin/structure/views/nojs/handler/sa_contrib_2013_035/page_1/header/area');
-    $this->assertRaw('[title] == &amp;lt;marquee&amp;gt;test&amp;lt;/marquee&amp;gt;', 'Token label is properly escaped.');
-    $this->assertRaw('[title_1] == &amp;lt;script&amp;gt;alert(&amp;quot;XSS&amp;quot;)&amp;lt;/script&amp;gt;', 'Token label is properly escaped.');
+    $this->assertRaw('{{ title }} == &amp;lt;marquee&amp;gt;test&amp;lt;/marquee&amp;gt;', 'Token label is properly escaped.');
+    $this->assertRaw('{{ title_1 }} == &amp;lt;script&amp;gt;alert(&amp;quot;XSS&amp;quot;)&amp;lt;/script&amp;gt;', 'Token label is properly escaped.');
   }
 
 }
