157 * comment objects (false). Default false. |
158 * comment objects (false). Default false. |
158 * @type array $date_query Date query clauses to limit comments by. See WP_Date_Query. |
159 * @type array $date_query Date query clauses to limit comments by. See WP_Date_Query. |
159 * Default null. |
160 * Default null. |
160 * @type string $fields Comment fields to return. Accepts 'ids' for comment IDs |
161 * @type string $fields Comment fields to return. Accepts 'ids' for comment IDs |
161 * only or empty for all fields. Default empty. |
162 * only or empty for all fields. Default empty. |
162 * @type int $ID Currently unused. |
|
163 * @type array $include_unapproved Array of IDs or email addresses of users whose unapproved |
163 * @type array $include_unapproved Array of IDs or email addresses of users whose unapproved |
164 * comments will be returned by the query regardless of |
164 * comments will be returned by the query regardless of |
165 * `$status`. Default empty. |
165 * `$status`. Default empty. |
166 * @type int $karma Karma score to retrieve matching comments for. |
166 * @type int $karma Karma score to retrieve matching comments for. |
167 * Default empty. |
167 * Default empty. |
168 * @type string|string[] $meta_key Meta key or keys to filter by. |
168 * @type string|string[] $meta_key Meta key or keys to filter by. |
169 * @type string|string[] $meta_value Meta value or values to filter by. |
169 * @type string|string[] $meta_value Meta value or values to filter by. |
170 * @type string $meta_compare MySQL operator used for comparing the meta value. |
170 * @type string $meta_compare MySQL operator used for comparing the meta value. |
171 * See WP_Meta_Query::__construct for accepted values and default value. |
171 * See WP_Meta_Query::__construct() for accepted values and default value. |
172 * @type string $meta_compare_key MySQL operator used for comparing the meta key. |
172 * @type string $meta_compare_key MySQL operator used for comparing the meta key. |
173 * See WP_Meta_Query::__construct for accepted values and default value. |
173 * See WP_Meta_Query::__construct() for accepted values and default value. |
174 * @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons. |
174 * @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons. |
175 * See WP_Meta_Query::__construct for accepted values and default value. |
175 * See WP_Meta_Query::__construct() for accepted values and default value. |
176 * @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons. |
176 * @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons. |
177 * See WP_Meta_Query::__construct for accepted values and default value. |
177 * See WP_Meta_Query::__construct() for accepted values and default value. |
178 * @type array $meta_query An associative array of WP_Meta_Query arguments. |
178 * @type array $meta_query An associative array of WP_Meta_Query arguments. |
179 * See WP_Meta_Query::__construct for accepted values. |
179 * See WP_Meta_Query::__construct() for accepted values. |
180 * @type int $number Maximum number of comments to retrieve. |
180 * @type int $number Maximum number of comments to retrieve. |
181 * Default empty (no limit). |
181 * Default empty (no limit). |
182 * @type int $paged When used with `$number`, defines the page of results to return. |
182 * @type int $paged When used with `$number`, defines the page of results to return. |
183 * When used with `$offset`, `$offset` takes precedence. Default 1. |
183 * When used with `$offset`, `$offset` takes precedence. Default 1. |
184 * @type int $offset Number of comments to offset the query. Used to build |
184 * @type int $offset Number of comments to offset the query. Used to build |
221 * children for. Default empty. |
221 * children for. Default empty. |
222 * @type int[] $post_author__in Array of author IDs to retrieve comments for. |
222 * @type int[] $post_author__in Array of author IDs to retrieve comments for. |
223 * Default empty. |
223 * Default empty. |
224 * @type int[] $post_author__not_in Array of author IDs *not* to retrieve comments for. |
224 * @type int[] $post_author__not_in Array of author IDs *not* to retrieve comments for. |
225 * Default empty. |
225 * Default empty. |
226 * @type int $post_ID Currently unused. |
|
227 * @type int $post_id Limit results to those affiliated with a given post ID. |
226 * @type int $post_id Limit results to those affiliated with a given post ID. |
228 * Default 0. |
227 * Default 0. |
229 * @type int[] $post__in Array of post IDs to include affiliated comments for. |
228 * @type int[] $post__in Array of post IDs to include affiliated comments for. |
230 * Default empty. |
229 * Default empty. |
231 * @type int[] $post__not_in Array of post IDs to exclude affiliated comments for. |
230 * @type int[] $post__not_in Array of post IDs to exclude affiliated comments for. |
451 |
450 |
452 $key = md5( serialize( $_args ) ); |
451 $key = md5( serialize( $_args ) ); |
453 $last_changed = wp_cache_get_last_changed( 'comment' ); |
452 $last_changed = wp_cache_get_last_changed( 'comment' ); |
454 |
453 |
455 $cache_key = "get_comments:$key:$last_changed"; |
454 $cache_key = "get_comments:$key:$last_changed"; |
456 $cache_value = wp_cache_get( $cache_key, 'comment' ); |
455 $cache_value = wp_cache_get( $cache_key, 'comment-queries' ); |
457 if ( false === $cache_value ) { |
456 if ( false === $cache_value ) { |
458 $comment_ids = $this->get_comment_ids(); |
457 $comment_ids = $this->get_comment_ids(); |
459 if ( $comment_ids ) { |
458 if ( $comment_ids ) { |
460 $this->set_found_comments(); |
459 $this->set_found_comments(); |
461 } |
460 } |
462 |
461 |
463 $cache_value = array( |
462 $cache_value = array( |
464 'comment_ids' => $comment_ids, |
463 'comment_ids' => $comment_ids, |
465 'found_comments' => $this->found_comments, |
464 'found_comments' => $this->found_comments, |
466 ); |
465 ); |
467 wp_cache_add( $cache_key, $cache_value, 'comment' ); |
466 wp_cache_add( $cache_key, $cache_value, 'comment-queries' ); |
468 } else { |
467 } else { |
469 $comment_ids = $cache_value['comment_ids']; |
468 $comment_ids = $cache_value['comment_ids']; |
470 $this->found_comments = $cache_value['found_comments']; |
469 $this->found_comments = $cache_value['found_comments']; |
471 } |
470 } |
472 |
471 |
473 if ( $this->found_comments && $this->query_vars['number'] ) { |
472 if ( $this->found_comments && $this->query_vars['number'] ) { |
474 $this->max_num_pages = ceil( $this->found_comments / $this->query_vars['number'] ); |
473 $this->max_num_pages = (int) ceil( $this->found_comments / $this->query_vars['number'] ); |
475 } |
474 } |
476 |
475 |
477 // If querying for a count only, there's nothing more to do. |
476 // If querying for a count only, there's nothing more to do. |
478 if ( $this->query_vars['count'] ) { |
477 if ( $this->query_vars['count'] ) { |
479 // $comment_ids is actually a count in this case. |
478 // $comment_ids is actually a count in this case. |
480 return (int) $comment_ids; |
479 return (int) $comment_ids; |
481 } |
480 } |
482 |
481 |
483 $comment_ids = array_map( 'intval', $comment_ids ); |
482 $comment_ids = array_map( 'intval', $comment_ids ); |
484 |
483 |
|
484 if ( $this->query_vars['update_comment_meta_cache'] ) { |
|
485 wp_lazyload_comment_meta( $comment_ids ); |
|
486 } |
|
487 |
485 if ( 'ids' === $this->query_vars['fields'] ) { |
488 if ( 'ids' === $this->query_vars['fields'] ) { |
486 $this->comments = $comment_ids; |
489 $this->comments = $comment_ids; |
487 return $this->comments; |
490 return $this->comments; |
488 } |
491 } |
489 |
492 |
490 _prime_comment_caches( $comment_ids, $this->query_vars['update_comment_meta_cache'] ); |
493 _prime_comment_caches( $comment_ids, false ); |
491 |
494 |
492 // Fetch full comment objects from the primed cache. |
495 // Fetch full comment objects from the primed cache. |
493 $_comments = array(); |
496 $_comments = array(); |
494 foreach ( $comment_ids as $comment_id ) { |
497 foreach ( $comment_ids as $comment_id ) { |
495 $_comment = get_comment( $comment_id ); |
498 $_comment = get_comment( $comment_id ); |
583 |
586 |
584 // User IDs or emails whose unapproved comments are included, regardless of $status. |
587 // User IDs or emails whose unapproved comments are included, regardless of $status. |
585 if ( ! empty( $this->query_vars['include_unapproved'] ) ) { |
588 if ( ! empty( $this->query_vars['include_unapproved'] ) ) { |
586 $include_unapproved = wp_parse_list( $this->query_vars['include_unapproved'] ); |
589 $include_unapproved = wp_parse_list( $this->query_vars['include_unapproved'] ); |
587 |
590 |
588 $unapproved_ids = array(); |
|
589 $unapproved_emails = array(); |
|
590 foreach ( $include_unapproved as $unapproved_identifier ) { |
591 foreach ( $include_unapproved as $unapproved_identifier ) { |
591 // Numeric values are assumed to be user IDs. |
592 // Numeric values are assumed to be user IDs. |
592 if ( is_numeric( $unapproved_identifier ) ) { |
593 if ( is_numeric( $unapproved_identifier ) ) { |
593 $approved_clauses[] = $wpdb->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier ); |
594 $approved_clauses[] = $wpdb->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier ); |
594 } else { |
595 } else { |
674 } |
675 } |
675 |
676 |
676 // If no date-related order is available, use the date from the first available clause. |
677 // If no date-related order is available, use the date from the first available clause. |
677 if ( ! $comment_id_order ) { |
678 if ( ! $comment_id_order ) { |
678 foreach ( $orderby_array as $orderby_clause ) { |
679 foreach ( $orderby_array as $orderby_clause ) { |
679 if ( false !== strpos( 'ASC', $orderby_clause ) ) { |
680 if ( str_contains( 'ASC', $orderby_clause ) ) { |
680 $comment_id_order = 'ASC'; |
681 $comment_id_order = 'ASC'; |
681 } else { |
682 } else { |
682 $comment_id_order = 'DESC'; |
683 $comment_id_order = 'DESC'; |
683 } |
684 } |
684 |
685 |
909 $groupby = "{$wpdb->comments}.comment_ID"; |
910 $groupby = "{$wpdb->comments}.comment_ID"; |
910 } |
911 } |
911 } |
912 } |
912 |
913 |
913 if ( ! empty( $this->query_vars['date_query'] ) && is_array( $this->query_vars['date_query'] ) ) { |
914 if ( ! empty( $this->query_vars['date_query'] ) && is_array( $this->query_vars['date_query'] ) ) { |
914 $this->date_query = new WP_Date_Query( $this->query_vars['date_query'], 'comment_date' ); |
915 $this->date_query = new WP_Date_Query( $this->query_vars['date_query'], 'comment_date' ); |
|
916 |
|
917 // Strip leading 'AND'. |
915 $this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() ); |
918 $this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() ); |
916 } |
919 } |
917 |
920 |
918 $where = implode( ' AND ', $this->sql_clauses['where'] ); |
921 $where = implode( ' AND ', $this->sql_clauses['where'] ); |
919 |
922 |
920 $clauses = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' ); |
923 $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' ); |
921 |
924 |
922 /** |
925 /** |
923 * Filters the comment query clauses. |
926 * Filters the comment query clauses. |
924 * |
927 * |
925 * @since 3.1.0 |
928 * @since 3.1.0 |
926 * |
929 * |
927 * @param string[] $clauses An associative array of comment query clauses. |
930 * @param string[] $clauses { |
|
931 * Associative array of the clauses for the query. |
|
932 * |
|
933 * @type string $fields The SELECT clause of the query. |
|
934 * @type string $join The JOIN clause of the query. |
|
935 * @type string $where The WHERE clause of the query. |
|
936 * @type string $orderby The ORDER BY clause of the query. |
|
937 * @type string $limits The LIMIT clause of the query. |
|
938 * @type string $groupby The GROUP BY clause of the query. |
|
939 * } |
928 * @param WP_Comment_Query $query Current instance of WP_Comment_Query (passed by reference). |
940 * @param WP_Comment_Query $query Current instance of WP_Comment_Query (passed by reference). |
929 */ |
941 */ |
930 $clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $clauses ), &$this ) ); |
942 $clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) ); |
931 |
943 |
932 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : ''; |
944 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : ''; |
933 $join = isset( $clauses['join'] ) ? $clauses['join'] : ''; |
945 $join = isset( $clauses['join'] ) ? $clauses['join'] : ''; |
934 $where = isset( $clauses['where'] ) ? $clauses['where'] : ''; |
946 $where = isset( $clauses['where'] ) ? $clauses['where'] : ''; |
935 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : ''; |
947 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : ''; |
959 $this->sql_clauses['from'] = "FROM $wpdb->comments $join"; |
971 $this->sql_clauses['from'] = "FROM $wpdb->comments $join"; |
960 $this->sql_clauses['groupby'] = $groupby; |
972 $this->sql_clauses['groupby'] = $groupby; |
961 $this->sql_clauses['orderby'] = $orderby; |
973 $this->sql_clauses['orderby'] = $orderby; |
962 $this->sql_clauses['limits'] = $limits; |
974 $this->sql_clauses['limits'] = $limits; |
963 |
975 |
964 $this->request = " |
976 // Beginning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticket/56841. |
965 {$this->sql_clauses['select']} |
977 $this->request = |
966 {$this->sql_clauses['from']} |
978 "{$this->sql_clauses['select']} |
967 {$where} |
979 {$this->sql_clauses['from']} |
968 {$this->sql_clauses['groupby']} |
980 {$where} |
969 {$this->sql_clauses['orderby']} |
981 {$this->sql_clauses['groupby']} |
970 {$this->sql_clauses['limits']} |
982 {$this->sql_clauses['orderby']} |
971 "; |
983 {$this->sql_clauses['limits']}"; |
972 |
984 |
973 if ( $this->query_vars['count'] ) { |
985 if ( $this->query_vars['count'] ) { |
974 return (int) $wpdb->get_var( $this->request ); |
986 return (int) $wpdb->get_var( $this->request ); |
975 } else { |
987 } else { |
976 $comment_ids = $wpdb->get_col( $this->request ); |
988 $comment_ids = $wpdb->get_col( $this->request ); |
1010 * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch |
1022 * Instead of calling `get_children()` separately on each child comment, we do a single set of queries to fetch |
1011 * the descendant trees for all matched top-level comments. |
1023 * the descendant trees for all matched top-level comments. |
1012 * |
1024 * |
1013 * @since 4.4.0 |
1025 * @since 4.4.0 |
1014 * |
1026 * |
1015 * @global wpdb $wpdb WordPress database abstraction object. |
|
1016 * |
|
1017 * @param WP_Comment[] $comments Array of top-level comments whose descendants should be filled in. |
1027 * @param WP_Comment[] $comments Array of top-level comments whose descendants should be filled in. |
1018 * @return array |
1028 * @return array |
1019 */ |
1029 */ |
1020 protected function fill_descendants( $comments ) { |
1030 protected function fill_descendants( $comments ) { |
1021 global $wpdb; |
|
1022 |
|
1023 $levels = array( |
1031 $levels = array( |
1024 0 => wp_list_pluck( $comments, 'comment_ID' ), |
1032 0 => wp_list_pluck( $comments, 'comment_ID' ), |
1025 ); |
1033 ); |
1026 |
1034 |
1027 $key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) ); |
1035 $key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) ); |
1033 do { |
1041 do { |
1034 // Parent-child relationships may be cached. Only query for those that are not. |
1042 // Parent-child relationships may be cached. Only query for those that are not. |
1035 $child_ids = array(); |
1043 $child_ids = array(); |
1036 $uncached_parent_ids = array(); |
1044 $uncached_parent_ids = array(); |
1037 $_parent_ids = $levels[ $level ]; |
1045 $_parent_ids = $levels[ $level ]; |
1038 foreach ( $_parent_ids as $parent_id ) { |
1046 if ( $_parent_ids ) { |
1039 $cache_key = "get_comment_child_ids:$parent_id:$key:$last_changed"; |
1047 $cache_keys = array(); |
1040 $parent_child_ids = wp_cache_get( $cache_key, 'comment' ); |
1048 foreach ( $_parent_ids as $parent_id ) { |
1041 if ( false !== $parent_child_ids ) { |
1049 $cache_keys[ $parent_id ] = "get_comment_child_ids:$parent_id:$key:$last_changed"; |
1042 $child_ids = array_merge( $child_ids, $parent_child_ids ); |
1050 } |
1043 } else { |
1051 $cache_data = wp_cache_get_multiple( array_values( $cache_keys ), 'comment-queries' ); |
1044 $uncached_parent_ids[] = $parent_id; |
1052 foreach ( $_parent_ids as $parent_id ) { |
|
1053 $parent_child_ids = $cache_data[ $cache_keys[ $parent_id ] ]; |
|
1054 if ( false !== $parent_child_ids ) { |
|
1055 $child_ids = array_merge( $child_ids, $parent_child_ids ); |
|
1056 } else { |
|
1057 $uncached_parent_ids[] = $parent_id; |
|
1058 } |
1045 } |
1059 } |
1046 } |
1060 } |
1047 |
1061 |
1048 if ( $uncached_parent_ids ) { |
1062 if ( $uncached_parent_ids ) { |
1049 // Fetch this level of comments. |
1063 // Fetch this level of comments. |
1069 $data = array(); |
1083 $data = array(); |
1070 foreach ( $parent_map as $parent_id => $children ) { |
1084 foreach ( $parent_map as $parent_id => $children ) { |
1071 $cache_key = "get_comment_child_ids:$parent_id:$key:$last_changed"; |
1085 $cache_key = "get_comment_child_ids:$parent_id:$key:$last_changed"; |
1072 $data[ $cache_key ] = $children; |
1086 $data[ $cache_key ] = $children; |
1073 } |
1087 } |
1074 wp_cache_set_multiple( $data, 'comment' ); |
1088 wp_cache_set_multiple( $data, 'comment-queries' ); |
1075 } |
1089 } |
1076 |
1090 |
1077 $level++; |
1091 ++$level; |
1078 $levels[ $level ] = $child_ids; |
1092 $levels[ $level ] = $child_ids; |
1079 } while ( $child_ids ); |
1093 } while ( $child_ids ); |
1080 |
1094 |
1081 // Prime comment caches for non-top-level comments. |
1095 // Prime comment caches for non-top-level comments. |
1082 $descendant_ids = array(); |
1096 $descendant_ids = array(); |