232
* WordPress Comment Query class.
234
* See WP_Comment_Query::__construct() for accepted arguments.
238
class WP_Comment_Query {
240
* SQL for database query.
249
* Metadata query container
253
* @var object WP_Meta_Query
255
public $meta_query = false;
258
* Date query container
262
* @var object WP_Date_Query
264
public $date_query = false;
267
* Query vars set by the user.
276
* Default values for query vars.
282
public $query_var_defaults;
285
* List of comments located by the query.
294
* Make private/protected methods readable for backwards compatibility.
299
* @param callable $name Method to call.
300
* @param array $arguments Arguments to pass when calling.
301
* @return mixed|false Return value of the callback, false otherwise.
303
public function __call( $name, $arguments ) {
304
if ( 'get_search_sql' === $name ) {
305
return call_user_func_array( array( $this, $name ), $arguments );
313
* Sets up the comment query, based on the query vars passed.
318
* @param string|array $query {
319
* Optional. Array or query string of comment query parameters. Default empty.
321
* @type string $author_email Comment author email address. Default empty.
322
* @type array $author__in Array of author IDs to include comments for. Default empty.
323
* @type array $author__not_in Array of author IDs to exclude comments for. Default empty.
324
* @type array $comment__in Array of comment IDs to include. Default empty.
325
* @type array $comment__not_in Array of comment IDs to exclude. Default empty.
326
* @type bool $count Whether to return a comment count (true) or array of comment
327
* objects (false). Default false.
328
* @type array $date_query Date query clauses to limit comments by. See WP_Date_Query.
330
* @type string $fields Comment fields to return. Accepts 'ids' for comment IDs only or
331
* empty for all fields. Default empty.
332
* @type int $ID Currently unused.
333
* @type array $include_unapproved Array of IDs or email addresses of users whose unapproved comments
334
* will be returned by the query regardless of `$status`. Default empty.
335
* @type int $karma Karma score to retrieve matching comments for. Default empty.
336
* @type string $meta_key Include comments with a matching comment meta key. Default empty.
337
* @type string $meta_value Include comments with a matching comment meta value. Requires
338
* `$meta_key` to be set. Default empty.
339
* @type array $meta_query Meta query clauses to limit retrieved comments by.
340
* See WP_Meta_Query. Default empty.
341
* @type int $number Maximum number of comments to retrieve. Default null (no limit).
342
* @type int $offset Number of comments to offset the query. Used to build LIMIT clause.
344
* @type string|array $orderby Comment status or array of statuses. To use 'meta_value' or
345
* 'meta_value_num', `$meta_key` must also be defined. To sort by
346
* a specific `$meta_query` clause, use that clause's array key.
347
* Accepts 'comment_agent', 'comment_approved', 'comment_author',
348
* 'comment_author_email', 'comment_author_IP',
349
* 'comment_author_url', 'comment_content', 'comment_date',
350
* 'comment_date_gmt', 'comment_ID', 'comment_karma',
351
* 'comment_parent', 'comment_post_ID', 'comment_type', 'user_id',
352
* 'meta_value', 'meta_value_num', the value of $meta_key, and the
353
* array keys of `$meta_query`. Also accepts false, an empty array,
354
* or 'none' to disable `ORDER BY` clause.
355
* Default: 'comment_date_gmt'.
356
* @type string $order How to order retrieved comments. Accepts 'ASC', 'DESC'.
358
* @type int $parent Parent ID of comment to retrieve children of. Default empty.
359
* @type array $post_author__in Array of author IDs to retrieve comments for. Default empty.
360
* @type array $post_author__not_in Array of author IDs *not* to retrieve comments for. Default empty.
361
* @type int $post_ID Currently unused.
362
* @type int $post_id Limit results to those affiliated with a given post ID. Default 0.
363
* @type array $post__in Array of post IDs to include affiliated comments for. Default empty.
364
* @type array $post__not_in Array of post IDs to exclude affiliated comments for. Default empty.
365
* @type int $post_author Comment author ID to limit results by. Default empty.
366
* @type string $post_status Post status to retrieve affiliated comments for. Default empty.
367
* @type string $post_type Post type to retrieve affiliated comments for. Default empty.
368
* @type string $post_name Post name to retrieve affiliated comments for. Default empty.
369
* @type int $post_parent Post parent ID to retrieve affiliated comments for. Default empty.
370
* @type string $search Search term(s) to retrieve matching comments for. Default empty.
371
* @type string $status Comment status to limit results by. Accepts 'hold'
372
* (`comment_status=0`), 'approve' (`comment_status=1`), 'all', or a
373
* custom comment status. Default 'all'.
374
* @type string|array $type Include comments of a given type, or array of types. Accepts
375
* 'comment', 'pings' (includes 'pingback' and 'trackback'), or any
376
* custom type string. Default empty.
377
* @type array $type__in Include comments from a given array of comment types. Default empty.
378
* @type array $type__not_in Exclude comments from a given array of comment types. Default empty.
379
* @type int $user_id Include comments for a specific user ID. Default empty.
382
public function __construct( $query = '' ) {
383
$this->query_var_defaults = array(
384
'author_email' => '',
386
'author__not_in' => '',
387
'include_unapproved' => '',
391
'comment__not_in' => '',
398
'post_author__in' => '',
399
'post_author__not_in' => '',
403
'post__not_in' => '',
412
'type__not_in' => '',
419
'date_query' => null, // See WP_Date_Query
422
if ( ! empty( $query ) ) {
423
$this->query( $query );
428
* Parse arguments passed to the comment query with default query parameters.
430
* @since 4.2.0 Extracted from WP_Comment_Query::query().
434
* @param string|array $query WP_Comment_Query arguments. See WP_Comment_Query::__construct()
436
public function parse_query( $query = '' ) {
437
if ( empty( $query ) ) {
438
$query = $this->query_vars;
441
$this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
442
do_action_ref_array( 'parse_comment_query', array( &$this ) );
446
* Sets up the WordPress query for retrieving comments.
449
* @since 4.1.0 Introduced 'comment__in', 'comment__not_in', 'post_author__in',
450
* 'post_author__not_in', 'author__in', 'author__not_in', 'post__in',
451
* 'post__not_in', 'include_unapproved', 'type__in', and 'type__not_in'
452
* arguments to $query_vars.
453
* @since 4.2.0 Moved parsing to WP_Comment_Query::parse_query().
456
* @param string|array $query Array or URL query string of parameters.
457
* @return array|int List of comments, or number of comments when 'count' is passed as a query var.
459
public function query( $query ) {
460
$this->query_vars = wp_parse_args( $query );
461
return $this->get_comments();
465
* Get a list of comments matching the query vars.
470
* @global wpdb $wpdb WordPress database abstraction object.
472
* @return int|array The list of comments.
474
public function get_comments() {
479
$this->parse_query();
482
$this->meta_query = new WP_Meta_Query();
483
$this->meta_query->parse_query_vars( $this->query_vars );
486
* Fires before comments are retrieved.
490
* @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
492
do_action_ref_array( 'pre_get_comments', array( &$this ) );
494
// Reparse query vars, in case they were modified in a 'pre_get_comments' callback.
495
$this->meta_query->parse_query_vars( $this->query_vars );
496
if ( ! empty( $this->meta_query->queries ) ) {
497
$meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
500
// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
501
$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
502
$last_changed = wp_cache_get( 'last_changed', 'comment' );
503
if ( ! $last_changed ) {
504
$last_changed = microtime();
505
wp_cache_set( 'last_changed', $last_changed, 'comment' );
507
$cache_key = "get_comments:$key:$last_changed";
509
if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
510
$this->comments = $cache;
511
return $this->comments;
516
// Assemble clauses related to 'comment_approved'.
517
$approved_clauses = array();
519
// 'status' accepts an array or a comma-separated string.
520
$status_clauses = array();
521
$statuses = $this->query_vars['status'];
522
if ( ! is_array( $statuses ) ) {
523
$statuses = preg_split( '/[\s,]+/', $statuses );
526
// 'any' overrides other statuses.
527
if ( ! in_array( 'any', $statuses ) ) {
528
foreach ( $statuses as $status ) {
531
$status_clauses[] = "comment_approved = '0'";
535
$status_clauses[] = "comment_approved = '1'";
540
$status_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )";
544
$status_clauses[] = $wpdb->prepare( "comment_approved = %s", $status );
549
if ( ! empty( $status_clauses ) ) {
550
$approved_clauses[] = '( ' . implode( ' OR ', $status_clauses ) . ' )';
554
// User IDs or emails whose unapproved comments are included, regardless of $status.
555
if ( ! empty( $this->query_vars['include_unapproved'] ) ) {
556
$include_unapproved = $this->query_vars['include_unapproved'];
558
// Accepts arrays or comma-separated strings.
559
if ( ! is_array( $include_unapproved ) ) {
560
$include_unapproved = preg_split( '/[\s,]+/', $include_unapproved );
563
$unapproved_ids = $unapproved_emails = array();
564
foreach ( $include_unapproved as $unapproved_identifier ) {
565
// Numeric values are assumed to be user ids.
566
if ( is_numeric( $unapproved_identifier ) ) {
567
$approved_clauses[] = $wpdb->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier );
569
// Otherwise we match against email addresses.
571
$approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier );
576
// Collapse comment_approved clauses into a single OR-separated clause.
577
if ( ! empty( $approved_clauses ) ) {
578
if ( 1 === count( $approved_clauses ) ) {
579
$where[] = $approved_clauses[0];
581
$where[] = '( ' . implode( ' OR ', $approved_clauses ) . ' )';
585
$order = ( 'ASC' == strtoupper( $this->query_vars['order'] ) ) ? 'ASC' : 'DESC';
587
// Disable ORDER BY with 'none', an empty array, or boolean false.
588
if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
590
} elseif ( ! empty( $this->query_vars['orderby'] ) ) {
591
$ordersby = is_array( $this->query_vars['orderby'] ) ?
592
$this->query_vars['orderby'] :
593
preg_split( '/[,\s]/', $this->query_vars['orderby'] );
595
$orderby_array = array();
596
$found_orderby_comment_ID = false;
597
foreach ( $ordersby as $_key => $_value ) {
602
if ( is_int( $_key ) ) {
610
if ( ! $found_orderby_comment_ID && 'comment_ID' === $_orderby ) {
611
$found_orderby_comment_ID = true;
614
$parsed = $this->parse_orderby( $_orderby );
620
$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
623
// If no valid clauses were found, order by comment_date_gmt.
624
if ( empty( $orderby_array ) ) {
625
$orderby_array[] = "$wpdb->comments.comment_date_gmt $order";
628
// To ensure determinate sorting, always include a comment_ID clause.
629
if ( ! $found_orderby_comment_ID ) {
630
$comment_ID_order = '';
632
// Inherit order from comment_date or comment_date_gmt, if available.
633
foreach ( $orderby_array as $orderby_clause ) {
634
if ( preg_match( '/comment_date(?:_gmt)*\ (ASC|DESC)/', $orderby_clause, $match ) ) {
635
$comment_ID_order = $match[1];
640
// If no date-related order is available, use the date from the first available clause.
641
if ( ! $comment_ID_order ) {
642
foreach ( $orderby_array as $orderby_clause ) {
643
if ( false !== strpos( 'ASC', $orderby_clause ) ) {
644
$comment_ID_order = 'ASC';
646
$comment_ID_order = 'DESC';
654
if ( ! $comment_ID_order ) {
655
$comment_ID_order = 'DESC';
658
$orderby_array[] = "$wpdb->comments.comment_ID $comment_ID_order";
661
$orderby = implode( ', ', $orderby_array );
663
$orderby = "$wpdb->comments.comment_date_gmt $order";
666
$number = absint( $this->query_vars['number'] );
667
$offset = absint( $this->query_vars['offset'] );
669
if ( ! empty( $number ) ) {
671
$limits = 'LIMIT ' . $offset . ',' . $number;
673
$limits = 'LIMIT ' . $number;
679
if ( $this->query_vars['count'] ) {
680
$fields = 'COUNT(*)';
682
switch ( strtolower( $this->query_vars['fields'] ) ) {
684
$fields = "$wpdb->comments.comment_ID";
694
$post_id = absint( $this->query_vars['post_id'] );
695
if ( ! empty( $post_id ) ) {
696
$where[] = $wpdb->prepare( 'comment_post_ID = %d', $post_id );
699
// Parse comment IDs for an IN clause.
700
if ( ! empty( $this->query_vars['comment__in'] ) ) {
701
$where[] = "$wpdb->comments.comment_ID IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['comment__in'] ) ) . ' )';
704
// Parse comment IDs for a NOT IN clause.
705
if ( ! empty( $this->query_vars['comment__not_in'] ) ) {
706
$where[] = "$wpdb->comments.comment_ID NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['comment__not_in'] ) ) . ' )';
709
// Parse comment post IDs for an IN clause.
710
if ( ! empty( $this->query_vars['post__in'] ) ) {
711
$where[] = 'comment_post_ID IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post__in'] ) ) . ' )';
714
// Parse comment post IDs for a NOT IN clause.
715
if ( ! empty( $this->query_vars['post__not_in'] ) ) {
716
$where[] = 'comment_post_ID NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post__not_in'] ) ) . ' )';
719
if ( '' !== $this->query_vars['author_email'] ) {
720
$where[] = $wpdb->prepare( 'comment_author_email = %s', $this->query_vars['author_email'] );
723
if ( '' !== $this->query_vars['karma'] ) {
724
$where[] = $wpdb->prepare( 'comment_karma = %d', $this->query_vars['karma'] );
727
// Filtering by comment_type: 'type', 'type__in', 'type__not_in'.
729
'IN' => array_merge( (array) $this->query_vars['type'], (array) $this->query_vars['type__in'] ),
730
'NOT IN' => (array) $this->query_vars['type__not_in'],
733
$comment_types = array();
734
foreach ( $raw_types as $operator => $_raw_types ) {
735
$_raw_types = array_unique( $_raw_types );
737
foreach ( $_raw_types as $type ) {
739
// An empty translates to 'all', for backward compatibility
746
$comment_types[ $operator ][] = "''";
750
$comment_types[ $operator ][] = "'pingback'";
751
$comment_types[ $operator ][] = "'trackback'";
755
$comment_types[ $operator ][] = $wpdb->prepare( '%s', $type );
760
if ( ! empty( $comment_types[ $operator ] ) ) {
761
$types_sql = implode( ', ', $comment_types[ $operator ] );
762
$where[] = "comment_type $operator ($types_sql)";
766
if ( '' !== $this->query_vars['parent'] ) {
767
$where[] = $wpdb->prepare( 'comment_parent = %d', $this->query_vars['parent'] );
770
if ( is_array( $this->query_vars['user_id'] ) ) {
771
$where[] = 'user_id IN (' . implode( ',', array_map( 'absint', $this->query_vars['user_id'] ) ) . ')';
772
} elseif ( '' !== $this->query_vars['user_id'] ) {
773
$where[] = $wpdb->prepare( 'user_id = %d', $this->query_vars['user_id'] );
776
if ( '' !== $this->query_vars['search'] ) {
777
$search_sql = $this->get_search_sql(
778
$this->query_vars['search'],
779
array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_content' )
782
// Strip leading 'AND'.
783
$where[] = preg_replace( '/^\s*AND\s*/', '', $search_sql );
786
// If any post-related query vars are passed, join the posts table.
787
$join_posts_table = false;
788
$plucked = wp_array_slice_assoc( $this->query_vars, array( 'post_author', 'post_name', 'post_parent', 'post_status', 'post_type' ) );
789
$post_fields = array_filter( $plucked );
791
if ( ! empty( $post_fields ) ) {
792
$join_posts_table = true;
793
foreach ( $post_fields as $field_name => $field_value ) {
794
// $field_value may be an array.
795
$esses = array_fill( 0, count( (array) $field_value ), '%s' );
796
$where[] = $wpdb->prepare( " {$wpdb->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $field_value );
800
// Comment author IDs for an IN clause.
801
if ( ! empty( $this->query_vars['author__in'] ) ) {
802
$where[] = 'user_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['author__in'] ) ) . ' )';
805
// Comment author IDs for a NOT IN clause.
806
if ( ! empty( $this->query_vars['author__not_in'] ) ) {
807
$where[] = 'user_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['author__not_in'] ) ) . ' )';
810
// Post author IDs for an IN clause.
811
if ( ! empty( $this->query_vars['post_author__in'] ) ) {
812
$join_posts_table = true;
813
$where[] = 'post_author IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post_author__in'] ) ) . ' )';
816
// Post author IDs for a NOT IN clause.
817
if ( ! empty( $this->query_vars['post_author__not_in'] ) ) {
818
$join_posts_table = true;
819
$where[] = 'post_author NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post_author__not_in'] ) ) . ' )';
822
if ( $join_posts_table ) {
823
$join = "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
826
if ( ! empty( $meta_query_clauses ) ) {
827
$join .= $meta_query_clauses['join'];
829
// Strip leading 'AND'.
830
$where[] = preg_replace( '/^\s*AND\s*/', '', $meta_query_clauses['where'] );
832
if ( ! $this->query_vars['count'] ) {
833
$groupby = "{$wpdb->comments}.comment_ID";
837
$date_query = $this->query_vars['date_query'];
838
if ( ! empty( $date_query ) && is_array( $date_query ) ) {
839
$date_query_object = new WP_Date_Query( $date_query, 'comment_date' );
840
$where[] = preg_replace( '/^\s*AND\s*/', '', $date_query_object->get_sql() );
843
$where = implode( ' AND ', $where );
845
$pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
847
* Filter the comment query clauses.
851
* @param array $pieces A compacted array of comment query clauses.
852
* @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
854
$clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
856
$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
857
$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
858
$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
859
$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
860
$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
861
$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
864
$where = 'WHERE ' . $where;
868
$groupby = 'GROUP BY ' . $groupby;
872
$orderby = "ORDER BY $orderby";
875
$this->request = "SELECT $fields FROM $wpdb->comments $join $where $groupby $orderby $limits";
877
if ( $this->query_vars['count'] ) {
878
return $wpdb->get_var( $this->request );
881
if ( 'ids' == $this->query_vars['fields'] ) {
882
$this->comments = $wpdb->get_col( $this->request );
883
return array_map( 'intval', $this->comments );
886
$results = $wpdb->get_results( $this->request );
888
* Filter the comment query results.
892
* @param array $results An array of comments.
893
* @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
895
$comments = apply_filters_ref_array( 'the_comments', array( $results, &$this ) );
897
wp_cache_add( $cache_key, $comments, 'comment' );
898
if ( '*' === $fields ) {
899
update_comment_cache( $comments );
902
$this->comments = $comments;
903
return $this->comments;
907
* Used internally to generate an SQL string for searching across multiple columns
914
* @param string $string
918
protected function get_search_sql( $string, $cols ) {
921
$like = '%' . $wpdb->esc_like( $string ) . '%';
924
foreach ( $cols as $col ) {
925
$searches[] = $wpdb->prepare( "$col LIKE %s", $like );
928
return ' AND (' . implode(' OR ', $searches) . ')';
932
* Parse and sanitize 'orderby' keys passed to the comment query.
937
* @global wpdb $wpdb WordPress database abstraction object.
939
* @param string $orderby Alias for the field to order by.
940
* @return string|false Value to used in the ORDER clause. False otherwise.
942
protected function parse_orderby( $orderby ) {
945
$allowed_keys = array(
949
'comment_author_email',
951
'comment_author_url',
963
if ( ! empty( $this->query_vars['meta_key'] ) ) {
964
$allowed_keys[] = $this->query_vars['meta_key'];
965
$allowed_keys[] = 'meta_value';
966
$allowed_keys[] = 'meta_value_num';
969
$meta_query_clauses = $this->meta_query->get_clauses();
970
if ( $meta_query_clauses ) {
971
$allowed_keys = array_merge( $allowed_keys, array_keys( $meta_query_clauses ) );
975
if ( $orderby == $this->query_vars['meta_key'] || $orderby == 'meta_value' ) {
976
$parsed = "$wpdb->commentmeta.meta_value";
977
} elseif ( $orderby == 'meta_value_num' ) {
978
$parsed = "$wpdb->commentmeta.meta_value+0";
979
} elseif ( in_array( $orderby, $allowed_keys ) ) {
981
if ( isset( $meta_query_clauses[ $orderby ] ) ) {
982
$meta_clause = $meta_query_clauses[ $orderby ];
983
$parsed = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
985
$parsed = "$wpdb->comments.$orderby";
993
* Parse an 'order' query variable and cast it to ASC or DESC as necessary.
998
* @param string $order The 'order' query variable.
999
* @return string The sanitized 'order' query variable.
1001
protected function parse_order( $order ) {
1002
if ( ! is_string( $order ) || empty( $order ) ) {
1006
if ( 'ASC' === strtoupper( $order ) ) {
1015
223
* Retrieve all of the WordPress supported comment statuses.
1017
225
* Comments have a limited set of valid status values, this provides the comment
1583
* @global wpdb $wpdb
838
* @global wpdb $wpdb WordPress database abstraction object.
1585
* @param int $comment_ID Comment ID.
1586
* @param array $args Optional args.
840
* @param int $comment_ID Comment ID.
841
* @param array $args {
842
* Array of optional arguments.
843
* @type string $type Limit paginated comments to those matching a given type. Accepts 'comment',
844
* 'trackback', 'pingback', 'pings' (trackbacks and pingbacks), or 'all'.
846
* @type int $per_page Per-page count to use when calculating pagination. Defaults to the value of the
847
* 'comments_per_page' option.
848
* @type int|string $max_depth If greater than 1, comment page will be determined for the top-level parent of
849
* `$comment_ID`. Defaults to the value of the 'thread_comments_depth' option.
1587
851
* @return int|null Comment page number or null on error.
1589
853
function get_page_of_comment( $comment_ID, $args = array() ) {
1592
858
if ( !$comment = get_comment( $comment_ID ) )
1595
861
$defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
1596
862
$args = wp_parse_args( $args, $defaults );
1598
if ( '' === $args['per_page'] && get_option('page_comments') )
1599
$args['per_page'] = get_query_var('comments_per_page');
863
$original_args = $args;
865
// Order of precedence: 1. `$args['per_page']`, 2. 'comments_per_page' query_var, 3. 'comments_per_page' option.
866
if ( get_option( 'page_comments' ) ) {
867
if ( '' === $args['per_page'] ) {
868
$args['per_page'] = get_query_var( 'comments_per_page' );
871
if ( '' === $args['per_page'] ) {
872
$args['per_page'] = get_option( 'comments_per_page' );
1600
876
if ( empty($args['per_page']) ) {
1601
877
$args['per_page'] = 0;
1602
878
$args['page'] = 0;
1604
if ( $args['per_page'] < 1 )
1607
if ( '' === $args['max_depth'] ) {
1608
if ( get_option('thread_comments') )
1609
$args['max_depth'] = get_option('thread_comments_depth');
1611
$args['max_depth'] = -1;
1614
// Find this comment's top level parent if threading is enabled
1615
if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
1616
return get_page_of_comment( $comment->comment_parent, $args );
1618
$allowedtypes = array(
1620
'pingback' => 'pingback',
1621
'trackback' => 'trackback',
1624
$comtypewhere = ( 'all' != $args['type'] && isset($allowedtypes[$args['type']]) ) ? " AND comment_type = '" . $allowedtypes[$args['type']] . "'" : '';
1626
// Count comments older than this one
1627
$oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = 0 AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) );
1629
// No older comments? Then it's page #1.
1630
if ( 0 == $oldercoms )
1633
// Divide comments older than this one by comments per page to get this comment's page number
1634
return ceil( ( $oldercoms + 1 ) / $args['per_page'] );
881
if ( $args['per_page'] < 1 ) {
885
if ( null === $page ) {
886
if ( '' === $args['max_depth'] ) {
887
if ( get_option('thread_comments') )
888
$args['max_depth'] = get_option('thread_comments_depth');
890
$args['max_depth'] = -1;
893
// Find this comment's top level parent if threading is enabled
894
if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
895
return get_page_of_comment( $comment->comment_parent, $args );
897
$comment_args = array(
898
'type' => $args['type'],
899
'post_id' => $comment->comment_post_ID,
902
'status' => 'approve',
904
'date_query' => array(
906
'column' => "$wpdb->comments.comment_date_gmt",
907
'before' => $comment->comment_date_gmt,
912
$comment_query = new WP_Comment_Query();
913
$older_comment_count = $comment_query->query( $comment_args );
915
// No older comments? Then it's page #1.
916
if ( 0 == $older_comment_count ) {
919
// Divide comments older than this one by comments per page to get this comment's page number
921
$page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
926
* Filters the calculated page on which a comment appears.
930
* @param int $page Comment page.
931
* @param array $args {
932
* Arguments used to calculate pagination. These include arguments auto-detected by the function,
933
* based on query vars, system settings, etc. For pristine arguments passed to the function,
934
* see `$original_args`.
936
* @type string $type Type of comments to count.
937
* @type int $page Calculated current page.
938
* @type int $per_page Calculated number of comments per page.
939
* @type int $max_depth Maximum comment threading depth allowed.
941
* @param array $original_args {
942
* Array of arguments passed to the function. Some or all of these may not be set.
944
* @type string $type Type of comments to count.
945
* @type int $page Current comment page.
946
* @type int $per_page Number of comments per page.
947
* @type int $max_depth Maximum comment threading depth allowed.
950
return apply_filters( 'get_page_of_comment', (int) $page, $args, $original_args );
3162
2591
if ( ! in_array( $post->post_type, $post_types ) )
2594
// Undated drafts should not show up as comments closed.
2595
if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
3165
2599
if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
2606
* Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form.
2608
* This function expects unslashed data, as opposed to functions such as `wp_new_comment()` which
2609
* expect slashed data.
2613
* @param array $comment_data {
2616
* @type string|int $comment_post_ID The ID of the post that relates to the comment.
2617
* @type string $author The name of the comment author.
2618
* @type string $email The comment author email address.
2619
* @type string $url The comment author URL.
2620
* @type string $comment The content of the comment.
2621
* @type string|int $comment_parent The ID of this comment's parent, if any. Default 0.
2622
* @type string $_wp_unfiltered_html_comment The nonce value for allowing unfiltered HTML.
2624
* @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
2626
function wp_handle_comment_submission( $comment_data ) {
2628
$comment_post_ID = $comment_parent = 0;
2629
$comment_author = $comment_author_email = $comment_author_url = $comment_content = $_wp_unfiltered_html_comment = null;
2631
if ( isset( $comment_data['comment_post_ID'] ) ) {
2632
$comment_post_ID = (int) $comment_data['comment_post_ID'];
2634
if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
2635
$comment_author = trim( strip_tags( $comment_data['author'] ) );
2637
if ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) ) {
2638
$comment_author_email = trim( $comment_data['email'] );
2640
if ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) ) {
2641
$comment_author_url = trim( $comment_data['url'] );
2643
if ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) ) {
2644
$comment_content = trim( $comment_data['comment'] );
2646
if ( isset( $comment_data['comment_parent'] ) ) {
2647
$comment_parent = absint( $comment_data['comment_parent'] );
2649
if ( isset( $comment_data['_wp_unfiltered_html_comment'] ) && is_string( $comment_data['_wp_unfiltered_html_comment'] ) ) {
2650
$_wp_unfiltered_html_comment = trim( $comment_data['_wp_unfiltered_html_comment'] );
2653
$post = get_post( $comment_post_ID );
2655
if ( empty( $post->comment_status ) ) {
2658
* Fires when a comment is attempted on a post that does not exist.
2662
* @param int $comment_post_ID Post ID.
2664
do_action( 'comment_id_not_found', $comment_post_ID );
2666
return new WP_Error( 'comment_id_not_found' );
2670
// get_post_status() will get the parent status for attachments.
2671
$status = get_post_status( $post );
2673
if ( ( 'private' == $status ) && ! current_user_can( 'read_post', $comment_post_ID ) ) {
2674
return new WP_Error( 'comment_id_not_found' );
2677
$status_obj = get_post_status_object( $status );
2679
if ( ! comments_open( $comment_post_ID ) ) {
2682
* Fires when a comment is attempted on a post that has comments closed.
2686
* @param int $comment_post_ID Post ID.
2688
do_action( 'comment_closed', $comment_post_ID );
2690
return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
2692
} elseif ( 'trash' == $status ) {
2695
* Fires when a comment is attempted on a trashed post.
2699
* @param int $comment_post_ID Post ID.
2701
do_action( 'comment_on_trash', $comment_post_ID );
2703
return new WP_Error( 'comment_on_trash' );
2705
} elseif ( ! $status_obj->public && ! $status_obj->private ) {
2708
* Fires when a comment is attempted on a post in draft mode.
2712
* @param int $comment_post_ID Post ID.
2714
do_action( 'comment_on_draft', $comment_post_ID );
2716
return new WP_Error( 'comment_on_draft' );
2718
} elseif ( post_password_required( $comment_post_ID ) ) {
2721
* Fires when a comment is attempted on a password-protected post.
2725
* @param int $comment_post_ID Post ID.
2727
do_action( 'comment_on_password_protected', $comment_post_ID );
2729
return new WP_Error( 'comment_on_password_protected' );
2734
* Fires before a comment is posted.
2738
* @param int $comment_post_ID Post ID.
2740
do_action( 'pre_comment_on_post', $comment_post_ID );
2744
// If the user is logged in
2745
$user = wp_get_current_user();
2746
if ( $user->exists() ) {
2747
if ( empty( $user->display_name ) ) {
2748
$user->display_name=$user->user_login;
2750
$comment_author = $user->display_name;
2751
$comment_author_email = $user->user_email;
2752
$comment_author_url = $user->user_url;
2753
$user_id = $user->ID;
2754
if ( current_user_can( 'unfiltered_html' ) ) {
2755
if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
2756
|| ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
2758
kses_remove_filters(); // start with a clean slate
2759
kses_init_filters(); // set up the filters
2763
if ( get_option( 'comment_registration' ) ) {
2764
return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to post a comment.' ), 403 );
2770
if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
2771
if ( 6 > strlen( $comment_author_email ) || '' == $comment_author ) {
2772
return new WP_Error( 'require_name_email', __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
2773
} elseif ( ! is_email( $comment_author_email ) ) {
2774
return new WP_Error( 'require_valid_email', __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
2778
if ( '' == $comment_content ) {
2779
return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
2782
$commentdata = compact(
2785
'comment_author_email',
2786
'comment_author_url',
2793
$comment_id = wp_new_comment( wp_slash( $commentdata ) );
2794
if ( ! $comment_id ) {
2795
return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
2798
return get_comment( $comment_id );