function &rs_get_term_descendants($requested_parent_id, $qualified_terms, $taxonomy)
{
    $empty_array = array();
    if (empty($qualified_terms)) {
        return $empty_array;
    }
    $term_list = array();
    $has_children = ScoperAncestry::get_terms_children($taxonomy);
    if ($requested_parent_id && !isset($has_children[$requested_parent_id])) {
        return $empty_array;
    }
    foreach ($qualified_terms as $term) {
        $use_id = false;
        if (!is_object($term)) {
            $term = get_term_by('id', $term, $taxonomy);
            if (is_wp_error($term)) {
                return $term;
            }
            $use_id = true;
        }
        if ($term->term_id == $requested_parent_id) {
            continue;
        }
        // if this qualified term has the requested parent, log it and all its descendants
        if ($term->parent == $requested_parent_id) {
            if ($use_id) {
                $descendant_list[] = $term->term_id;
            } else {
                $descendant_list[] = $term;
            }
            if (!isset($has_children[$term->term_id])) {
                continue;
            }
            if ($descendants = rs_get_term_descendants($term->term_id, $qualified_terms, $taxonomy)) {
                $descendant_list = array_merge($descendant_list, $descendants);
            }
        }
    }
    return $descendant_list;
}
 function flt_get_terms($results, $taxonomies, $args)
 {
     global $wpdb;
     $empty_array = array();
     //d_echo( 'flt_get_terms input:' );
     $single_taxonomy = false;
     if (!is_array($taxonomies)) {
         $single_taxonomy = true;
         $taxonomies = array($taxonomies);
     } elseif (count($taxonomies) < 2) {
         $single_taxonomy = true;
     }
     // === END Role Scoper MODIFICATION ===
     foreach ((array) $taxonomies as $taxonomy) {
         if (!taxonomy_exists($taxonomy)) {
             // === BEGIN Role Scoper MODIFICATION: this caused plugin activation error in some situations (though at that time, the error object was created and return on a single line, not byRef as now) ===
             //
             //$error = & new WP_Error('invalid_taxonomy', __awp('Invalid Taxonomy'));
             //return $error;
             return array();
             //
             // === END Role Scoper MODIFICATION ===
         }
     }
     // === BEGIN Role Scoper ADDITION: global var; various special case exemption checks ===
     //
     global $scoper;
     if ($tx_obj = get_taxonomy($taxonomies[0])) {
         // don't require use_taxonomies setting for link_categories or other non-post taxonomies
         if (array_intersect($tx_obj->object_type, get_post_types(array('public' => true)))) {
             $use_taxonomies = scoper_get_option('use_taxonomies');
             if (empty($use_taxonomies[$taxonomy])) {
                 return $results;
             }
         }
     }
     // no backend filter for administrators
     $parent_or = '';
     if (is_admin() || defined('XMLRPC_REQUEST')) {
         if (is_content_administrator_rs()) {
             return $results;
         } else {
             if ($tx = $scoper->taxonomies->get($taxonomies[0])) {
                 // is a Category Edit form being displayed?
                 if (!empty($tx->uri_vars)) {
                     $term_id = $scoper->data_sources->detect('id', $tx);
                 } else {
                     $term_id = $scoper->data_sources->detect('id', $tx->source);
                 }
                 if ($term_id) {
                     // don't filter current parent category out of selection UI even if current user can't manage it
                     $parent_or = " OR t.term_id = (SELECT parent FROM {$wpdb->term_taxonomy} WHERE term_id = '{$term_id}') ";
                 }
             }
         }
     }
     // need to skip cache retrieval if QTranslate is filtering get_terms with a priority of 1 or less
     static $no_cache;
     if (!isset($no_cache)) {
         $no_cache = defined('SCOPER_NO_TERMS_CACHE') || !defined('SCOPER_QTRANSLATE_COMPAT') && awp_is_plugin_active('qtranslate');
     }
     // this filter currently only supports a single taxonomy for each get_terms call
     // (although the terms_where filter does support multiple taxonomies and this function could be made to do so)
     if (!$single_taxonomy) {
         return $results;
     }
     // link category roles / restrictions are only scoped for management (TODO: abstract this)
     if ($single_taxonomy && 'link_category' == $taxonomies[0] && $scoper->is_front()) {
         return $results;
     }
     // depth is not really a get_terms arg, but remap exclude arg to exclude_tree if wp_list_terms called with depth=1
     if (!empty($args['exclude']) && empty($args['exclude_tree']) && !empty($args['depth']) && 1 == $args['depth']) {
         $args['exclude_tree'] = $args['exclude'];
     }
     // don't offer to set a category as its own parent
     if ('edit-tags.php' == $GLOBALS['pagenow']) {
         if ($tx_obj->hierarchical) {
             if ($editing_cat_id = $scoper->data_sources->get_from_uri('id', 'term')) {
                 if (!empty($args['exclude'])) {
                     $args['exclude'] .= ',';
                 }
                 $args['exclude'] .= $editing_cat_id;
             }
         }
     }
     // we'll need this array in most cases, to support a disjointed tree with some parents missing (note alternate function call - was _get_term_hierarchy)
     $children = ScoperAncestry::get_terms_children($taxonomies[0]);
     //
     // === END Role Scoper ADDITION ===
     // =================================
     $in_taxonomies = "'" . implode("', '", $taxonomies) . "'";
     $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => '', 'exclude_tree' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'skip_teaser' => false, 'depth' => 0, 'remap_parents' => -1, 'enforce_actual_depth' => -1, 'remap_thru_excluded_parent' => -1, 'post_type' => '');
     // Role Scoper arguments added above
     $args = wp_parse_args($args, $defaults);
     $args['number'] = (int) $args['number'];
     $args['offset'] = absint($args['offset']);
     $args['child_of'] = (int) $args['child_of'];
     // Role Scoper modification: null value will confuse children array check
     if (!$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' !== $args['parent']) {
         $args['child_of'] = 0;
         $args['hierarchical'] = false;
         $args['pad_counts'] = false;
     }
     if ('all' == $args['get']) {
         $args['child_of'] = 0;
         $args['hide_empty'] = 0;
         $args['hierarchical'] = false;
         $args['pad_counts'] = false;
     }
     extract($args, EXTR_SKIP);
     // === BEGIN Role Scoper MODIFICATION: use the $children array we already have ===
     //
     if ('nav-menus.php' == $GLOBALS['pagenow']) {
         if ('nav_menu' != $taxonomies[0]) {
             if (!scoper_get_option('admin_nav_menu_filter_items')) {
                 return $results;
             } else {
                 $hide_empty = 1;
             }
         }
     }
     if ($child_of && !isset($children[$child_of])) {
         return array();
     }
     if ($parent && !isset($children[$parent])) {
         return array();
     }
     if ($post_type && is_string($post_type)) {
         $post_type = explode(',', $post_type);
     }
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     $is_term_admin = in_array($GLOBALS['pagenow'], array('edit-tags.php', 'edit-link-categories.php'));
     $filter_key = has_filter('list_terms_exclusions') ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
     $key = md5(serialize(compact(array_keys($defaults))) . serialize($taxonomies) . $filter_key);
     // === BEGIN Role Scoper MODIFICATION: cache key specific to access type and user/groups ===
     // support Quick Post Widget plugin
     if (isset($name) && 'quick_post_cat' == $name) {
         $required_operation = 'edit';
         $post_type = 'post';
         $remap_parents = true;
     } elseif (isset($name) && 'quick_post_new_cat_parent' == $name) {
         $is_term_admin = true;
         $required_operation = '';
         $remap_parents = true;
     } else {
         $required_operation = '';
     }
     $object_src_name = $scoper->taxonomies->member_property($taxonomies[0], 'object_source', 'name');
     $ckey = md5($key . serialize($scoper->get_terms_reqd_caps($taxonomies[0], $required_operation, $is_term_admin)));
     global $current_rs_user;
     $cache_flag = 'rs_get_terms';
     $cache = $current_rs_user->cache_get($cache_flag);
     if (false !== $cache) {
         if (!is_array($cache)) {
             $cache = array();
         }
         if (!$no_cache && isset($cache[$ckey])) {
             // RS Modification: alternate filter name (get_terms filter is already applied by WP)
             remove_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
             $terms = apply_filters('get_terms', $cache[$ckey], $taxonomies, $args);
             $terms = apply_filters('get_terms_rs', $terms, $taxonomies, $args);
             add_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
             return $terms;
         }
     }
     // buffer term names in case they were filtered previously
     if ('all' == $fields) {
         $term_names = scoper_get_property_array($results, 'term_id', 'name');
     }
     //
     // === END Role Scoper MODIFICATION ===
     // =====================================
     $_orderby = strtolower($orderby);
     if ('count' == $_orderby) {
         $orderby = 'tt.count';
     } else {
         if ('name' == $_orderby) {
             $orderby = 't.name';
         } else {
             if ('slug' == $_orderby) {
                 $orderby = 't.slug';
             } else {
                 if ('term_group' == $_orderby) {
                     $orderby = 't.term_group';
                 } else {
                     if ('none' == $_orderby) {
                         $orderby = '';
                         $order = '';
                     } else {
                         if (empty($_orderby) || 'id' == $_orderby) {
                             $orderby = 't.term_id';
                         } elseif ('order' == $_orderby) {
                             $orderby = 't.term_order';
                         } else {
                             $orderby = 't.name';
                         }
                     }
                 }
             }
         }
     }
     $orderby = apply_filters('get_terms_orderby', $orderby, $args);
     if (!empty($orderby)) {
         $orderby = "ORDER BY {$orderby}";
     }
     $where = '';
     // === Role Scoper MODIFICATION: if an include argument is provided, strip out non-matching terms after filtering is done. ===
     /*
     $inclusions = '';
     if ( !empty($include) ) {
     	$exclude = '';
     	$exclude_tree = '';
     	$interms = wp_parse_id_list($include);
     	if ( count($interms) ) {
     		foreach ( $interms as $interm ) {
     			if (empty($inclusions))
     				$inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
     			else
     				$inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
     		}
     	}
     }
     	
     if ( !empty($inclusions) )
     	$inclusions .= ')';
     $where .= $inclusions;
     */
     // === END Role Scoper MODIFICATION ===
     $exclusions = '';
     if (!empty($exclude_tree)) {
         // === BEGIN Role Scoper MODIFICATION: temporarily unhook this filter for unfiltered get_terms calls ===
         remove_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
         // === END Role Scoper MODIFICATION ===
         $excluded_trunks = wp_parse_id_list($exclude_tree);
         foreach ((array) $excluded_trunks as $extrunk) {
             $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids'));
             $excluded_children[] = $extrunk;
             foreach ($excluded_children as $exterm) {
                 if (empty($exclusions)) {
                     $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
                 } else {
                     $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
                 }
             }
         }
         // === BEGIN Role Scoper MODIFICATION: re-hook this filter
         add_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
         // === END Role Scoper MODIFICATION ===
     }
     if (!empty($exclude)) {
         $exterms = wp_parse_id_list($exclude);
         foreach ($exterms as $exterm) {
             if (empty($exclusions)) {
                 $exclusions = ' AND ( t.term_id <> "' . intval($exterm) . '" ';
             } else {
                 $exclusions .= ' AND t.term_id <> "' . intval($exterm) . '" ';
             }
         }
     }
     if (!empty($exclusions)) {
         $exclusions .= ')';
     }
     // WPML attempts to pull taxonomy out of debug_backtrace() unless set in $_GET or $_POST; previous filter execution throws it off
     if (defined('ICL_SITEPRESS_VERSION') && !isset($_GET['taxonomy'])) {
         $_GET['taxonomy'] = current($taxonomies);
     }
     $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args);
     $where .= $exclusions;
     if (!empty($slug)) {
         $slug = sanitize_title($slug);
         $where .= " AND t.slug = '{$slug}'";
     }
     if (!empty($name__like)) {
         $where .= " AND t.name LIKE '{$name__like}%'";
     }
     if ('' !== $parent) {
         $parent = (int) $parent;
         // === BEGIN Role Scoper MODIFICATION: otherwise termroles only work if parent terms also have role
         if ($parent || 'ids' != $fields) {
             $where .= " AND tt.parent = '{$parent}'";
         }
         // === END Role Scoper MODIFICATION ===
     }
     // === BEGIN Role Scoper MODIFICATION: instead, manually remove truly empty cats at the bottom of this function, so we don't exclude cats with private but readable posts
     //if ( $hide_empty && !$hierarchical )
     //	$where .= ' AND tt.count > 0';
     // === END Role Scoper MODIFICATION ===
     // don't limit the query results when we have to descend the family tree
     if (!empty($number) && !$hierarchical && empty($child_of) && '' == $parent) {
         if ($offset) {
             $limit = 'LIMIT ' . $offset . ',' . $number;
         } else {
             $limit = 'LIMIT ' . $number;
         }
     } else {
         $limit = '';
     }
     if (!empty($search)) {
         $search = like_escape($search);
         $where .= " AND (t.name LIKE '%{$search}%')";
     }
     $selects = array();
     switch ($fields) {
         case 'all':
             $selects = array('t.*', 'tt.*');
             break;
         case 'ids':
         case 'id=>parent':
             $selects = array('t.term_id', 'tt.term_taxonomy_id', 'tt.parent', 'tt.count');
             break;
         case 'names':
             $selects = array('t.term_id', 'tt.term_taxonomy_id', 'tt.parent', 'tt.count', 't.name');
             break;
         case 'count':
             $orderby = '';
             $order = '';
             $selects = array('COUNT(*)');
     }
     $select_this = implode(', ', apply_filters('get_terms_fields', $selects, $args));
     // === BEGIN Role Scoper MODIFICATION: run the query through scoping filter
     //
     $query_base = "SELECT DISTINCT {$select_this} FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE 1=1 AND tt.taxonomy IN ({$in_taxonomies}) {$where} {$parent_or} {$orderby} {$order} {$limit}";
     // only force application of scoped query filter if we're NOT doing a teaser
     if ('all' == $fields) {
         $do_teaser = $scoper->is_front() && empty($skip_teaser) && scoper_get_otype_option('do_teaser', 'post');
     } else {
         $do_teaser = false;
     }
     $query = apply_filters('terms_request_rs', $query_base, $taxonomies[0], array('skip_teaser' => !$do_teaser, 'is_term_admin' => $is_term_admin, 'required_operation' => $required_operation, 'post_type' => $post_type));
     // if no filering was applied because the teaser is enabled, prevent a redundant query
     if (!empty($exclude_tree) || $query_base != $query || $parent || 'all' != $fields) {
         $terms = scoper_get_results($query);
     } else {
         $terms = $results;
     }
     if ('count' == $fields) {
         $term_count = $wpdb->get_var($query);
         return $term_count;
     }
     if ('all' == $fields && empty($include)) {
         update_term_cache($terms);
     }
     // RS: don't cache an empty array, just in case something went wrong
     if (empty($terms)) {
         return array();
     }
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     // === BEGIN Role Scoper ADDITION: Support a disjointed terms tree with some parents hidden
     //
     if ('all' == $fields) {
         $ancestors = ScoperAncestry::get_term_ancestors($taxonomy);
         // array of all ancestor IDs for keyed term_id, with direct parent first
         if ($parent > 0 || !$hierarchical) {
             // in Category Edit form, need to list all editable cats even if parent is not editable
             $remap_parents = false;
             $enforce_actual_depth = true;
             $remap_thru_excluded_parent = false;
         } else {
             // if these settings were passed into this get_terms call, use them
             if (is_admin()) {
                 $remap_parents = true;
             } else {
                 if (-1 === $remap_parents) {
                     $remap_parents = scoper_get_option('remap_term_parents');
                 }
                 if ($remap_parents) {
                     if (-1 === $enforce_actual_depth) {
                         $enforce_actual_depth = scoper_get_option('enforce_actual_term_depth');
                     }
                     if (-1 === $remap_thru_excluded_parent) {
                         $remap_thru_excluded_parent = scoper_get_option('remap_thru_excluded_term_parent');
                     }
                 }
             }
         }
         $remap_args = compact('child_of', 'parent', 'depth', 'orderby', 'remap_parents', 'enforce_actual_depth', 'remap_thru_excluded_parent');
         // one or more of these args may have been modified after extraction
         ScoperHardway::remap_tree($terms, $ancestors, 'term_id', 'parent', $remap_args);
     }
     //
     // === END Role Scoper ADDITION ===
     // ================================
     // === BEGIN Role Scoper MODIFICATION: call alternate functions
     // rs_tally_term_counts() replaces _pad_term_counts()
     // rs_get_term_descendants replaces _get_term_children()
     //
     if (($child_of || $hierarchical) && !empty($children)) {
         $terms = rs_get_term_descendants($child_of, $terms, $taxonomies[0]);
     }
     if (!$terms) {
         return array();
     }
     // Replace DB-stored term counts with actual number of posts this user can read.
     // In addition, without the rs_tally_term_counts call, WP will hide categories that have no public posts (even if this user can read some of the pvt posts).
     // Post counts will be incremented to include child categories only if $pad_counts is true
     if (!defined('XMLRPC_REQUEST') && in_array($fields, array('all', 'ids', 'names')) && !$is_term_admin) {
         if (!is_admin() || !in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php'))) {
             //-- RoleScoper Modification - alternate function call (was _pad_term_counts) --//
             rs_tally_term_counts($terms, $taxonomies[0], array('pad_counts' => $pad_counts, 'skip_teaser' => !$do_teaser, 'post_type' => $post_type));
         }
     }
     // Make sure we show empty categories that have children.
     if ($hierarchical && $hide_empty) {
         foreach ($terms as $k => $term) {
             if (!$term->count) {
                 //-- RoleScoper Modification - call alternate function (was _get_term_children) --//
                 if ($children = rs_get_term_descendants($term->term_id, $terms, $taxonomies[0])) {
                     foreach ($children as $child) {
                         if ($child->count) {
                             continue 2;
                         }
                     }
                 }
                 // It really is empty
                 unset($terms[$k]);
             }
         }
     }
     reset($terms);
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     // === BEGIN Role Scoper ADDITION: hide empty cats based on actual query result instead of 'count > 0' clause, so we don't exclude cats with private but readable posts
     if ($terms && empty($hierarchical) && !empty($hide_empty)) {
         foreach ($terms as $key => $term) {
             if (!$term->count) {
                 unset($terms[$key]);
             }
         }
     }
     //
     // === END Role Scoper ADDITION ===
     // ================================
     if (!empty($include)) {
         $interms = wp_parse_id_list($include);
         foreach ($terms as $key => $term) {
             if (!in_array($term->term_id, $interms)) {
                 unset($terms[$key]);
             }
         }
     }
     $_terms = array();
     if ('id=>parent' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[$term->term_id] = $term->parent;
         }
         $terms = $_terms;
     } elseif ('ids' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[] = $term->term_id;
         }
         $terms = $_terms;
     } elseif ('names' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[] = $term->name;
         }
         $terms = $_terms;
     }
     if (0 < $number && intval(@count($terms)) > $number) {
         $terms = array_slice($terms, $offset, $number);
     }
     // === BEGIN Role Scoper MODIFICATION: cache key is specific to user/group
     //
     if (!$no_cache) {
         $cache[$ckey] = $terms;
         $current_rs_user->cache_set($cache, $cache_flag);
     }
     // RS Modification: alternate filter name (get_terms filter is already applied by WP)
     remove_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
     $terms = apply_filters('get_terms', $terms, $taxonomies, $args);
     $terms = apply_filters('get_terms_rs', $terms, $taxonomies, $args);
     add_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
     // restore buffered term names in case they were filtered previously
     if ('all' == $fields) {
         scoper_restore_property_array($terms, $term_names, 'term_id', 'name');
     }
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     //dump($terms);
     return $terms;
 }
 function flt_get_terms($terms, $taxonomies, $args)
 {
     if (empty($terms)) {
         return array();
     }
     if ($skip = $this->skip_filtering($taxonomies, $args)) {
         if ('return_empty' === $skip) {
             return array();
         } else {
             return $terms;
         }
     }
     $taxonomy = reset($taxonomies);
     extract($args, EXTR_SKIP);
     $criteria = $this->get_filter_criteria($args);
     extract($criteria);
     // sets $is_term_admin, $filter_key, $required_operation' (may also force $post_type and $remap_parents)
     //d_echo( 'flt_get_terms input:' );
     //dump($terms);
     if (!$this->no_cache) {
         // NOTE: this caching eliminates both the results post-processing below and query clause filtering in flt_terms_clauses()
         $ckey = $this->get_cache_key($taxonomy, $args, $criteria);
         $cache_flag = 'rs_get_terms';
         $cache = $GLOBALS['current_rs_user']->cache_get($cache_flag);
         if (false !== $cache) {
             if (!is_array($cache)) {
                 $cache = array();
             }
             if (isset($cache[$ckey])) {
                 return $cache[$ckey];
             }
         }
     }
     // if some args were forced to prevent core post-processing, restore actual values now
     if (!empty($args['actual_args'])) {
         extract($args['actual_args']);
     }
     // we'll need this array in most cases, to support a disjointed tree with some parents missing (note alternate function call - was _get_term_hierarchy)
     $children = ScoperAncestry::get_terms_children($taxonomy);
     if ('all' == $fields) {
         // buffer term names in case they were filtered previously
         $term_names = scoper_get_property_array($terms, 'term_id', 'name');
         $ancestors = ScoperAncestry::get_term_ancestors($taxonomy);
         // array of all ancestor IDs for keyed term_id, with direct parent first
         if ($parent > 0 || !$hierarchical) {
             // in Term Edit form, need to list all editable terms even if parent is not editable
             $remap_parents = false;
             $enforce_actual_depth = true;
             $remap_thru_excluded_parent = false;
         } else {
             // if these settings were passed into this get_terms call, use them
             if (is_admin()) {
                 $remap_parents = true;
             } else {
                 if (-1 === $remap_parents) {
                     $remap_parents = scoper_get_option('remap_term_parents');
                 }
                 if ($remap_parents) {
                     if (-1 === $enforce_actual_depth) {
                         $enforce_actual_depth = scoper_get_option('enforce_actual_term_depth');
                     }
                     if (-1 === $remap_thru_excluded_parent) {
                         $remap_thru_excluded_parent = scoper_get_option('remap_thru_excluded_term_parent');
                     }
                 }
             }
         }
         $remap_args = compact('child_of', 'parent', 'depth', 'orderby', 'remap_parents', 'enforce_actual_depth', 'remap_thru_excluded_parent');
         ScoperHardway::remap_tree($terms, $ancestors, 'term_id', 'parent', $remap_args);
     }
     if (($child_of || $hierarchical) && !empty($children)) {
         $terms = rs_get_term_descendants($child_of, $terms, $taxonomy);
     }
     // rs_get_term_descendants is RS equivalent to WP _get_term_children()
     if (!$terms) {
         return array();
     }
     // Replace DB-stored term counts with actual number of posts this user can read.
     // In addition, without the rs_tally_term_counts() call, WP will hide terms that have no public posts (even if this user can read some of the pvt posts).
     // Post counts will be incremented to include child terms only if $pad_counts is true
     if (!defined('XMLRPC_REQUEST') && in_array($fields, array('all', 'ids', 'names')) && !$is_term_admin) {
         if (!is_admin() || !in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php'))) {
             // rs_tally_term_counts() is RS equivalent to WP _pad_term_counts()
             rs_tally_term_counts($terms, $taxonomy, array('pad_counts' => $pad_counts, 'skip_teaser' => !$this->doing_teaser($args), 'post_type' => $post_type));
         }
     }
     // Empty terms will be identified via count property set by rs_tally_term_counts() instead of 'count > 0' clause, to reflect logged user's actual post access (including readable private posts)
     if ($hide_empty) {
         if ($hierarchical) {
             // Remove empty categories, but only if their descendants are all empty too.
             foreach ($terms as $k => $term) {
                 if (!$term->count) {
                     if ($descendants = rs_get_term_descendants($term->term_id, $terms, $taxonomies[0])) {
                         foreach ($descendants as $child) {
                             if ($child->count) {
                                 continue 2;
                             }
                         }
                     }
                     // It really is empty
                     unset($terms[$k]);
                 }
             }
         } else {
             foreach ($terms as $key => $term) {
                 if (!$term->count) {
                     unset($terms[$key]);
                 }
             }
         }
     }
     reset($terms);
     // === Standard WP post-processing for include, fields, number args ===
     //
     if (!empty($include)) {
         $interms = wp_parse_id_list($include);
         foreach ($terms as $key => $term) {
             if (!in_array($term->term_id, $interms)) {
                 unset($terms[$key]);
             }
         }
     }
     $_terms = array();
     if ('id=>parent' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[$term->term_id] = $term->parent;
         }
         $terms = $_terms;
     } elseif ('ids' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[] = $term->term_id;
         }
         $terms = $_terms;
     } elseif ('names' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[] = $term->name;
         }
         $terms = $_terms;
     }
     if (0 < $number && intval(@count($terms)) > $number) {
         $terms = array_slice($terms, $offset, $number);
     }
     // === end standard WP block ===
     if (!$this->no_cache) {
         $cache[$ckey] = $terms;
         $GLOBALS['current_rs_user']->cache_set($cache, $cache_flag);
     }
     // restore buffered term names in case they were filtered previously
     if ('all' == $fields) {
         scoper_restore_property_array($terms, $term_names, 'term_id', 'name');
     }
     return $terms;
 }