diff --git a/include/ajax.search.php b/include/ajax.search.php
index d8ce8dbab1b4ef7443b5a3b664cdac63f3ce4425..93da251e7d164e9548550dce3b35cf16051bbcf3 100644
--- a/include/ajax.search.php
+++ b/include/ajax.search.php
@@ -366,7 +366,7 @@ class SearchAjaxAPI extends AjaxController {
         $field_name = $_GET['field'];
         $id = $_GET['id'];
         $object_id = $_GET['object_id'];
-        $condition = new QueueColumnCondition();
+        $condition = new QueueColumnCondition(array());
         include STAFFINC_DIR . 'templates/queue-column-condition.tmpl.php';
     }
 
diff --git a/include/class.list.php b/include/class.list.php
index b504d1bb94437b15ff973555ef73a209df3a31bf..e5c84fbd91b58cc2f8dc742bbec745bba1151882 100644
--- a/include/class.list.php
+++ b/include/class.list.php
@@ -1282,7 +1282,7 @@ implements CustomListItem, TemplateVariable, Searchable {
             'state' => new TicketStateChoiceField(array(
                 'label' => __('State'),
             )),
-            'name' => new TextBoxField(array(
+            'id' => new TicketStatusChoiceField(array(
                 'label' => __('Status Name'),
             )),
         );
diff --git a/include/class.queue.php b/include/class.queue.php
index 62e1ef5dcab6dcb81540ccf18ae82d3f1dd7612c..dfa3846425c8d86c867d491f52c2b75be4fafb1e 100644
--- a/include/class.queue.php
+++ b/include/class.queue.php
@@ -118,12 +118,13 @@ class CustomQueue extends VerySimpleModel {
 
     function getCriteria($include_parent=false) {
         if (!isset($this->criteria)) {
-            $old = @$this->config[0] === '{';
             $this->criteria = is_string($this->config)
                 ? JsonDataParser::decode($this->config)
                 : $this->config;
+            // XXX: Drop this block in v1.12
             // Auto-upgrade v1.10 saved-search criteria to new format
             // But support new style with `conditions` support
+            $old = @$this->config[0] === '{';
             if ($old && is_array($this->criteria)
                 && !isset($this->criteria['conditions'])
             ) {
@@ -641,7 +642,10 @@ class CustomQueue extends VerySimpleModel {
             && $this->hasFlag(self::FLAG_INHERIT_COLUMNS)
             && $this->parent
         ) {
-            return $this->parent->getColumns();
+            $columns = $this->parent->getColumns();
+            foreach ($columns as $c)
+                $c->setQueue($this);
+            return $columns;
         }
         elseif (count($this->columns)) {
             return $this->columns;
@@ -1214,9 +1218,10 @@ class CustomQueue extends VerySimpleModel {
             $errors['criteria'] = __('Validation errors exist on criteria');
         }
         else {
+            $this->criteria = static::isolateCriteria($form->getClean(),
+                $this->getRoot());
             $this->config = JsonDataEncoder::encode([
-                'criteria' => self::isolateCriteria($form->getClean(),
-                    $this->getRoot()),
+                'criteria' => $this->criteria,
                 'conditions' => $conditions,
             ]);
             // Clear currently set criteria.and conditions.
@@ -1260,6 +1265,44 @@ class CustomQueue extends VerySimpleModel {
             && $this->sorts->saveAll();
     }
 
+    /**
+     * Fetch a tree-organized listing of the queues. Each queue is listed in
+     * the tree exactly once, and every visible queue is represented. The
+     * returned structure is an array where the items are two-item arrays
+     * where the first item is a CustomQueue object an the second is a list
+     * of the children using the same pattern (two-item arrays of a CustomQueue
+     * and its children). Visually:
+     *
+     * [ [ $queue, [ [ $child, [] ], [ $child, [] ] ], [ $queue, ... ] ]
+     *
+     * Parameters:
+     * $staff - <Staff> staff object which should be used to determine
+     *      visible queues.
+     * $pid - <int> parent_id of root queue. Default is zero (top-level)
+     */
+    static function getHierarchicalQueues(Staff $staff, $pid=0) {
+        $all = static::objects()
+            ->filter(Q::any(array(
+                'flags__hasbit' => self::FLAG_PUBLIC,
+                'flags__hasbit' => static::FLAG_QUEUE,
+                'staff_id' => $staff->getId(),
+            )))
+            ->exclude(['flags__hasbit' => self::FLAG_DISABLED])
+            ->asArray();
+
+        // Find all the queues with a given parent
+        $for_parent = function($pid) use ($all, &$for_parent) {
+            $results = [];
+            foreach (new \ArrayIterator($all) as $q) {
+                if ($q->parent_id == $pid)
+                    $results[] = [ $q, $for_parent($q->getId()) ];
+            }
+            return $results;
+        };
+
+        return $for_parent($pid);
+    }
+
     static function getOrmPath($name, $query=null) {
         // Special case for custom data `__answers!id__value`. Only add the
         // join and constraint on the query the first pass, when the query
@@ -1684,7 +1727,8 @@ class QueueColumnCondition {
 
     // Add the annotation to a QuerySet
     function annotate($query) {
-        $Q = $this->getSearchQ($query);
+        if (!($Q = $this->getSearchQ($query)))
+            return $query;
 
         // Add an annotation to the query
         return $query->annotate(array(
@@ -1929,6 +1973,7 @@ extends VerySimpleModel {
 
     var $_annotations;
     var $_conditions;
+    var $_queue;            // Apparent queue if being inherited
 
     function getId() {
         return $this->id;
@@ -1947,7 +1992,15 @@ extends VerySimpleModel {
     // These getters fetch data from the annotated overlay from the
     // queue_column table
     function getQueue() {
-        return $this->queue;
+        return $this->_queue ?: $this->queue;
+    }
+    /**
+     * If a column is inherited into a child queue and there are conditions
+     * added to that queue, then the column will need to be linked at
+     * run-time to the child queue rather than the parent.
+     */
+    function setQueue(CustomQueue $queue) {
+        $this->_queue = $queue;
     }
 
     function getWidth() {
@@ -1993,7 +2046,7 @@ extends VerySimpleModel {
         $text = $this->renderBasicValue($row);
 
         // Filter
-        if ($filter = $this->getFilter()) {
+        if ($text && ($filter = $this->getFilter())) {
             $text = $filter->filter($text, $row) ?: $text;
         }
 
diff --git a/include/class.search.php b/include/class.search.php
index a061cb58eecf3f153b3209c36cf377c7a2d7099c..be17902260dd53b308ffdd3a47ad30156ac7d811 100644
--- a/include/class.search.php
+++ b/include/class.search.php
@@ -1408,6 +1408,8 @@ class TicketStatusChoiceField extends SelectionField {
 
     function getSearchQ($method, $value, $name=false) {
         $name = $name ?: $this->get('name');
+        if (!$value)
+            return false;
         switch ($method) {
         case '!includes':
             return Q::not(array("{$name}__in" => array_keys($value)));
diff --git a/include/staff/queue.inc.php b/include/staff/queue.inc.php
index 8506fbee9d1ce3d78b429fe74c969f7f2771f158..b936699df859013ba8706f9c27daba2c310a840e 100644
--- a/include/staff/queue.inc.php
+++ b/include/staff/queue.inc.php
@@ -346,6 +346,8 @@ if ($queue->getConditions()) {
   foreach ($queue->getConditions() as $i=>$condition) {
      $id = QueueColumnCondition::getUid();
      list($label, $field) = $condition->getField();
+     if (!$field || !$label)
+        continue;
      $field_name = $condition->getFieldName();
      $object_id = $queue->id;
      include STAFFINC_DIR . 'templates/queue-column-condition.tmpl.php';
diff --git a/include/staff/templates/queue-column.tmpl.php b/include/staff/templates/queue-column.tmpl.php
index 806825ad4ade38dbb6c33052c38e1be774626a2d..3ca9d9a310268851e76d061b1b88d8fadbee2c33 100644
--- a/include/staff/templates/queue-column.tmpl.php
+++ b/include/staff/templates/queue-column.tmpl.php
@@ -122,6 +122,8 @@ if ($column->getConditions(false)) {
   foreach ($column->getConditions() as $i=>$condition) {
      $id = QueueColumnCondition::getUid();
      list($label, $field) = $condition->getField();
+     if (!$label || !$field)
+        continue;
      $field_name = $condition->getFieldName();
      $object_id = $column->getId();
      include STAFFINC_DIR . 'templates/queue-column-condition.tmpl.php';
diff --git a/include/staff/templates/queue-columns.tmpl.php b/include/staff/templates/queue-columns.tmpl.php
index 6088c925de0233116b5e39d457741dcb9d3ec9d6..fd8e99529a4ac346ebdfa177b100a735ae5fa9a4 100644
--- a/include/staff/templates/queue-columns.tmpl.php
+++ b/include/staff/templates/queue-columns.tmpl.php
@@ -1,12 +1,13 @@
 <div style="overflow-y: auto; height:auto; max-height: 350px;">
 <table class="table">
 <?php
+$hidden_cols = $queue->inheritColumns() || count($queue->columns) === 0;
 if ($queue->parent) { ?>
   <tbody>
     <tr>
       <td colspan="3">
         <input type="checkbox" name="inherit-columns" <?php
-          if ($queue->inheritColumns()) echo 'checked="checked"'; ?>
+          if ($hidden_cols) echo 'checked="checked"'; ?>
           onchange="javascript:$(this).closest('table').find('.if-not-inherited').toggle(!$(this).prop('checked'));" />
         <?php echo __('Inherit columns from the parent queue'); ?>
         <br /><br />
diff --git a/include/staff/templates/queue-navigation.tmpl.php b/include/staff/templates/queue-navigation.tmpl.php
index b903f29fd12e025df3e519af361d0eb693e89a52..3e40918fd8f94efdd80c27d285b626c5e3aff58f 100644
--- a/include/staff/templates/queue-navigation.tmpl.php
+++ b/include/staff/templates/queue-navigation.tmpl.php
@@ -4,6 +4,7 @@
 // $q - <CustomQueue> object for this navigation entry
 // $selected - <bool> true if this queue is currently active
 // $child_selected - <bool> true if the selected queue is a descendent
+$childs = $children;
 $this_queue = $q;
 $selected = (!isset($_REQUEST['a'])  && $_REQUEST['queue'] == $this_queue->getId());
 ?>
@@ -28,8 +29,21 @@ $selected = (!isset($_REQUEST['a'])  && $_REQUEST['queue'] == $this_queue->getId
       </li>
 
       <!-- Start Dropdown and child queues -->
-      <?php foreach ($this_queue->getPublicChildren() as $q) {
-          include 'queue-subnavigation.tmpl.php';
+      <?php foreach ($childs as $_) {
+          list($q, $children) = $_;
+          if (!$q->isPrivate())
+              include 'queue-subnavigation.tmpl.php';
+      }
+      $first_child = true;
+      foreach ($childs as $_) {
+        list($q, $children) = $_;
+        if (!$q->isPrivate())
+            continue;
+        if ($first_child) {
+            $first_child = false;
+            echo '<li class="personalQ"></li>';
+        }
+        include 'queue-subnavigation.tmpl.php';
       } ?>
       <!-- Personal Queues -->
       <?php
diff --git a/include/staff/templates/queue-savedsearches-nav.tmpl.php b/include/staff/templates/queue-savedsearches-nav.tmpl.php
index 4899b794a2edce13e0cc6009f6f23beb883cb1e4..ef06cf06c91db2b6e5a32ea0395885cc8d05cd25 100644
--- a/include/staff/templates/queue-savedsearches-nav.tmpl.php
+++ b/include/staff/templates/queue-savedsearches-nav.tmpl.php
@@ -18,11 +18,13 @@
       <!-- Start Dropdown and child queues -->
       <?php foreach ($searches->findAll(array(
             'staff_id' => $thisstaff->getId(),
+            'parent_id' => 0,
             Q::not(array(
                 'flags__hasbit' => CustomQueue::FLAG_PUBLIC
             ))
       )) as $q) {
-        include 'queue-subnavigation.tmpl.php';
+        if ($q->checkAccess($thisstaff))
+            include 'queue-subnavigation.tmpl.php';
       } ?>
      <?php
      if (isset($_SESSION['advsearch'])) { ?>
diff --git a/include/staff/templates/queue-subnavigation.tmpl.php b/include/staff/templates/queue-subnavigation.tmpl.php
index b0cbeeb75d98b1db5ac61e7004b1cd20aa48c732..fa33b7b7223e23097ee83b1b5a55013efea4c994 100644
--- a/include/staff/templates/queue-subnavigation.tmpl.php
+++ b/include/staff/templates/queue-subnavigation.tmpl.php
@@ -1,10 +1,9 @@
 <?php
 // Calling conventions
 // $q - <CustomQueue> object for this navigation entry
+// $children - <Array<CustomQueue>> all direct children of this queue
 $queue = $q;
-$children = !$queue instanceof SavedSearch ? $queue->getPublicChildren() : array();
-$subq_searches = !$queue instanceof SavedSearch ? $queue->getMyChildren() : array();
-$hasChildren = count($children) + count($subq_searches) > 0;
+$hasChildren = count($children) > 0;
 $selected = $_REQUEST['queue'] == $q->getId();
 global $thisstaff;
 ?>
@@ -27,24 +26,30 @@ global $thisstaff;
     </a>
 
     <?php
-    $closure_include = function($q) use ($thisstaff, $ost, $cfg) {
+    $closure_include = function($q, $children) {
         global $thisstaff, $ost, $cfg;
         include __FILE__;
     };
     if ($hasChildren) { ?>
     <ul class="subMenuQ">
     <?php
-    foreach ($children as $q)
-        $closure_include($q);
+    foreach ($children as $_) {
+        list($q, $childs) = $_;
+        if (!$q->isPrivate())
+          $closure_include($q, $childs);
+    }
 
     // Include personal sub-queues
     $first_child = true;
-    foreach ($subq_searches as $q) {
-      if ($first_child) {
+    foreach ($children as $_) {
+      list($q, $childs) = $_;
+      if ($q->isPrivate()) {
+        if ($first_child) {
           $first_child = false;
           echo '<li class="personalQ"></li>';
+        }
+        $closure_include($q, $childs);
       }
-      $closure_include($q);
     } ?>
     </ul>
 <?php
diff --git a/scp/tickets.php b/scp/tickets.php
index 450403f99b1639037ba303f06f8cbfbb99c944fe..82e9b07032bb34897244e6bd88691a8ef6dd5aab 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -445,19 +445,14 @@ $nav->setTabActive('tickets');
 $nav->addSubNavInfo('jb-overflowmenu', 'customQ_nav');
 
 // Fetch ticket queues organized by root and sub-queues
-$queues = SavedQueue::queues()
-    ->filter(Q::any(array(
-        'flags__hasbit' => CustomQueue::FLAG_PUBLIC,
-        'staff_id' => $thisstaff->getId(),
-    )))
-    ->exclude(['flags__hasbit' => CustomQueue::FLAG_DISABLED])
-    ->getIterator();
+$queues = CustomQueue::getHierarchicalQueues($thisstaff);
 
 // Start with all the top-level (container) queues
-foreach ($queues->findAll(array('parent_id' => 0))
-as $q) {
-    $nav->addSubMenu(function() use ($q, $queue) {
-        $selected = false;
+foreach ($queues as $_) {
+    list($q, $children) = $_;
+    if ($q->isPrivate())
+        continue;
+    $nav->addSubMenu(function() use ($q, $queue, $children) {
         // A queue is selected if it is the one being displayed. It is
         // "child" selected if its ID is in the path of the one selected
         $child_selected = $queue