diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/relationship/GroupwiseMax.php b/core/modules/views/lib/Drupal/views/Plugin/views/relationship/GroupwiseMax.php
index 87376ee..d7aa8af 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/relationship/GroupwiseMax.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/relationship/GroupwiseMax.php
@@ -11,6 +11,7 @@
 use Drupal\views\ViewExecutable;
 use Drupal\Component\Annotation\Plugin;
 use Drupal\views\Views;
+use Drupal\views_ui\ViewFormControllerBase;
 
 /**
  * Relationship handler that allows a groupwise maximum of the linked in table.
@@ -90,7 +91,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Get the sorts that apply to our base.
-    $sorts = views_fetch_fields($this->definition['base'], 'sort');
+    $sorts = ViewFormControllerBase::fetchFields($this->definition['base'], 'sort');
     foreach ($sorts as $sort_id => $sort) {
       $sort_options[$sort_id] = "$sort[group]: $sort[title]";
     }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
index 4b2512c..d05d1a9 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\views\Plugin\Core\Entity\View;
 use Drupal\views\Views;
+use Drupal\views_ui\ViewFormControllerBase;
 use Drupal\views_ui\ViewUI;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\PluginBase;
@@ -556,9 +557,6 @@ protected function row_style_options() {
    */
   protected function build_filters(&$form, &$form_state) {
     // Find all the fields we are allowed to filter by.
-    module_load_include('inc', 'views_ui', 'admin');
-    $fields = views_fetch_fields($this->base_table, 'filter');
-
     $bundles = entity_get_bundles($this->entity_type);
     // If the current base table support bundles and has more than one (like user).
     if (isset($this->entity_info['bundle_keys']) && !empty($bundles)) {
@@ -824,7 +822,7 @@ protected function default_display_filters_user(array $form, array &$form_state)
       // the base table for the view; the taxonomy vocabulary machine_name, for
       // example, is stored in taxonomy_vocabulary, not taxonomy_term_data.
       module_load_include('inc', 'views_ui', 'admin');
-      $fields = views_fetch_fields($this->base_table, 'filter');
+      $fields = ViewFormControllerBase::fetchFields($this->base_table, 'filter');
       if (isset($fields[$this->base_table . '.' . $bundle_key])) {
         $table = $this->base_table;
       }
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewsDataTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewsDataTest.php
index 3357008..edf71e0 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewsDataTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewsDataTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Tests;
 
+use Drupal\views_ui\ViewFormControllerBase;
+
 /**
  * Tests the fetching of views data.
  *
@@ -215,7 +217,7 @@ public function testViewsFetchFields() {
 
     $handler_types = array('field', 'argument', 'filter', 'sort', 'area');
     foreach ($handler_types as $handler_type) {
-      $fields = views_fetch_fields('views_test_data', $handler_type);
+      $fields = ViewFormControllerBase::fetchFields('views_test_data', $handler_type);
       $expected_keys = array_walk($expected[$handler_type], function(&$item) {
         $item = "views_test_data.$item";
       });
@@ -224,7 +226,7 @@ public function testViewsFetchFields() {
 
     // Check for subtype filtering, so header and footer.
     foreach (array('header', 'footer') as $sub_type) {
-      $fields = views_fetch_fields('views_test_data', 'area', FALSE, $sub_type);
+      $fields = ViewFormControllerBase::fetchFields('views_test_data', 'area', FALSE, $sub_type);
 
       $expected_keys = array_walk($expected[$sub_type], function(&$item) {
         $item = "views_test_data.$item";
diff --git a/core/modules/views/views_ui/admin.inc b/core/modules/views/views_ui/admin.inc
index df344d2..d0412b5 100644
--- a/core/modules/views/views_ui/admin.inc
+++ b/core/modules/views/views_ui/admin.inc
@@ -408,141 +408,6 @@ function views_ui_build_form_url($form_state) {
   return $url;
 }
 
-function _views_sort_types($a, $b) {
-  $a_group = drupal_strtolower($a['group']);
-  $b_group = drupal_strtolower($b['group']);
-  if ($a_group != $b_group) {
-    return $a_group < $b_group ? -1 : 1;
-  }
-
-  $a_title = drupal_strtolower($a['title']);
-  $b_title = drupal_strtolower($b['title']);
-  if ($a_title != $b_title) {
-    return $a_title < $b_title ? -1 : 1;
-  }
-
-  return 0;
-}
-
-/**
- * Fetch a list of all fields available for a given base type.
- *
- * @param (array|string) $base
- *   A list or a single base_table, for example node.
- * @param string $type
- *   The handler type, for example field or filter.
- * @param bool $grouping
- *   Should the result grouping by its 'group' label.
- * @param string $sub_type
- *   An optional sub type. E.g. Allows making an area plugin available for
- *   header only, instead of header, footer, and empty regions.
- *
- * @return array
- *   A keyed array of in the form of 'base_table' => 'Description'.
- */
-function views_fetch_fields($base, $type, $grouping = FALSE, $sub_type = NULL) {
-  static $fields = array();
-  if (empty($fields)) {
-    $data = Views::viewsData()->get();
-    $start = microtime(TRUE);
-    // This constructs this ginormous multi dimensional array to
-    // collect the important data about fields. In the end,
-    // the structure looks a bit like this (using nid as an example)
-    // $strings['nid']['filter']['title'] = 'string'.
-    //
-    // This is constructed this way because the above referenced strings
-    // can appear in different places in the actual data structure so that
-    // the data doesn't have to be repeated a lot. This essentially lets
-    // each field have a cheap kind of inheritance.
-
-    foreach ($data as $table => $table_data) {
-      $bases = array();
-      $strings = array();
-      $skip_bases = array();
-      foreach ($table_data as $field => $info) {
-        // Collect table data from this table
-        if ($field == 'table') {
-          // calculate what tables this table can join to.
-          if (!empty($info['join'])) {
-            $bases = array_keys($info['join']);
-          }
-          // And it obviously joins to itself.
-          $bases[] = $table;
-          continue;
-        }
-        foreach (array('field', 'sort', 'filter', 'argument', 'relationship', 'area') as $key) {
-          if (!empty($info[$key])) {
-            if ($grouping && !empty($info[$key]['no group by'])) {
-              continue;
-            }
-            if ($sub_type && isset($info[$key]['sub_type']) && (!in_array($sub_type, (array) $info[$key]['sub_type']))) {
-              continue;
-            }
-            if (!empty($info[$key]['skip base'])) {
-              foreach ((array) $info[$key]['skip base'] as $base_name) {
-                $skip_bases[$field][$key][$base_name] = TRUE;
-              }
-            }
-            elseif (!empty($info['skip base'])) {
-              foreach ((array) $info['skip base'] as $base_name) {
-                $skip_bases[$field][$key][$base_name] = TRUE;
-              }
-            }
-            foreach (array('title', 'group', 'help', 'base', 'aliases') as $string) {
-              // First, try the lowest possible level
-              if (!empty($info[$key][$string])) {
-                $strings[$field][$key][$string] = $info[$key][$string];
-              }
-              // Then try the field level
-              elseif (!empty($info[$string])) {
-                $strings[$field][$key][$string] = $info[$string];
-              }
-              // Finally, try the table level
-              elseif (!empty($table_data['table'][$string])) {
-                $strings[$field][$key][$string] = $table_data['table'][$string];
-              }
-              else {
-                if ($string != 'base' && $string != 'base') {
-                  $strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string));
-                }
-              }
-            }
-          }
-        }
-      }
-      foreach ($bases as $base_name) {
-        foreach ($strings as $field => $field_strings) {
-          foreach ($field_strings as $type_name => $type_strings) {
-            if (empty($skip_bases[$field][$type_name][$base_name])) {
-              $fields[$base_name][$type_name]["$table.$field"] = $type_strings;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // If we have an array of base tables available, go through them
-  // all and add them together. Duplicate keys will be lost and that's
-  // Just Fine.
-  if (is_array($base)) {
-    $strings = array();
-    foreach ($base as $base_table) {
-      if (isset($fields[$base_table][$type])) {
-        $strings += $fields[$base_table][$type];
-      }
-    }
-    uasort($strings, '_views_sort_types');
-    return $strings;
-  }
-
-  if (isset($fields[$base][$type])) {
-    uasort($fields[$base][$type], '_views_sort_types');
-    return $fields[$base][$type];
-  }
-  return array();
-}
-
 /**
  * #process callback for a button; determines if a button is the form's triggering element.
  *
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/AddItem.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/AddItem.php
index 1c8d13e..14f0065 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/AddItem.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/AddItem.php
@@ -9,6 +9,7 @@
 
 use Drupal\views\ViewExecutable;
 use Drupal\views\ViewStorageInterface;
+use Drupal\views_ui\ViewFormControllerBase;
 
 /**
  * Provides a form for adding an item in the Views UI.
@@ -81,7 +82,7 @@ public function buildForm(array $form, array &$form_state) {
 
     // Figure out all the base tables allowed based upon what the relationships provide.
     $base_tables = $executable->getBaseTables();
-    $options = views_fetch_fields(array_keys($base_tables), $type, $display->useGroupBy(), $form_state['type']);
+    $options = ViewFormControllerBase::fetchFields(array_keys($base_tables), $type, $display->useGroupBy(), $form_state['type']);
 
     if (!empty($options)) {
       $form['override']['controls'] = array(
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php
index 93564b7..bfc3725 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php
@@ -10,6 +10,7 @@
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
+use Drupal\views_ui\ViewFormControllerBase;
 
 /**
  * Provides a form for configuring an item in the Views UI.
@@ -105,7 +106,7 @@ public function buildForm(array $form, array &$form_state) {
           // If this relationship is valid for this type, add it to the list.
           $data = Views::viewsData()->get($relationship['table']);
           $base = $data[$relationship['field']]['relationship']['base'];
-          $base_fields = views_fetch_fields($base, $form_state['type'], $executable->display_handler->useGroupBy());
+          $base_fields = ViewFormControllerBase::fetchFields($base, $form_state['type'], $executable->display_handler->useGroupBy());
           if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
             $relationship_handler->init($executable, $executable->display_handler, $relationship);
             $relationship_options[$relationship['id']] = $relationship_handler->label();
@@ -115,7 +116,7 @@ public function buildForm(array $form, array &$form_state) {
         if (!empty($relationship_options)) {
           // Make sure the existing relationship is even valid. If not, force
           // it to none.
-          $base_fields = views_fetch_fields($view->get('base_table'), $form_state['type'], $executable->display_handler->useGroupBy());
+          $base_fields = ViewFormControllerBase::fetchFields($view->get('base_table'), $form_state['type'], $executable->display_handler->useGroupBy());
           if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
             $relationship_options = array_merge(array('none' => t('Do not use a relationship')), $relationship_options);
           }
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
index 17db2ec..549790f 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityFormController;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\views\Views;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
@@ -174,4 +175,151 @@ public function getDisplayLabel(ViewUI $view, $display_id, $check_changed = TRUE
     return $title;
   }
 
+  /**
+   * Fetch a list of all fields available for a given base type.
+   *
+   * @param (array|string) $base
+   *   A list or a single base_table, for example node.
+   * @param string $type
+   *   The handler type, for example field or filter.
+   * @param bool $grouping
+   *   Should the result grouping by its 'group' label.
+   * @param string $sub_type
+   *   An optional sub type. E.g. Allows making an area plugin available for
+   *   header only, instead of header, footer, and empty regions.
+   *
+   * @return array
+   *   A keyed array of in the form of 'base_table' => 'Description'.
+   */
+  public static function fetchFields($base, $type, $grouping = FALSE, $sub_type = NULL) {
+    static $fields = array();
+    if (empty($fields)) {
+      $data = Views::viewsData()->get();
+      // This constructs this ginormous multi dimensional array to
+      // collect the important data about fields. In the end,
+      // the structure looks a bit like this (using nid as an example)
+      // $strings['nid']['filter']['title'] = 'string'.
+      //
+      // This is constructed this way because the above referenced strings
+      // can appear in different places in the actual data structure so that
+      // the data doesn't have to be repeated a lot. This essentially lets
+      // each field have a cheap kind of inheritance.
+
+      foreach ($data as $table => $table_data) {
+        $bases = array();
+        $strings = array();
+        $skip_bases = array();
+        foreach ($table_data as $field => $info) {
+          // Collect table data from this table
+          if ($field == 'table') {
+            // calculate what tables this table can join to.
+            if (!empty($info['join'])) {
+              $bases = array_keys($info['join']);
+            }
+            // And it obviously joins to itself.
+            $bases[] = $table;
+            continue;
+          }
+          foreach (array('field', 'sort', 'filter', 'argument', 'relationship', 'area') as $key) {
+            if (!empty($info[$key])) {
+              if ($grouping && !empty($info[$key]['no group by'])) {
+                continue;
+              }
+              if ($sub_type && isset($info[$key]['sub_type']) && (!in_array($sub_type, (array) $info[$key]['sub_type']))) {
+                continue;
+              }
+              if (!empty($info[$key]['skip base'])) {
+                foreach ((array) $info[$key]['skip base'] as $base_name) {
+                  $skip_bases[$field][$key][$base_name] = TRUE;
+                }
+              }
+              elseif (!empty($info['skip base'])) {
+                foreach ((array) $info['skip base'] as $base_name) {
+                  $skip_bases[$field][$key][$base_name] = TRUE;
+                }
+              }
+              foreach (array('title', 'group', 'help', 'base', 'aliases') as $string) {
+                // First, try the lowest possible level
+                if (!empty($info[$key][$string])) {
+                  $strings[$field][$key][$string] = $info[$key][$string];
+                }
+                // Then try the field level
+                elseif (!empty($info[$string])) {
+                  $strings[$field][$key][$string] = $info[$string];
+                }
+                // Finally, try the table level
+                elseif (!empty($table_data['table'][$string])) {
+                  $strings[$field][$key][$string] = $table_data['table'][$string];
+                }
+                else {
+                  if ($string != 'base' && $string != 'base') {
+                    $strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string));
+                  }
+                }
+              }
+            }
+          }
+        }
+        foreach ($bases as $base_name) {
+          foreach ($strings as $field => $field_strings) {
+            foreach ($field_strings as $type_name => $type_strings) {
+              if (empty($skip_bases[$field][$type_name][$base_name])) {
+                $fields[$base_name][$type_name]["$table.$field"] = $type_strings;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // If we have an array of base tables available, go through them
+    // all and add them together. Duplicate keys will be lost and that's
+    // Just Fine.
+    if (is_array($base)) {
+      $strings = array();
+      foreach ($base as $base_table) {
+        if (isset($fields[$base_table][$type])) {
+          $strings += $fields[$base_table][$type];
+        }
+      }
+      uasort($strings, array('self', 'fetchedFieldSort'));
+      return $strings;
+    }
+
+    if (isset($fields[$base][$type])) {
+      uasort($fields[$base][$type], array('self', 'fetchedFieldSort'));
+      return $fields[$base][$type];
+    }
+    return array();
+  }
+
+  /**
+   * Sort function for fetched fields.
+   *
+   * @param array $a
+   *   First item for comparison. The compared items should be associative arrays
+   *   that include a 'group' and a 'title' key.
+   * @param array $b
+   *   Second item for comparison.
+   *
+   * @return int
+   *   Returns -1 if $a comes before $b, 1 other way round and 0 if it cannot be
+   *   decided.
+   */
+  protected static function fetchedFieldSort($a, $b) {
+    $a_group = drupal_strtolower($a['group']);
+    $b_group = drupal_strtolower($b['group']);
+    if ($a_group != $b_group) {
+      return $a_group < $b_group ? -1 : 1;
+    }
+
+    $a_title = drupal_strtolower($a['title']);
+    $b_title = drupal_strtolower($b['title']);
+    if ($a_title != $b_title) {
+      return $a_title < $b_title ? -1 : 1;
+    }
+
+    return 0;
+  }
+
 }
