diff --git a/includes/fields.inc b/includes/fields.inc
index 162262c..2cb46fd 100644
--- a/includes/fields.inc
+++ b/includes/fields.inc
@@ -170,8 +170,6 @@ function ctools_field_label($field_name) {
  *
  * @param $field_name
  *   Either a field instance object or the name of the field.
- *   If the 'field' key is populated it will be used as the field
- *   settings.
  * @param $op
  *   Possible operations include:
  *   - form
@@ -221,10 +219,9 @@ function ctools_field_label($field_name) {
  *
  * @see _field_invoke()
  */
-function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
+function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array(), $field = NULL) {
   if (is_array($field_name)) {
     $instance = $field_name;
-    $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field'];
     $field_name = $instance['field_name'];
   }
   else {
@@ -248,6 +245,10 @@ function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a
 
   // Everything from here is unmodified code from _field_invoke() formerly
   // inside a foreach loop over the instances.
+  if (!isset($field)) {
+    $field = field_info_field($field_name);
+  }
+
   $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
   if (function_exists($function)) {
     // Determine the list of languages to iterate on.
diff --git a/plugins/access/entity_field_value.inc b/plugins/access/entity_field_value.inc
index e5857d8..3b8442c 100644
--- a/plugins/access/entity_field_value.inc
+++ b/plugins/access/entity_field_value.inc
@@ -9,8 +9,9 @@ $plugin = array(
   'title' => t("(Custom) Entity: Field Value"),
   'description' => t('Control access by entity field value.'),
   'callback' => 'ctools_entity_field_value_ctools_access_check',
-  'default' => array('type' => array()),
+  'default' => array('operator' => '==', 'type' => array()),
   'settings form' => 'ctools_entity_field_value_ctools_access_settings',
+  'settings form validate' => 'ctools_entity_field_value_ctools_access_settings_validate',
   'settings form submit' => 'ctools_entity_field_value_ctools_access_settings_submit',
   'summary' => 'ctools_entity_field_value_ctools_access_summary',
   'get child' => 'ctools_entity_field_value_ctools_access_get_child',
@@ -64,6 +65,11 @@ function _ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $e
     $field = $field_instances[$field_name];
   }
 
+  // @todo We should consider only supporting basic, core field types and add some way of
+  // altering in other fields that have been tested first.
+
+  // For example, field collection fields are a total fail here.
+
   $plugin['title'] = t('@entity @type: @field Field', array('@entity' => $entity['label'], '@type' => $bundle_type, '@field' => $field['label']));
   $plugin['keyword'] = $entity_type;
   $plugin['description'] = t('Control access by @entity entity bundle.', array('@entity' => $entity_type));
@@ -89,49 +95,67 @@ function ctools_entity_field_value_ctools_access_settings($form, &$form_state, $
     $columns[] = _field_sql_storage_columnname($field_name, $column);
   }
   ctools_include('fields');
+
+  // Make sure this is always set, as it won't be on new fields.
+  if (!isset($conf[$field_name])) {
+    $conf[$field_name] = array();
+  }
+
+  // Make a fake entity with our field.
   $entity = (object)array(
     $entity_info['entity keys']['bundle'] => $bundle_type,
+    $field_name => $conf[$field_name],
   );
   $langcode = field_valid_language(NULL);
-  $form['settings'] += (array) ctools_field_invoke_field($instance, 'form', $entity_type, $entity, $form, $form_state, array('default' => TRUE, 'language' => $langcode));
+
+  $form['settings']['operator'] = array(
+    '#title' => t('Operator'),
+    '#type' => 'select',
+    '#default_value' => isset($conf['operator']) ? $conf['operator'] : '==',
+    '#options' => array(
+      '==' => '==',
+      '!=' => '!=',
+      '>' => '>',
+      '>=' => '>=',
+      '<' => '<',
+      '<=' => '<=',
+      'regex' => t('Regular expression'),
+      '!regex' => t('Not equal to regular expression'),
+    )
+  );
+
+  $form['#parents'] = array('settings');
+
+  // Regardless of actual status of the field, for our comparison we want 1 and only 1:
+  $field['cardinality'] = 1;
+
+  $form['settings'] += (array) ctools_field_invoke_field($instance, 'form', $entity_type, $entity, $form, $form_state, array('default' => TRUE, 'language' => $langcode), $field);
+  _ctools_entity_field_value_ctools_access_remove_required($form);
+
   // weight is really not important once this is populated and will only interfere with the form layout.
   foreach (element_children($form['settings']) as $element) {
     unset($form['settings'][$element]['#weight']);
   }
 
-  // Need more logic here to handle compound fields.
-  foreach ($columns as $column) {
-    if (isset($conf[$column]) && is_array($conf[$column])) {
-      foreach ($conf[$column] as $delta => $conf_value) {
-        if (is_numeric($delta) && is_array($conf_value)) {
-          $form['settings'][$field_name][LANGUAGE_NONE][$delta]['value']['#default_value'] = $conf_value['value'];
-        }
-      }
-    }
-    else {
-      $form['settings'][$field_name][LANGUAGE_NONE]['#default_value'] = $conf[$column];
-    }
+  // Special support for lists.
+  if ($field['module'] == 'list') {
+    $form['settings'][$field_name][LANGUAGE_NONE]['#type'] = 'select';
+    $form['settings'][$field_name][LANGUAGE_NONE]['#multiple'] = TRUE;
+    $form['settings'][$field_name][LANGUAGE_NONE]['#description'] = t('If you select more than one, only == or != operators will work.');
   }
-
   return $form;
 }
 
 /**
- * Compress the entity bundles allowed to the minimum.
+ * Recursively remove #required options from a form.
  */
-function ctools_entity_field_value_ctools_access_settings_submit($form, &$form_state) {
-  $plugin = $form_state['plugin'];
-  list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']);
-  $langcode  = field_valid_language(NULL);
-  $langcode  = isset($form_state['input']['settings'][$field_name][$langcode]) ? $langcode : LANGUAGE_NONE;
-  $instances = field_info_instances($entity_type, $bundle_type);
-  $instance  = $instances[$field_name];
-  $field     = field_info_field_by_id($instance['field_id']);
-  foreach ($field['columns'] as $column => $attributes) {
-    $columns[] = _field_sql_storage_columnname($field_name, $column);
+function _ctools_entity_field_value_ctools_access_remove_required(&$form) {
+  if (!empty($form['#required'])) {
+    unset($form['#required']);
   }
-  foreach ($columns as $column) {
-    $form_state['values']['settings'][$column] = $form_state['input']['settings'][$field_name][$langcode];
+
+  foreach (element_children($form) as $key) {
+    _ctools_entity_field_value_ctools_access_remove_required($form[$key]);
   }
 }
 
@@ -140,42 +164,86 @@ function ctools_entity_field_value_ctools_access_settings_submit($form, &$form_s
  */
 function ctools_entity_field_value_ctools_access_check($conf, $context, $plugin) {
   list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']);
+  $instances   = field_info_instances($entity_type, $bundle_type);
+  $instance    = $instances[$field_name];
+  $field       = field_info_field_by_id($instance['field_id']);
+
+  $operator = isset($conf['operator']) ? $conf['operator'] : '==';
 
-  if ($field_items = field_get_items($entity_type, $context->data, $field_name)) {
-    $langcode = field_language($entity_type, $context->data, $field_name);
-    // Get field storage columns.
-    $instance = field_info_instance($entity_type, $field_name, $bundle_type);
-    $field = field_info_field_by_id($instance['field_id']);
-    $columns = array();
-    foreach ($field['columns'] as $column => $attributes) {
-      $columns[$column] = _field_sql_storage_columnname($field_name, $column);
+  // The right side is what is in configuration.
+  $conf_value_array = $conf[$field_name][LANGUAGE_NONE];
+
+  // Special support for the list handling!
+  if ($field['module'] == 'list' && count($conf_value_array) > 1 && ($operator == '==' || $operator == '!=')) {
+    if ($operator == '==') {
+      $operator = 'in';
+    }
+    elseif ($operator == '!=') {
+      $operator = 'not in';
+    }
+    $right = array();
+    foreach ($conf_value_array as $value) {
+      $right[] = reset($value);
+    }
+  }
+  else {
+    // Get the first delta, as there should be only one.
+    $right = reset($conf_value_array);
+    // If there are columns, get only the first column.
+    if (is_array($right)) {
+      $right = reset($right);
     }
+  }
 
-    if (isset($conf[$field_name])) {
-      // We have settings for this field.
-      $conf_value_array = _ctools_entity_field_value_ctools_access_get_conf_field_values($conf[$field_name], $langcode);
-      if (empty($conf_value_array)) {
-        return FALSE;
-      }
+  // The left side is what's in the field.
+  if (!empty($context->data)) {
+    $field_items = field_get_items($entity_type, $context->data, $field_name);
+  }
 
-      // Check field value.
-      foreach ($field_items as $field_value) {
-        foreach ($field_value as $field_column => $value) {
-          // Iterate through config values.
-          foreach ($conf_value_array as $conf_value) {
-            // Check access only for stored in config column values.
-            if (isset($conf_value[$field_column]) && $value == $conf_value[$field_column]) {
-              return TRUE;
-            }
-          }
-        }
-      }
+  // If there aren't any field items, make an empty one so that we can test properly.
+  if (empty($field_items)) {
+    $field_items = array(array('value' => ''));
+  }
+
+  // Check field value. For multiples, we check if any one of them passes.
+  foreach ($field_items as $field_value) {
+    $left = reset($field_value);
+    if (_ctools_entity_field_compare($left, $operator, $right)) {
+      return TRUE;
     }
   }
 
   return FALSE;
 }
 
+function _ctools_entity_field_compare($left, $operator, $right) {
+  switch ($operator) {
+    case '==':
+      return $left == $right;
+    case '!=':
+      return $left != $right;
+    case '>':
+      return $left > $right;
+    case '>=':
+      return $left >= $right;
+    case '<':
+      return $left < $right;
+    case '<=':
+      return $left <= $right;
+    case 'regex':
+      return preg_match($left, $right);
+    case '!regex':
+      return !preg_match($left, $right);
+    case 'in':
+      return in_array($left, $right);
+    case 'not in':
+      return !in_array($left, $right);
+
+    default:
+      return FALSE;
+  }
+}
+
 function _ctools_entity_field_value_ctools_access_get_conf_field_values($values, $langcode = LANGUAGE_NONE) {
   if (!is_array($values) || !isset($values[$langcode])) {
     return;
@@ -200,42 +268,49 @@ function ctools_entity_field_value_ctools_access_summary($conf, $context, $plugi
   $entity_info = entity_get_info($entity_type);
   $entity      = (object)array(
     $entity_info['entity keys']['bundle'] => $bundle_type,
+    $field_name => $conf[$field_name],
   );
-  $string = '';
-  $keys   = array();
-  $values = array();
-  foreach ($field['columns'] as $column => $attributes) {
-    $conf_key = _field_sql_storage_columnname($field_name, $column);
-    if (count($field['columns']) > 1) {
-      // Add some sort of handling for compound fields
-    }
-    else {
-      if (isset($conf[$conf_key])) {
-        $entity->{$field_name}[LANGUAGE_NONE][] = array($column => $conf[$conf_key]);
-      }
+
+  $operator = isset($conf['operator']) ? $conf['operator'] : '==';
+
+  $render_array = field_view_field($entity_type, $entity, $field_name);
+
+  // Special support for lists.
+  if ($field['module'] == 'list' && count($conf[$field_name][LANGUAGE_NONE]) > 1 && ($operator == '==' || $operator == '!=')) {
+    if ($operator == '==') {
+      $operator = 'is one of';
     }
-    $string .= " @{$column} equals @{$column}_value";
-    $keys['@' . $column] = $column;
-    $values["@{$column}_value"] = $conf[$conf_key];
-  }
-  $view_mode = 'full';
-  $null      = NULL;
-  $options   = array('language' => LANGUAGE_NONE);
-  ctools_include('fields');
-  $display         = field_get_display($instance, $view_mode, $entity);
-  if (isset($display['module'])) {
-    $display['type'] = 'list_default';
-    $function        = $display['module'] . '_field_formatter_view';
-    $items           = isset($entity->{$field_name}[LANGUAGE_NONE]) ? $entity->{$field_name}[LANGUAGE_NONE] : array();
-    if (function_exists($function)) {
-      $elements = $function($entity_type, $entity, $field, $instance, LANGUAGE_NONE, $items, $display);
+    if ($operator == '!=') {
+      $operator = 'is not one of';
     }
-    $value_keys = array_keys($values);
-    foreach ($value_keys as $key => $value) {
-      $values[$value] = isset($elements[$key]['#markup']) ? $elements[$key]['#markup'] : '';
+
+    $values = array();
+    foreach (array_keys($conf[$field_name][LANGUAGE_NONE]) as $index) {
+      $values[] = drupal_render($render_array[$index]);
     }
+    $value = implode(', ', $values);
+  }
+
+  if (!isset($value)) {
+    // We don't want the field template or label or anything, just the value.
+    $value = drupal_render($render_array[0]);
   }
-  $values = array_merge($keys, $values);
-  return t($string, $values);
+
+  $values = array(
+    '@identifier' => $context->identifier,
+    '@field' => $instance['label'],
+    '!value' => $value,
+    '@operator' => $operator,
+  );
+
+  if ($values['@operator'] == 'regex') {
+    $values['@operator'] = t('matches');
+  }
+
+  if ($values['@operator'] == '!regex') {
+    $values['@operator'] = t('does not match');
+  }
+
+  return t('@identifier @field @operator "!value"', $values);
 }
 
