/**
  * Fetch descendants for located comments.
  *
  * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch
  * the descendant trees for all matched top-level comments.
  *
  * @since 4.4.0
  *
  * @param array $comments Array of top-level comments whose descendants should be filled in.
  * @return array
  */
 protected function fill_descendants($comments)
 {
     global $wpdb;
     $levels = array(0 => wp_list_pluck($comments, 'comment_ID'));
     /*
      * The WHERE clause for the descendant query is the same as for the top-level
      * query, minus the `parent`, `parent__in`, and `parent__not_in` sub-clauses.
      */
     $_where = $this->filtered_where_clause;
     $exclude_keys = array('parent', 'parent__in', 'parent__not_in');
     foreach ($exclude_keys as $exclude_key) {
         if (isset($this->sql_clauses['where'][$exclude_key])) {
             $clause = $this->sql_clauses['where'][$exclude_key];
             // Strip the clause as well as any adjacent ANDs.
             $pattern = '|(?:AND)?\\s*' . $clause . '\\s*(?:AND)?|';
             $_where_parts = preg_split($pattern, $_where);
             // Remove empties.
             $_where_parts = array_filter(array_map('trim', $_where_parts));
             // Reassemble with an AND.
             $_where = implode(' AND ', $_where_parts);
         }
     }
     // Fetch an entire level of the descendant tree at a time.
     $level = 0;
     do {
         $parent_ids = $levels[$level];
         if (!$parent_ids) {
             break;
         }
         $where = 'WHERE ' . $_where . ' AND comment_parent IN (' . implode(',', array_map('intval', $parent_ids)) . ')';
         $comment_ids = $wpdb->get_col("{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} ORDER BY comment_date_gmt ASC, comment_ID ASC");
         $level++;
         $levels[$level] = $comment_ids;
     } while ($comment_ids);
     // Prime comment caches for non-top-level comments.
     $descendant_ids = array();
     for ($i = 1; $i < count($levels); $i++) {
         $descendant_ids = array_merge($descendant_ids, $levels[$i]);
     }
     _prime_comment_caches($descendant_ids, $this->query_vars['update_comment_meta_cache']);
     // Assemble a flat array of all comments + descendants.
     $all_comments = $comments;
     foreach ($descendant_ids as $descendant_id) {
         $all_comments[] = get_comment($descendant_id);
     }
     // If a threaded representation was requested, build the tree.
     if ('threaded' === $this->query_vars['hierarchical']) {
         $threaded_comments = $ref = array();
         foreach ($all_comments as $k => $c) {
             $_c = get_comment($c->comment_ID);
             // If the comment isn't in the reference array, it goes in the top level of the thread.
             if (!isset($ref[$c->comment_parent])) {
                 $threaded_comments[$_c->comment_ID] = $_c;
                 $ref[$_c->comment_ID] = $threaded_comments[$_c->comment_ID];
                 // Otherwise, set it as a child of its parent.
             } else {
                 $ref[$_c->comment_parent]->add_child($_c);
                 $ref[$_c->comment_ID] = $ref[$_c->comment_parent]->get_child($_c->comment_ID);
             }
         }
         // Set the 'populated_children' flag, to ensure additional database queries aren't run.
         foreach ($ref as $_ref) {
             $_ref->populated_children(true);
         }
         $comments = $threaded_comments;
     } else {
         $comments = $all_comments;
     }
     return $comments;
 }
 /**
  * Fetch descendants for located comments.
  *
  * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch
  * the descendant trees for all matched top-level comments.
  *
  * @since 4.4.0
  *
  * @param array $comments Array of top-level comments whose descendants should be filled in.
  * @return array
  */
 protected function fill_descendants($comments)
 {
     global $wpdb;
     $levels = array(0 => wp_list_pluck($comments, 'comment_ID'));
     $where_clauses = $this->sql_clauses['where'];
     unset($where_clauses['parent'], $where_clauses['parent__in'], $where_clauses['parent__not_in']);
     // Fetch an entire level of the descendant tree at a time.
     $level = 0;
     do {
         $parent_ids = $levels[$level];
         if (!$parent_ids) {
             break;
         }
         $where = 'WHERE ' . implode(' AND ', $where_clauses) . ' AND comment_parent IN (' . implode(',', array_map('intval', $parent_ids)) . ')';
         $comment_ids = $wpdb->get_col("{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} ORDER BY comment_date_gmt ASC, comment_ID ASC");
         $level++;
         $levels[$level] = $comment_ids;
     } while ($comment_ids);
     // Prime comment caches for non-top-level comments.
     $descendant_ids = array();
     for ($i = 1; $i < count($levels); $i++) {
         $descendant_ids = array_merge($descendant_ids, $levels[$i]);
     }
     _prime_comment_caches($descendant_ids, $this->query_vars['update_comment_meta_cache']);
     // Assemble a flat array of all comments + descendants.
     $all_comments = $comments;
     foreach ($descendant_ids as $descendant_id) {
         $all_comments[] = get_comment($descendant_id);
     }
     // If a threaded representation was requested, build the tree.
     if ('threaded' === $this->query_vars['hierarchical']) {
         $threaded_comments = $ref = array();
         foreach ($all_comments as $k => $c) {
             $_c = get_comment($c->comment_ID);
             // If the comment isn't in the reference array, it goes in the top level of the thread.
             if (!isset($ref[$c->comment_parent])) {
                 $threaded_comments[$_c->comment_ID] = $_c;
                 $ref[$_c->comment_ID] = $threaded_comments[$_c->comment_ID];
                 // Otherwise, set it as a child of its parent.
             } else {
                 $ref[$_c->comment_parent]->add_child($_c);
                 $ref[$_c->comment_ID] = $ref[$_c->comment_parent]->get_child($_c->comment_ID);
             }
         }
         // Set the 'populated_children' flag, to ensure additional database queries aren't run.
         foreach ($ref as $_ref) {
             $_ref->populated_children(true);
         }
         $comments = $threaded_comments;
     } else {
         $comments = $all_comments;
     }
     return $comments;
 }
 /**
  * Fetch descendants for located comments.
  *
  * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch
  * the descendant trees for all matched top-level comments.
  *
  * @since 4.4.0
  *
  * @param array $comments Array of top-level comments whose descendants should be filled in.
  * @return array
  */
 protected function fill_descendants($comments)
 {
     global $wpdb;
     $levels = array(0 => wp_list_pluck($comments, 'comment_ID'));
     /*
      * The WHERE clause for the descendant query is the same as for the top-level
      * query, minus the `parent`, `parent__in`, and `parent__not_in` sub-clauses.
      */
     $_where = $this->filtered_where_clause;
     $exclude_keys = array('parent', 'parent__in', 'parent__not_in');
     foreach ($exclude_keys as $exclude_key) {
         if (isset($this->sql_clauses['where'][$exclude_key])) {
             $clause = $this->sql_clauses['where'][$exclude_key];
             // Strip the clause as well as any adjacent ANDs.
             $pattern = '|(?:AND)?\\s*' . $clause . '\\s*(?:AND)?|';
             $_where_parts = preg_split($pattern, $_where);
             // Remove empties.
             $_where_parts = array_filter(array_map('trim', $_where_parts));
             // Reassemble with an AND.
             $_where = implode(' AND ', $_where_parts);
         }
     }
     $key = md5(serialize(wp_array_slice_assoc($this->query_vars, array_keys($this->query_var_defaults))));
     $last_changed = wp_cache_get_last_changed('comment');
     // Fetch an entire level of the descendant tree at a time.
     $level = 0;
     do {
         // Parent-child relationships may be cached. Only query for those that are not.
         $child_ids = $uncached_parent_ids = array();
         $_parent_ids = $levels[$level];
         foreach ($_parent_ids as $parent_id) {
             $cache_key = "get_comment_child_ids:{$parent_id}:{$key}:{$last_changed}";
             $parent_child_ids = wp_cache_get($cache_key, 'comment');
             if (false !== $parent_child_ids) {
                 $child_ids = array_merge($child_ids, $parent_child_ids);
             } else {
                 $uncached_parent_ids[] = $parent_id;
             }
         }
         if ($uncached_parent_ids) {
             // Fetch this level of comments.
             $parent_query_args = $this->query_vars;
             foreach ($exclude_keys as $exclude_key) {
                 $parent_query_args[$exclude_key] = '';
             }
             $parent_query_args['parent__in'] = $uncached_parent_ids;
             $parent_query_args['no_found_rows'] = true;
             $parent_query_args['hierarchical'] = false;
             $parent_query_args['offset'] = 0;
             $parent_query_args['number'] = 0;
             $level_comments = get_comments($parent_query_args);
             // Cache parent-child relationships.
             $parent_map = array_fill_keys($uncached_parent_ids, array());
             foreach ($level_comments as $level_comment) {
                 $parent_map[$level_comment->comment_parent][] = $level_comment->comment_ID;
                 $child_ids[] = $level_comment->comment_ID;
             }
             foreach ($parent_map as $parent_id => $children) {
                 $cache_key = "get_comment_child_ids:{$parent_id}:{$key}:{$last_changed}";
                 wp_cache_set($cache_key, $children, 'comment');
             }
         }
         $level++;
         $levels[$level] = $child_ids;
     } while ($child_ids);
     // Prime comment caches for non-top-level comments.
     $descendant_ids = array();
     for ($i = 1, $c = count($levels); $i < $c; $i++) {
         $descendant_ids = array_merge($descendant_ids, $levels[$i]);
     }
     _prime_comment_caches($descendant_ids, $this->query_vars['update_comment_meta_cache']);
     // Assemble a flat array of all comments + descendants.
     $all_comments = $comments;
     foreach ($descendant_ids as $descendant_id) {
         $all_comments[] = get_comment($descendant_id);
     }
     // If a threaded representation was requested, build the tree.
     if ('threaded' === $this->query_vars['hierarchical']) {
         $threaded_comments = $ref = array();
         foreach ($all_comments as $k => $c) {
             $_c = get_comment($c->comment_ID);
             // If the comment isn't in the reference array, it goes in the top level of the thread.
             if (!isset($ref[$c->comment_parent])) {
                 $threaded_comments[$_c->comment_ID] = $_c;
                 $ref[$_c->comment_ID] = $threaded_comments[$_c->comment_ID];
                 // Otherwise, set it as a child of its parent.
             } else {
                 $ref[$_c->comment_parent]->add_child($_c);
                 $ref[$_c->comment_ID] = $ref[$_c->comment_parent]->get_child($_c->comment_ID);
             }
         }
         // Set the 'populated_children' flag, to ensure additional database queries aren't run.
         foreach ($ref as $_ref) {
             $_ref->populated_children(true);
         }
         $comments = $threaded_comments;
     } else {
         $comments = $all_comments;
     }
     return $comments;
 }
 /**
  * Get a list of comments matching the query vars.
  *
  * @since 4.2.0
  * @access public
  *
  * @global wpdb $wpdb WordPress database abstraction object.
  *
  * @return int|array The list of comments.
  */
 public function get_comments()
 {
     global $wpdb;
     $this->parse_query();
     // Parse meta query
     $this->meta_query = new WP_Meta_Query();
     $this->meta_query->parse_query_vars($this->query_vars);
     /**
      * Fires before comments are retrieved.
      *
      * @since 3.1.0
      *
      * @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
      */
     do_action_ref_array('pre_get_comments', array(&$this));
     // Reparse query vars, in case they were modified in a 'pre_get_comments' callback.
     $this->meta_query->parse_query_vars($this->query_vars);
     if (!empty($this->meta_query->queries)) {
         $this->meta_query_clauses = $this->meta_query->get_sql('comment', $wpdb->comments, 'comment_ID', $this);
     }
     // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
     $key = md5(serialize(wp_array_slice_assoc($this->query_vars, array_keys($this->query_var_defaults))));
     $last_changed = wp_cache_get('last_changed', 'comment');
     if (!$last_changed) {
         $last_changed = microtime();
         wp_cache_set('last_changed', $last_changed, 'comment');
     }
     $cache_key = "get_comment_ids:{$key}:{$last_changed}";
     $comment_ids = wp_cache_get($cache_key, 'comment');
     if (false === $comment_ids) {
         $comment_ids = $this->get_comment_ids();
         wp_cache_add($cache_key, $comment_ids, 'comment');
     }
     // If querying for a count only, there's nothing more to do.
     if ($this->query_vars['count']) {
         // $comment_ids is actually a count in this case.
         return intval($comment_ids);
     }
     $comment_ids = array_map('intval', $comment_ids);
     if ('ids' == $this->query_vars['fields']) {
         $this->comments = $comment_ids;
         return $this->comments;
     }
     _prime_comment_caches($comment_ids, $this->query_vars['update_comment_meta_cache']);
     // Fetch full comment objects from the primed cache.
     $_comments = array();
     foreach ($comment_ids as $comment_id) {
         if ($_comment = wp_cache_get($comment_id, 'comment')) {
             $_comments[] = $_comment;
         }
     }
     /**
      * Filter the comment query results.
      *
      * @since 3.1.0
      *
      * @param array            $results  An array of comments.
      * @param WP_Comment_Query &$this    Current instance of WP_Comment_Query, passed by reference.
      */
     $_comments = apply_filters_ref_array('the_comments', array($_comments, &$this));
     // Convert to WP_Comment instances
     $comments = array_map('get_comment', $_comments);
     $this->comments = $comments;
     return $this->comments;
 }