diff --git a/include/ajax.search.php b/include/ajax.search.php
index 40cd7311050d761e2ad71d76cadbc295db290599..4edad32cac5b6c6acea5666cf5fc1426838940c9 100644
--- a/include/ajax.search.php
+++ b/include/ajax.search.php
@@ -231,7 +231,7 @@ class SearchAjaxAPI extends AjaxController {
 
         // TODO: Update queue columns (but without save)
         foreach ($_POST['columns'] as $colid) {
-            $col = QueueColumn::create(array("id" => $colid));
+            $col = QueueColumn::create(array("id" => $colid, "queue" => $queue));
             $col->update($_POST);
             $queue->addColumn($col);
         }
@@ -248,8 +248,8 @@ class SearchAjaxAPI extends AjaxController {
         if (!$thisstaff) {
             Http::response(403, 'Agent login is required');
         }
-        elseif (!isset($_GET['field'])) {
-            Http::response(400, '`field` parameter is required');
+        elseif (!isset($_GET['field']) || !isset($_GET['id']) || !isset($_GET['colid'])) {
+            Http::response(400, '`field`, `id`, and `colid` parameters required');
         }
         $fields = SavedSearch::getSearchableFields('Ticket');
         if (!isset($fields[$_GET['field']])) {
@@ -258,6 +258,10 @@ class SearchAjaxAPI extends AjaxController {
         }
       
         $field = $fields[$_GET['field']];
+        // Ensure `name` is preserved
+        $field_name = $_GET['field'];
+        $id = $_GET['id'];
+        $column = QueueColumn::create(array('id' => $_GET['colid']));
         $condition = new QueueColumnCondition();
         include STAFFINC_DIR . 'templates/queue-column-condition.tmpl.php';
     }
@@ -268,11 +272,12 @@ class SearchAjaxAPI extends AjaxController {
         if (!$thisstaff) {
             Http::response(403, 'Agent login is required');
         }
-        elseif (!isset($_GET['prop'])) {
-            Http::response(400, '`prop` parameter is required');
+        elseif (!isset($_GET['prop']) || !isset($_GET['condition'])) {
+            Http::response(400, '`prop` and `condition` parameters required');
         }
 
         $prop = $_GET['prop'];
+        $id = $_GET['condition'];
         include STAFFINC_DIR . 'templates/queue-column-condition-prop.tmpl.php';
     }
 
diff --git a/include/class.forms.php b/include/class.forms.php
index 9171b5f90978ab2e4cd4d639ad2d08dffcba564e..71a5c717b778005487445aabfb2acb7192fa80a5 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -4213,7 +4213,7 @@ class VisibilityConstraint {
             else {
                 @list($f, $op) = self::splitFieldAndOp($c);
                 $field = $form->getField($f);
-                $wval = $field->getClean();
+                $wval = $field ? $field->getClean() : null;
                 switch ($op) {
                 case 'eq':
                 case null:
diff --git a/include/class.orm.php b/include/class.orm.php
index 3a51e8cdccffb525c949422f186c49b39b45baae..5c247029590f7bcddbb54d8867e33394ca7a9b20 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -822,7 +822,7 @@ class SqlExpr extends SqlFunction {
         $O = array();
         foreach ($this->args as $field=>$value) {
             if ($value instanceof Q) {
-                $ex = $compiler->compileQ($value);
+                $ex = $compiler->compileQ($value, $model);
                 $O[] = $ex->text;
             }
             else {
@@ -833,7 +833,7 @@ class SqlExpr extends SqlFunction {
                     $O[] = sprintf($op, $field, $compiler->input($value));
             }
         }
-        return implode(' ', $O) . ($alias ? ' AS ' . $alias : '');
+        return implode(' ', $O) . ($alias ? ' AS ' .  $compiler->quote($alias) : '');
     }
 }
 
diff --git a/include/class.queue.php b/include/class.queue.php
index c265952ad3465de3b84bd5eaa4d785fb08e4d9a1..d0aa1c64563d3c4ba32507bd385d843a8c055c94 100644
--- a/include/class.queue.php
+++ b/include/class.queue.php
@@ -284,10 +284,12 @@ extends ChoiceField {
 
 class QueueColumnCondition {
     var $config;
+    var $queue;
     var $properties = array();
 
-    function __construct($config) {
+    function __construct($config, $queue=null) {
         $this->config = $config;
+        $this->queue = $queue;
         if (is_array($config['prop']))
             $this->properties = $config['prop'];
     }
@@ -296,17 +298,34 @@ class QueueColumnCondition {
         return $this->properties;
     }
 
-    function getField() {
-    }
-
     // Add the annotation to a QuerySet
     function annotate($query) {
-        $criteria = $this->config['crit'];
-        $searchable = SavedSearch::getSearchableFields('Ticket');
+        $Q = $this->getSearchQ();
 
-        // Setup a dummy form with a source for field setup
-        $form = new Form($criteria);
-        $fields = array();
+        // Add an annotation to the query
+        return $query->annotate(array(
+            $this->getAnnotationName() => new SqlExpr(array($Q))
+        ));
+    }
+
+    function getSearchQ() {
+        // FIXME
+        #$root = $this->getColumn()->getQueue()->getRoot();
+        $root = 'Ticket';
+        $searchable = SavedSearch::getSearchableFields($root);
+        list($name, $method, $value) = $this->config['crit'];
+
+        // Lookup the field to search this condition
+        if (!isset($searchable[$name]))
+            return null;
+        $field = $searchable[$name];
+
+        // Fetch a criteria Q for the query
+        return $field->getSearchQ($method, $value, $name);
+    }
+
+    static function isolateCriteria($criteria, $root='Ticket') {
+        $searchable = SavedSearch::getSearchableFields($root);
         foreach ($criteria as $k=>$v) {
             if (substr($k, -7) === '+method') {
                 list($name,) = explode('+', $k, 2);
@@ -317,55 +336,66 @@ class QueueColumnCondition {
                 $field = $searchable[$name];
 
                 // Get the search method and value
-                $breakout = SavedSearch::getSearchField($field, $name);
-                $method = $breakout["{$name}+method"];
-                $method->setForm($form);
-                if (!($method = $method->getClean()))
-                    continue;
+                $method = $v;
+                // Not all search methods require a value
+                $value = $criteria["{$name}+{$method}"];
 
-                if (!($value = $breakout["{$name}+{$method}"]))
-                    continue;
-
-                // Fetch a criteria Q for the query
-                $value = $value->getClean();
-                $Q = $field->getSearchQ($method, $value, $name);
-
-                // Add an annotation to the query
-                $query = $query->annotate(array(
-                    $this->getAnnotationName() => new SqlExpr($Q)
-                ));
-
-                // Only one field can be considered in the condition
-                break;
+                return array($name, $method, $value);
             }
         }
-        return $query;
     }
 
     function render($row, $text) {
-        $field = $this->getAnnotationName();
-        if ($V = $row[$field]) {
+        $annotation = $this->getAnnotationName();
+        if ($V = $row[$annotation]) {
             $style = array();
             foreach ($this->getProperties() as $css=>$value) {
-                $style[] = "{$css}:{$value}";
+                $field = QueueColumnConditionProperty::getField($css);
+                $field->value = $value;
+                $V = $field->getClean();
+                if (is_array($V))
+                    $V = current($V);
+                $style[] = "{$css}:{$V}";
             }
             $text = sprintf('<span style="%s">%s</span>',
-                implode(' ', $style), $text);
+                implode(';', $style), $text);
         }
         return $text;
     }
 
     function getAnnotationName() {
-        return 'howdy';
+        // This should be predictable based on the criteria so that the
+        // query can deduplicate the same annotations used in different
+        // conditions
+        if (!isset($this->annotation_name)) {
+            $this->annotation_name = $this->getShortHash();
+        }
+        return $this->annotation_name;
     }
 
-    static function fromJson($config) {
+    function __toString() {
+        list($name, $method, $value) = $this->config['crit'];
+        if (is_array($value))
+            $value = implode('+', $value);
+
+        return "{$name} {$method} {$value}";
+    }
+
+    function getHash($binary=false) {
+        return sha1($this->__toString(), $binary);
+    }
+
+    function getShortHash() {
+        return substr($this->getHash(), -10);
+    }
+
+    static function fromJson($config, $queue=null) {
         if (is_string($config))
-            $config = JsonDataParser::decode($cnofig);
+            $config = JsonDataParser::decode($config);
         if (!is_array($config))
             throw new BadMethodCallException('$config must be string or array');
 
-        return new static($config);
+        return new static($config, $queue);
     }
 }
 
@@ -399,17 +429,20 @@ extends ChoiceField {
     }
 
     static function getProperties() {
-        return array_keys(static::$properties[$this->property]);
+        return array_keys(static::$properties);
     }
 
     static function getField($prop) {
         $choices = static::$properties[$prop];
+        if (!isset($choices))
+            return null;
         if (is_array($choices))
             return new ChoiceField(array(
+                'name' => $prop,
                 'choices' => array_combine($choices, $choices),
             ));
         elseif (class_exists($choices))
-            return new $choices();
+            return new $choices(array('name' => $prop));
     }
 
     function getChoices() {
@@ -629,7 +662,7 @@ extends VerySimpleModel {
 
         // Do the decorations
         $this->_decorations = $this->decorations = array();
-        foreach ($vars['decorations'] as $i=>$class) {
+        foreach (@$vars['decorations'] as $i=>$class) {
             if (!class_exists($class) || !is_subclass_of($class, 'QueueDecoration'))
                 continue;
             if ($vars['deco_column'][$i] != $this->id)
@@ -638,8 +671,54 @@ extends VerySimpleModel {
             $this->_decorations[] = QueueDecoration::fromJson($json);
             $this->decorations[] = $json;
         }
+
+        // Do the conditions
+        $this->_conditions = $this->conditions = array();
+        foreach (@$vars['conditions'] as $i=>$id) {
+            if ($vars['condition_column'][$i] != $this->id)
+                // Not a condition for this column
+                continue;
+            // Determine the criteria
+            $name = $vars['condition_field'][$i];
+            $fields = SavedSearch::getSearchableFields($this->getQueue()->getRoot());
+            if (!isset($fields[$name]))
+                // No such field exists for this queue root type
+                continue;
+            $field = $fields[$name];
+            $parts = SavedSearch::getSearchField($field, $name);
+            $search_form = new SimpleForm($parts, $vars, array('id' => $id));
+            $search_form->getField("{$name}+search")->value = true;
+            $crit = $search_form->getClean();
+            // Check the box to enable searching on the field
+            $crit["{$name}+search"] = true;
+
+            // Convert search criteria to a Q instance
+            $crit = QueueColumnCondition::isolateCriteria($crit);
+
+            // Determine the properties
+            $props = array();
+            foreach ($vars['properties'] as $i=>$cid) {
+                if ($cid != $id)
+                    // Not a property for this condition
+                    continue;
+
+                // Determine the property configuration
+                $prop = $vars['property_name'][$i];
+                if (!($F = QueueColumnConditionProperty::getField($prop))) {
+                    // Not a valid property
+                    continue;
+                }
+                $prop_form = new SimpleForm(array($F), $vars, array('id' => $cid));
+                $props[$prop] = $prop_form->getClean();
+            }
+            $json = array('crit' => $crit, 'prop' => $props);
+            $this->_conditions[] = QueueColumnCondition::fromJson($json);
+            $this->conditions[] = $json;
+        }
+
         // Store as JSON array
         $this->decorations = JsonDataEncoder::encode($this->decorations);
+        $this->conditions = JsonDataEncoder::encode($this->conditions);
     }
 }
 
diff --git a/include/staff/templates/queue-column-condition-prop.tmpl.php b/include/staff/templates/queue-column-condition-prop.tmpl.php
index f29f5947d99b6a57f73df9aa96648b261cb0b0af..be7a820a4efc9fc60c5073e612a8a35db3a7d9bc 100644
--- a/include/staff/templates/queue-column-condition-prop.tmpl.php
+++ b/include/staff/templates/queue-column-condition-prop.tmpl.php
@@ -2,12 +2,14 @@
 /**
  * Calling conventions
  *
- * $name - condition field name, like 'thread__lastmessage'
+ * $id - temporary condition ID number for the property
  * $prop - CSS property name from QueueColumnConditionProperty::$properties
  * $v - value for the property
  */
 ?>
 <div class="condition-property">
+  <input type="hidden" name="properties[]" value="<?php echo $id; ?>" />
+  <input type="hidden" name="property_name[]" value="<?php echo $prop; ?>" />
   <div class="pull-right">
     <a href="#" onclick="javascript:$(this).closest('.condition-property').remove()"
       ><i class="icon-trash"></i></a>
@@ -15,9 +17,8 @@
   <div><?php echo mb_convert_case($prop, MB_CASE_TITLE); ?></div>
 <?php
     $F = QueueColumnConditionProperty::getField($prop);
-    $F->set('name', "prop-{$name}-{$prop}");
     $F->value = $v;
-    $form = new SimpleForm(array($F), $_POST);
+    $form = new SimpleForm(array($F), false, array('id' => $id));
     echo $F->render();
     echo $form->getMedia();
 ?>
diff --git a/include/staff/templates/queue-column-condition.tmpl.php b/include/staff/templates/queue-column-condition.tmpl.php
index d445f4f4d1ac567018b55fc414b876673c5a605f..1c1684b43b62491d2e7e92b5e813d45f2d808d97 100644
--- a/include/staff/templates/queue-column-condition.tmpl.php
+++ b/include/staff/templates/queue-column-condition.tmpl.php
@@ -4,8 +4,15 @@
 // $field - field for the condition (Ticket / Last Update)
 // $properties - currently-configured properties for the condition
 // $condition - <QueueColumnCondition> instance for this condition
+// $column - <QueueColumn> to which the condition belongs
+// $id - temporary ID number for the condition
+// $field_name - search path / name for the field
 ?>
 <div class="condition">
+  <input name="conditions[]" value="<?php echo $id; ?>" type="hidden" />
+  <input name="condition_column[]" value="<?php echo $column->getId(); ?>"
+    type="hidden" />
+  <input name="condition_field[]" value="<?php echo $field_name; ?>" type="hidden" />
   <div class="pull-right">
     <a href="#" onclick="javascript: $(this).closest('.condition').remove();
       "><i class="icon-trash"></i></a>
@@ -13,16 +20,15 @@
   <?php echo $field->get('label'); ?>
   <div class="advanced-search">
 <?php
-$name = $field->get('name');
-$parts = SavedSearch::getSearchField($field, $name);
+$parts = SavedSearch::getSearchField($field, $field_name);
 // Drop the search checkbox field
-unset($parts["{$name}+search"]);
+unset($parts["{$field_name}+search"]);
 foreach ($parts as $name=>$F) {
     if (substr($name, -7) == '+method')
         // XXX: Hack
         unset($F->ht['visibility']);
 }
-$form = new SimpleForm($parts);
+$form = new SimpleForm($parts, false, array('id' => $id));
 foreach ($form->getFields() as $F) { ?>
     <fieldset id="field<?php echo $F->getWidget()->id;
         ?>" <?php
@@ -44,7 +50,8 @@ foreach ($form->getFields() as $F) { ?>
 <?php } ?>
 
     <div class="properties" style="margin-left: 25px; margin-top: 10px">
-<?php foreach ($condition->getProperties() as $prop=>$v) {
+<?php
+foreach ($condition->getProperties() as $prop=>$v) {
     include 'queue-column-condition-prop.tmpl.php';
 } ?>
       <div style="margin-top: 10px">
@@ -55,7 +62,7 @@ foreach ($form->getFields() as $F) { ?>
             container = $this.closest('.properties');
         $.ajax({
           url: 'ajax.php/queue/condition/addProperty',
-          data: { prop: selected.val() },
+          data: { prop: selected.val(), condition: <?php echo $id; ?> },
           dataType: 'html',
           success: function(html) {
             $(html).insertBefore(container);
diff --git a/include/staff/templates/queue-column.tmpl.php b/include/staff/templates/queue-column.tmpl.php
index 925687ea345cf063a867f4eecb28b6ee2afa93df..5d2f23e6f57c6ef5c5ecfbe39c8230049f7e6400 100644
--- a/include/staff/templates/queue-column.tmpl.php
+++ b/include/staff/templates/queue-column.tmpl.php
@@ -113,18 +113,7 @@ $data_form = $column->getDataConfigForm($_POST);
 } ?>
     <div style="margin-top: 20px">
       <i class="icon-plus-sign"></i>
-      <select id="add-condition" onchange="javascript:
-      var $this = $(this),
-          container = $this.closest('div');
-      $.ajax({
-        url: 'ajax.php/queue/condition/add',
-        data: { field: $(this).find(':selected').val() },
-        dataType: 'html',
-        success: function(html) {
-          $(html).insertBefore(container);
-        }
-      });
-      ">
+      <select class="add-condition">
         <option>— <?php echo __("Add a condition"); ?> —</option>
 <?php
       foreach (SavedSearch::getSearchableFields('Ticket') as $path=>$f) {
@@ -132,6 +121,26 @@ $data_form = $column->getDataConfigForm($_POST);
       }
 ?>
       </select>
+      <script>
+      $(function() {
+        var colid = <?php echo $colid ?: 0 ?>,
+            nextid = colid * 40;
+        $('#' + colid + '-conditions select.add-condition').change(function() {
+          var $this = $(this),
+              container = $this.closest('div'),
+              selected = $this.find(':selected');
+          $.ajax({
+            url: 'ajax.php/queue/condition/add',
+            data: { field: selected.val(), colid: colid, id: nextid },
+            dataType: 'html',
+            success: function(html) {
+              $(html).insertBefore(container);
+              nextid++;
+            }
+          });
+        });
+      });
+      </script>
     </div>
   </div>
 </div>