~canonical-sysadmins/wordpress/4.6

« back to all changes in this revision

Viewing changes to wp-includes/comment.php

  • Committer: Manuel Seelaus
  • Date: 2015-12-09 17:47:18 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: manuel.seelaus@canonical.com-20151209174718-coxethm2swbeqksy
Merge WP4.4 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
<?php
2
2
/**
3
 
 * Manages WordPress comments
 
3
 * Core Comment API
4
4
 *
5
5
 * @package WordPress
6
6
 * @subpackage Comment
161
161
 *
162
162
 * @since 2.0.0
163
163
 *
164
 
 * @global wpdb   $wpdb WordPress database abstraction object.
165
 
 * @global object $comment
 
164
 * @global WP_Comment $comment
166
165
 *
167
 
 * @param object|string|int $comment Comment to retrieve.
 
166
 * @param WP_Comment|string|int $comment Comment to retrieve.
168
167
 * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
169
 
 * @return object|array|null Depends on $output value.
 
168
 * @return WP_Comment|array|null Depends on $output value.
170
169
 */
171
 
function get_comment(&$comment, $output = OBJECT) {
172
 
        global $wpdb;
 
170
function get_comment( &$comment = null, $output = OBJECT ) {
 
171
        if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
 
172
                $comment = $GLOBALS['comment'];
 
173
        }
173
174
 
174
 
        if ( empty($comment) ) {
175
 
                if ( isset($GLOBALS['comment']) )
176
 
                        $_comment = & $GLOBALS['comment'];
177
 
                else
178
 
                        $_comment = null;
179
 
        } elseif ( is_object($comment) ) {
180
 
                wp_cache_add($comment->comment_ID, $comment, 'comment');
 
175
        if ( $comment instanceof WP_Comment ) {
181
176
                $_comment = $comment;
 
177
        } elseif ( is_object( $comment ) ) {
 
178
                $_comment = new WP_Comment( $comment );
182
179
        } else {
183
 
                if ( isset($GLOBALS['comment']) && ($GLOBALS['comment']->comment_ID == $comment) ) {
184
 
                        $_comment = & $GLOBALS['comment'];
185
 
                } elseif ( ! $_comment = wp_cache_get($comment, 'comment') ) {
186
 
                        $_comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID = %d LIMIT 1", $comment));
187
 
                        if ( ! $_comment )
188
 
                                return null;
189
 
                        wp_cache_add($_comment->comment_ID, $_comment, 'comment');
190
 
                }
 
180
                $_comment = WP_Comment::get_instance( $comment );
 
181
        }
 
182
 
 
183
        if ( ! $_comment ) {
 
184
                return null;
191
185
        }
192
186
 
193
187
        /**
202
196
        if ( $output == OBJECT ) {
203
197
                return $_comment;
204
198
        } elseif ( $output == ARRAY_A ) {
205
 
                $__comment = get_object_vars($_comment);
206
 
                return $__comment;
 
199
                return $_comment->to_array();
207
200
        } elseif ( $output == ARRAY_N ) {
208
 
                $__comment = array_values(get_object_vars($_comment));
209
 
                return $__comment;
210
 
        } else {
211
 
                return $_comment;
 
201
                return array_values( $_comment->to_array() );
212
202
        }
 
203
        return $_comment;
213
204
}
214
205
 
215
206
/**
229
220
}
230
221
 
231
222
/**
232
 
 * WordPress Comment Query class.
233
 
 *
234
 
 * See WP_Comment_Query::__construct() for accepted arguments.
235
 
 *
236
 
 * @since 3.1.0
237
 
 */
238
 
class WP_Comment_Query {
239
 
        /**
240
 
         * SQL for database query.
241
 
         *
242
 
         * @since 4.0.1
243
 
         * @access public
244
 
         * @var string
245
 
         */
246
 
        public $request;
247
 
 
248
 
        /**
249
 
         * Metadata query container
250
 
         *
251
 
         * @since 3.5.0
252
 
         * @access public
253
 
         * @var object WP_Meta_Query
254
 
         */
255
 
        public $meta_query = false;
256
 
 
257
 
        /**
258
 
         * Date query container
259
 
         *
260
 
         * @since 3.7.0
261
 
         * @access public
262
 
         * @var object WP_Date_Query
263
 
         */
264
 
        public $date_query = false;
265
 
 
266
 
        /**
267
 
         * Query vars set by the user.
268
 
         *
269
 
         * @since 3.1.0
270
 
         * @access public
271
 
         * @var array
272
 
         */
273
 
        public $query_vars;
274
 
 
275
 
        /**
276
 
         * Default values for query vars.
277
 
         *
278
 
         * @since 4.2.0
279
 
         * @access public
280
 
         * @var array
281
 
         */
282
 
        public $query_var_defaults;
283
 
 
284
 
        /**
285
 
         * List of comments located by the query.
286
 
         *
287
 
         * @since 4.0.0
288
 
         * @access public
289
 
         * @var array
290
 
         */
291
 
        public $comments;
292
 
 
293
 
        /**
294
 
         * Make private/protected methods readable for backwards compatibility.
295
 
         *
296
 
         * @since 4.0.0
297
 
         * @access public
298
 
         *
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.
302
 
         */
303
 
        public function __call( $name, $arguments ) {
304
 
                if ( 'get_search_sql' === $name ) {
305
 
                        return call_user_func_array( array( $this, $name ), $arguments );
306
 
                }
307
 
                return false;
308
 
        }
309
 
 
310
 
        /**
311
 
         * Constructor.
312
 
         *
313
 
         * Sets up the comment query, based on the query vars passed.
314
 
         *
315
 
         * @since  4.2.0
316
 
         * @access public
317
 
         *
318
 
         * @param string|array $query {
319
 
         *     Optional. Array or query string of comment query parameters. Default empty.
320
 
         *
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.
329
 
         *                                             Default null.
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.
343
 
         *                                             Default 0.
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'.
357
 
         *                                             Default: '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.
380
 
         * }
381
 
         */
382
 
        public function __construct( $query = '' ) {
383
 
                $this->query_var_defaults = array(
384
 
                        'author_email' => '',
385
 
                        'author__in' => '',
386
 
                        'author__not_in' => '',
387
 
                        'include_unapproved' => '',
388
 
                        'fields' => '',
389
 
                        'ID' => '',
390
 
                        'comment__in' => '',
391
 
                        'comment__not_in' => '',
392
 
                        'karma' => '',
393
 
                        'number' => '',
394
 
                        'offset' => '',
395
 
                        'orderby' => '',
396
 
                        'order' => 'DESC',
397
 
                        'parent' => '',
398
 
                        'post_author__in' => '',
399
 
                        'post_author__not_in' => '',
400
 
                        'post_ID' => '',
401
 
                        'post_id' => 0,
402
 
                        'post__in' => '',
403
 
                        'post__not_in' => '',
404
 
                        'post_author' => '',
405
 
                        'post_name' => '',
406
 
                        'post_parent' => '',
407
 
                        'post_status' => '',
408
 
                        'post_type' => '',
409
 
                        'status' => 'all',
410
 
                        'type' => '',
411
 
                        'type__in' => '',
412
 
                        'type__not_in' => '',
413
 
                        'user_id' => '',
414
 
                        'search' => '',
415
 
                        'count' => false,
416
 
                        'meta_key' => '',
417
 
                        'meta_value' => '',
418
 
                        'meta_query' => '',
419
 
                        'date_query' => null, // See WP_Date_Query
420
 
                );
421
 
 
422
 
                if ( ! empty( $query ) ) {
423
 
                        $this->query( $query );
424
 
                }
425
 
        }
426
 
 
427
 
        /**
428
 
         * Parse arguments passed to the comment query with default query parameters.
429
 
         *
430
 
         * @since  4.2.0 Extracted from WP_Comment_Query::query().
431
 
         *
432
 
         * @access public
433
 
         *
434
 
         * @param string|array $query WP_Comment_Query arguments. See WP_Comment_Query::__construct()
435
 
         */
436
 
        public function parse_query( $query = '' ) {
437
 
                if ( empty( $query ) ) {
438
 
                        $query = $this->query_vars;
439
 
                }
440
 
 
441
 
                $this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
442
 
                do_action_ref_array( 'parse_comment_query', array( &$this ) );
443
 
        }
444
 
 
445
 
        /**
446
 
         * Sets up the WordPress query for retrieving comments.
447
 
         *
448
 
         * @since 3.1.0
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().
454
 
         * @access public
455
 
         *
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.
458
 
         */
459
 
        public function query( $query ) {
460
 
                $this->query_vars = wp_parse_args( $query );
461
 
                return $this->get_comments();
462
 
        }
463
 
 
464
 
        /**
465
 
         * Get a list of comments matching the query vars.
466
 
         *
467
 
         * @since 4.2.0
468
 
         * @access public
469
 
         *
470
 
         * @global wpdb $wpdb WordPress database abstraction object.
471
 
         *
472
 
         * @return int|array The list of comments.
473
 
         */
474
 
        public function get_comments() {
475
 
                global $wpdb;
476
 
 
477
 
                $groupby = '';
478
 
 
479
 
                $this->parse_query();
480
 
 
481
 
                // Parse meta query
482
 
                $this->meta_query = new WP_Meta_Query();
483
 
                $this->meta_query->parse_query_vars( $this->query_vars );
484
 
 
485
 
                /**
486
 
                 * Fires before comments are retrieved.
487
 
                 *
488
 
                 * @since 3.1.0
489
 
                 *
490
 
                 * @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
491
 
                 */
492
 
                do_action_ref_array( 'pre_get_comments', array( &$this ) );
493
 
 
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 );
498
 
                }
499
 
 
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' );
506
 
                }
507
 
                $cache_key = "get_comments:$key:$last_changed";
508
 
 
509
 
                if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
510
 
                        $this->comments = $cache;
511
 
                        return $this->comments;
512
 
                }
513
 
 
514
 
                $where = array();
515
 
 
516
 
                // Assemble clauses related to 'comment_approved'.
517
 
                $approved_clauses = array();
518
 
 
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 );
524
 
                }
525
 
 
526
 
                // 'any' overrides other statuses.
527
 
                if ( ! in_array( 'any', $statuses ) ) {
528
 
                        foreach ( $statuses as $status ) {
529
 
                                switch ( $status ) {
530
 
                                        case 'hold' :
531
 
                                                $status_clauses[] = "comment_approved = '0'";
532
 
                                                break;
533
 
 
534
 
                                        case 'approve' :
535
 
                                                $status_clauses[] = "comment_approved = '1'";
536
 
                                                break;
537
 
 
538
 
                                        case 'all' :
539
 
                                        case '' :
540
 
                                                $status_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )";
541
 
                                                break;
542
 
 
543
 
                                        default :
544
 
                                                $status_clauses[] = $wpdb->prepare( "comment_approved = %s", $status );
545
 
                                                break;
546
 
                                }
547
 
                        }
548
 
 
549
 
                        if ( ! empty( $status_clauses ) ) {
550
 
                                $approved_clauses[] = '( ' . implode( ' OR ', $status_clauses ) . ' )';
551
 
                        }
552
 
                }
553
 
 
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'];
557
 
 
558
 
                        // Accepts arrays or comma-separated strings.
559
 
                        if ( ! is_array( $include_unapproved ) ) {
560
 
                                $include_unapproved = preg_split( '/[\s,]+/', $include_unapproved );
561
 
                        }
562
 
 
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 );
568
 
 
569
 
                                // Otherwise we match against email addresses.
570
 
                                } else {
571
 
                                        $approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier );
572
 
                                }
573
 
                        }
574
 
                }
575
 
 
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];
580
 
                        } else {
581
 
                                $where[] = '( ' . implode( ' OR ', $approved_clauses ) . ' )';
582
 
                        }
583
 
                }
584
 
 
585
 
                $order = ( 'ASC' == strtoupper( $this->query_vars['order'] ) ) ? 'ASC' : 'DESC';
586
 
 
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 ) ) {
589
 
                        $orderby = '';
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'] );
594
 
 
595
 
                        $orderby_array = array();
596
 
                        $found_orderby_comment_ID = false;
597
 
                        foreach ( $ordersby as $_key => $_value ) {
598
 
                                if ( ! $_value ) {
599
 
                                        continue;
600
 
                                }
601
 
 
602
 
                                if ( is_int( $_key ) ) {
603
 
                                        $_orderby = $_value;
604
 
                                        $_order = $order;
605
 
                                } else {
606
 
                                        $_orderby = $_key;
607
 
                                        $_order = $_value;
608
 
                                }
609
 
 
610
 
                                if ( ! $found_orderby_comment_ID && 'comment_ID' === $_orderby ) {
611
 
                                        $found_orderby_comment_ID = true;
612
 
                                }
613
 
 
614
 
                                $parsed = $this->parse_orderby( $_orderby );
615
 
 
616
 
                                if ( ! $parsed ) {
617
 
                                        continue;
618
 
                                }
619
 
 
620
 
                                $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
621
 
                        }
622
 
 
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";
626
 
                        }
627
 
 
628
 
                        // To ensure determinate sorting, always include a comment_ID clause.
629
 
                        if ( ! $found_orderby_comment_ID ) {
630
 
                                $comment_ID_order = '';
631
 
 
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];
636
 
                                                break;
637
 
                                        }
638
 
                                }
639
 
 
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';
645
 
                                                } else {
646
 
                                                        $comment_ID_order = 'DESC';
647
 
                                                }
648
 
 
649
 
                                                break;
650
 
                                        }
651
 
                                }
652
 
 
653
 
                                // Default to DESC.
654
 
                                if ( ! $comment_ID_order ) {
655
 
                                        $comment_ID_order = 'DESC';
656
 
                                }
657
 
 
658
 
                                $orderby_array[] = "$wpdb->comments.comment_ID $comment_ID_order";
659
 
                        }
660
 
 
661
 
                        $orderby = implode( ', ', $orderby_array );
662
 
                } else {
663
 
                        $orderby = "$wpdb->comments.comment_date_gmt $order";
664
 
                }
665
 
 
666
 
                $number = absint( $this->query_vars['number'] );
667
 
                $offset = absint( $this->query_vars['offset'] );
668
 
 
669
 
                if ( ! empty( $number ) ) {
670
 
                        if ( $offset ) {
671
 
                                $limits = 'LIMIT ' . $offset . ',' . $number;
672
 
                        } else {
673
 
                                $limits = 'LIMIT ' . $number;
674
 
                        }
675
 
                } else {
676
 
                        $limits = '';
677
 
                }
678
 
 
679
 
                if ( $this->query_vars['count'] ) {
680
 
                        $fields = 'COUNT(*)';
681
 
                } else {
682
 
                        switch ( strtolower( $this->query_vars['fields'] ) ) {
683
 
                                case 'ids':
684
 
                                        $fields = "$wpdb->comments.comment_ID";
685
 
                                        break;
686
 
                                default:
687
 
                                        $fields = "*";
688
 
                                        break;
689
 
                        }
690
 
                }
691
 
 
692
 
                $join = '';
693
 
 
694
 
                $post_id = absint( $this->query_vars['post_id'] );
695
 
                if ( ! empty( $post_id ) ) {
696
 
                        $where[] = $wpdb->prepare( 'comment_post_ID = %d', $post_id );
697
 
                }
698
 
 
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'] ) ) . ' )';
702
 
                }
703
 
 
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'] ) ) . ' )';
707
 
                }
708
 
 
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'] ) ) . ' )';
712
 
                }
713
 
 
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'] ) ) . ' )';
717
 
                }
718
 
 
719
 
                if ( '' !== $this->query_vars['author_email'] ) {
720
 
                        $where[] = $wpdb->prepare( 'comment_author_email = %s', $this->query_vars['author_email'] );
721
 
                }
722
 
 
723
 
                if ( '' !== $this->query_vars['karma'] ) {
724
 
                        $where[] = $wpdb->prepare( 'comment_karma = %d', $this->query_vars['karma'] );
725
 
                }
726
 
 
727
 
                // Filtering by comment_type: 'type', 'type__in', 'type__not_in'.
728
 
                $raw_types = array(
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'],
731
 
                );
732
 
 
733
 
                $comment_types = array();
734
 
                foreach ( $raw_types as $operator => $_raw_types ) {
735
 
                        $_raw_types = array_unique( $_raw_types );
736
 
 
737
 
                        foreach ( $_raw_types as $type ) {
738
 
                                switch ( $type ) {
739
 
                                        // An empty translates to 'all', for backward compatibility
740
 
                                        case '':
741
 
                                        case 'all' :
742
 
                                                break;
743
 
 
744
 
                                        case 'comment':
745
 
                                        case 'comments':
746
 
                                                $comment_types[ $operator ][] = "''";
747
 
                                                break;
748
 
 
749
 
                                        case 'pings':
750
 
                                                $comment_types[ $operator ][] = "'pingback'";
751
 
                                                $comment_types[ $operator ][] = "'trackback'";
752
 
                                                break;
753
 
 
754
 
                                        default:
755
 
                                                $comment_types[ $operator ][] = $wpdb->prepare( '%s', $type );
756
 
                                                break;
757
 
                                }
758
 
                        }
759
 
 
760
 
                        if ( ! empty( $comment_types[ $operator ] ) ) {
761
 
                                $types_sql = implode( ', ', $comment_types[ $operator ] );
762
 
                                $where[] = "comment_type $operator ($types_sql)";
763
 
                        }
764
 
                }
765
 
 
766
 
                if ( '' !== $this->query_vars['parent'] ) {
767
 
                        $where[] = $wpdb->prepare( 'comment_parent = %d', $this->query_vars['parent'] );
768
 
                }
769
 
 
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'] );
774
 
                }
775
 
 
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' )
780
 
                        );
781
 
 
782
 
                        // Strip leading 'AND'.
783
 
                        $where[] = preg_replace( '/^\s*AND\s*/', '', $search_sql );
784
 
                }
785
 
 
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 );
790
 
 
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 );
797
 
                        }
798
 
                }
799
 
 
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'] ) ) . ' )';
803
 
                }
804
 
 
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'] ) ) . ' )';
808
 
                }
809
 
 
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'] ) ) . ' )';
814
 
                }
815
 
 
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'] ) ) . ' )';
820
 
                }
821
 
 
822
 
                if ( $join_posts_table ) {
823
 
                        $join = "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
824
 
                }
825
 
 
826
 
                if ( ! empty( $meta_query_clauses ) ) {
827
 
                        $join .= $meta_query_clauses['join'];
828
 
 
829
 
                        // Strip leading 'AND'.
830
 
                        $where[] = preg_replace( '/^\s*AND\s*/', '', $meta_query_clauses['where'] );
831
 
 
832
 
                        if ( ! $this->query_vars['count'] ) {
833
 
                                $groupby = "{$wpdb->comments}.comment_ID";
834
 
                        }
835
 
                }
836
 
 
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() );
841
 
                }
842
 
 
843
 
                $where = implode( ' AND ', $where );
844
 
 
845
 
                $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
846
 
                /**
847
 
                 * Filter the comment query clauses.
848
 
                 *
849
 
                 * @since 3.1.0
850
 
                 *
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.
853
 
                 */
854
 
                $clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
855
 
 
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' ] : '';
862
 
 
863
 
                if ( $where ) {
864
 
                        $where = 'WHERE ' . $where;
865
 
                }
866
 
 
867
 
                if ( $groupby ) {
868
 
                        $groupby = 'GROUP BY ' . $groupby;
869
 
                }
870
 
 
871
 
                if ( $orderby ) {
872
 
                        $orderby = "ORDER BY $orderby";
873
 
                }
874
 
 
875
 
                $this->request = "SELECT $fields FROM $wpdb->comments $join $where $groupby $orderby $limits";
876
 
 
877
 
                if ( $this->query_vars['count'] ) {
878
 
                        return $wpdb->get_var( $this->request );
879
 
                }
880
 
 
881
 
                if ( 'ids' == $this->query_vars['fields'] ) {
882
 
                        $this->comments = $wpdb->get_col( $this->request );
883
 
                        return array_map( 'intval', $this->comments );
884
 
                }
885
 
 
886
 
                $results = $wpdb->get_results( $this->request );
887
 
                /**
888
 
                 * Filter the comment query results.
889
 
                 *
890
 
                 * @since 3.1.0
891
 
                 *
892
 
                 * @param array            $results  An array of comments.
893
 
                 * @param WP_Comment_Query &$this    Current instance of WP_Comment_Query, passed by reference.
894
 
                 */
895
 
                $comments = apply_filters_ref_array( 'the_comments', array( $results, &$this ) );
896
 
 
897
 
                wp_cache_add( $cache_key, $comments, 'comment' );
898
 
                if ( '*' === $fields ) {
899
 
                        update_comment_cache( $comments );
900
 
                }
901
 
 
902
 
                $this->comments = $comments;
903
 
                return $this->comments;
904
 
        }
905
 
 
906
 
        /**
907
 
         * Used internally to generate an SQL string for searching across multiple columns
908
 
         *
909
 
         * @since 3.1.0
910
 
         * @access protected
911
 
         *
912
 
         * @global wpdb $wpdb
913
 
         *
914
 
         * @param string $string
915
 
         * @param array $cols
916
 
         * @return string
917
 
         */
918
 
        protected function get_search_sql( $string, $cols ) {
919
 
                global $wpdb;
920
 
 
921
 
                $like = '%' . $wpdb->esc_like( $string ) . '%';
922
 
 
923
 
                $searches = array();
924
 
                foreach ( $cols as $col ) {
925
 
                        $searches[] = $wpdb->prepare( "$col LIKE %s", $like );
926
 
                }
927
 
 
928
 
                return ' AND (' . implode(' OR ', $searches) . ')';
929
 
        }
930
 
 
931
 
        /**
932
 
         * Parse and sanitize 'orderby' keys passed to the comment query.
933
 
         *
934
 
         * @since 4.2.0
935
 
         * @access protected
936
 
         *
937
 
         * @global wpdb $wpdb WordPress database abstraction object.
938
 
         *
939
 
         * @param string $orderby Alias for the field to order by.
940
 
         * @return string|false Value to used in the ORDER clause. False otherwise.
941
 
         */
942
 
        protected function parse_orderby( $orderby ) {
943
 
                global $wpdb;
944
 
 
945
 
                $allowed_keys = array(
946
 
                        'comment_agent',
947
 
                        'comment_approved',
948
 
                        'comment_author',
949
 
                        'comment_author_email',
950
 
                        'comment_author_IP',
951
 
                        'comment_author_url',
952
 
                        'comment_content',
953
 
                        'comment_date',
954
 
                        'comment_date_gmt',
955
 
                        'comment_ID',
956
 
                        'comment_karma',
957
 
                        'comment_parent',
958
 
                        'comment_post_ID',
959
 
                        'comment_type',
960
 
                        'user_id',
961
 
                );
962
 
 
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';
967
 
                }
968
 
 
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 ) );
972
 
                }
973
 
 
974
 
                $parsed = false;
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 ) ) {
980
 
 
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'] ) );
984
 
                        } else {
985
 
                                $parsed = "$wpdb->comments.$orderby";
986
 
                        }
987
 
                }
988
 
 
989
 
                return $parsed;
990
 
        }
991
 
 
992
 
        /**
993
 
         * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
994
 
         *
995
 
         * @since 4.2.0
996
 
         * @access protected
997
 
         *
998
 
         * @param string $order The 'order' query variable.
999
 
         * @return string The sanitized 'order' query variable.
1000
 
         */
1001
 
        protected function parse_order( $order ) {
1002
 
                if ( ! is_string( $order ) || empty( $order ) ) {
1003
 
                        return 'DESC';
1004
 
                }
1005
 
 
1006
 
                if ( 'ASC' === strtoupper( $order ) ) {
1007
 
                        return 'ASC';
1008
 
                } else {
1009
 
                        return 'DESC';
1010
 
                }
1011
 
        }
1012
 
}
1013
 
 
1014
 
/**
1015
223
 * Retrieve all of the WordPress supported comment statuses.
1016
224
 *
1017
225
 * Comments have a limited set of valid status values, this provides the comment
1028
236
                'approve'       => _x('Approved', 'adjective'),
1029
237
                /* translators: comment status */
1030
238
                'spam'          => _x('Spam', 'adjective'),
 
239
                /* translators: comment status */
 
240
                'trash'         => _x('Trash', 'adjective'),
1031
241
        );
1032
242
 
1033
243
        return $status;
1146
356
        ", ARRAY_A);
1147
357
 
1148
358
        $comment_count = array(
1149
 
                "approved"              => 0,
1150
 
                "awaiting_moderation"   => 0,
1151
 
                "spam"                  => 0,
1152
 
                "total_comments"        => 0
 
359
                'approved'            => 0,
 
360
                'awaiting_moderation' => 0,
 
361
                'spam'                => 0,
 
362
                'trash'               => 0,
 
363
                'post-trashed'        => 0,
 
364
                'total_comments'      => 0,
 
365
                'all'                 => 0,
1153
366
        );
1154
367
 
1155
368
        foreach ( $totals as $row ) {
1156
369
                switch ( $row['comment_approved'] ) {
 
370
                        case 'trash':
 
371
                                $comment_count['trash'] = $row['total'];
 
372
                                break;
 
373
                        case 'post-trashed':
 
374
                                $comment_count['post-trashed'] = $row['total'];
 
375
                                break;
1157
376
                        case 'spam':
1158
377
                                $comment_count['spam'] = $row['total'];
1159
 
                                $comment_count["total_comments"] += $row['total'];
 
378
                                $comment_count['total_comments'] += $row['total'];
1160
379
                                break;
1161
 
                        case 1:
 
380
                        case '1':
1162
381
                                $comment_count['approved'] = $row['total'];
1163
382
                                $comment_count['total_comments'] += $row['total'];
 
383
                                $comment_count['all'] += $row['total'];
1164
384
                                break;
1165
 
                        case 0:
 
385
                        case '0':
1166
386
                                $comment_count['awaiting_moderation'] = $row['total'];
1167
387
                                $comment_count['total_comments'] += $row['total'];
 
388
                                $comment_count['all'] += $row['total'];
1168
389
                                break;
1169
390
                        default:
1170
391
                                break;
1254
475
 * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
1255
476
 * to recall previous comments by this commentator that are still held in moderation.
1256
477
 *
1257
 
 * @param object $comment Comment object.
1258
 
 * @param object $user Comment author's object.
 
478
 * @param WP_Comment $comment Comment object.
 
479
 * @param object     $user    Comment author's object.
1259
480
 *
1260
481
 * @since 3.4.0
1261
482
 */
1368
589
                ") AND comment_content = %s LIMIT 1",
1369
590
                wp_unslash( $commentdata['comment_content'] )
1370
591
        );
1371
 
        if ( $wpdb->get_var( $dupe ) ) {
 
592
 
 
593
        $dupe_id = $wpdb->get_var( $dupe );
 
594
 
 
595
        /**
 
596
         * Filters the ID, if any, of the duplicate comment found when creating a new comment.
 
597
         *
 
598
         * Return an empty value from this filter to allow what WP considers a duplicate comment.
 
599
         *
 
600
         * @since 4.4.0
 
601
         *
 
602
         * @param int   $dupe_id     ID of the comment identified as a duplicate.
 
603
         * @param array $commentdata Data for the comment being created.
 
604
         */
 
605
        $dupe_id = apply_filters( 'duplicate_comment_id', $dupe_id, $commentdata );
 
606
 
 
607
        if ( $dupe_id ) {
1372
608
                /**
1373
609
                 * Fires immediately after a duplicate comment is detected.
1374
610
                 *
1436
672
                        $commentdata['comment_author_IP'],
1437
673
                        $commentdata['comment_agent']
1438
674
                ) ) {
1439
 
                        $approved = 'spam';
 
675
                        $approved = EMPTY_TRASH_DAYS ? 'trash' : 'spam';
1440
676
                }
1441
677
        }
1442
678
 
1468
704
 */
1469
705
function check_comment_flood_db( $ip, $email, $date ) {
1470
706
        global $wpdb;
1471
 
        if ( current_user_can( 'manage_options' ) )
1472
 
                return; // don't throttle admins
 
707
        // don't throttle admins or moderators
 
708
        if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
 
709
                return;
 
710
        }
1473
711
        $hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
1474
 
        if ( $lasttime = $wpdb->get_var( $wpdb->prepare( "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( `comment_author_IP` = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1", $hour_ago, $ip, $email ) ) ) {
 
712
 
 
713
        if ( is_user_logged_in() ) {
 
714
                $user = get_current_user_id();
 
715
                $check_column = '`user_id`';
 
716
        } else {
 
717
                $user = $ip;
 
718
                $check_column = '`comment_author_IP`';
 
719
        }
 
720
 
 
721
        $sql = $wpdb->prepare(
 
722
                "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( $check_column = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1",
 
723
                $hour_ago,
 
724
                $user,
 
725
                $email
 
726
        );
 
727
        $lasttime = $wpdb->get_var( $sql );
 
728
        if ( $lasttime ) {
1475
729
                $time_lastcomment = mysql2date('U', $lasttime, false);
1476
730
                $time_newcomment  = mysql2date('U', $date, false);
1477
731
                /**
1535
789
 *
1536
790
 * @global WP_Query $wp_query
1537
791
 *
1538
 
 * @param array $comments Optional array of comment objects. Defaults to $wp_query->comments
 
792
 * @param array $comments Optional array of WP_Comment objects. Defaults to $wp_query->comments
1539
793
 * @param int   $per_page Optional comments per page.
1540
794
 * @param bool  $threaded Optional control over flat or threaded comments.
1541
795
 * @return int Number of comment pages.
1552
806
        if ( empty($comments) )
1553
807
                return 0;
1554
808
 
1555
 
        if ( ! get_option( 'page_comments' ) )
 
809
        if ( ! get_option( 'page_comments' ) ) {
1556
810
                return 1;
 
811
        }
1557
812
 
1558
813
        if ( !isset($per_page) )
1559
814
                $per_page = (int) get_query_var('comments_per_page');
1580
835
 *
1581
836
 * @since 2.7.0
1582
837
 *
1583
 
 * @global wpdb $wpdb
 
838
 * @global wpdb $wpdb WordPress database abstraction object.
1584
839
 *
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'.
 
845
 *                                  Default is '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.
 
850
 * } *
1587
851
 * @return int|null Comment page number or null on error.
1588
852
 */
1589
853
function get_page_of_comment( $comment_ID, $args = array() ) {
1590
854
        global $wpdb;
1591
855
 
 
856
        $page = null;
 
857
 
1592
858
        if ( !$comment = get_comment( $comment_ID ) )
1593
859
                return;
1594
860
 
1595
861
        $defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
1596
862
        $args = wp_parse_args( $args, $defaults );
1597
 
 
1598
 
        if ( '' === $args['per_page'] && get_option('page_comments') )
1599
 
                $args['per_page'] = get_query_var('comments_per_page');
 
863
        $original_args = $args;
 
864
 
 
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' );
 
869
                }
 
870
 
 
871
                if ( '' === $args['per_page'] ) {
 
872
                        $args['per_page'] = get_option( 'comments_per_page' );
 
873
                }
 
874
        }
 
875
 
1600
876
        if ( empty($args['per_page']) ) {
1601
877
                $args['per_page'] = 0;
1602
878
                $args['page'] = 0;
1603
879
        }
1604
 
        if ( $args['per_page'] < 1 )
1605
 
                return 1;
1606
 
 
1607
 
        if ( '' === $args['max_depth'] ) {
1608
 
                if ( get_option('thread_comments') )
1609
 
                        $args['max_depth'] = get_option('thread_comments_depth');
1610
 
                else
1611
 
                        $args['max_depth'] = -1;
1612
 
        }
1613
 
 
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 );
1617
 
 
1618
 
        $allowedtypes = array(
1619
 
                'comment' => '',
1620
 
                'pingback' => 'pingback',
1621
 
                'trackback' => 'trackback',
1622
 
        );
1623
 
 
1624
 
        $comtypewhere = ( 'all' != $args['type'] && isset($allowedtypes[$args['type']]) ) ? " AND comment_type = '" . $allowedtypes[$args['type']] . "'" : '';
1625
 
 
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 ) );
1628
 
 
1629
 
        // No older comments? Then it's page #1.
1630
 
        if ( 0 == $oldercoms )
1631
 
                return 1;
1632
 
 
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'] );
 
880
 
 
881
        if ( $args['per_page'] < 1 ) {
 
882
                $page = 1;
 
883
        }
 
884
 
 
885
        if ( null === $page ) {
 
886
                if ( '' === $args['max_depth'] ) {
 
887
                        if ( get_option('thread_comments') )
 
888
                                $args['max_depth'] = get_option('thread_comments_depth');
 
889
                        else
 
890
                                $args['max_depth'] = -1;
 
891
                }
 
892
 
 
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 );
 
896
 
 
897
                $comment_args = array(
 
898
                        'type'       => $args['type'],
 
899
                        'post_id'    => $comment->comment_post_ID,
 
900
                        'fields'     => 'ids',
 
901
                        'count'      => true,
 
902
                        'status'     => 'approve',
 
903
                        'parent'     => 0,
 
904
                        'date_query' => array(
 
905
                                array(
 
906
                                        'column' => "$wpdb->comments.comment_date_gmt",
 
907
                                        'before' => $comment->comment_date_gmt,
 
908
                                )
 
909
                        ),
 
910
                );
 
911
 
 
912
                $comment_query = new WP_Comment_Query();
 
913
                $older_comment_count = $comment_query->query( $comment_args );
 
914
 
 
915
                // No older comments? Then it's page #1.
 
916
                if ( 0 == $older_comment_count ) {
 
917
                        $page = 1;
 
918
 
 
919
                // Divide comments older than this one by comments per page to get this comment's page number
 
920
                } else {
 
921
                        $page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
 
922
                }
 
923
        }
 
924
 
 
925
        /**
 
926
         * Filters the calculated page on which a comment appears.
 
927
         *
 
928
         * @since 4.4.0
 
929
         *
 
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`.
 
935
         *
 
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.
 
940
         * }
 
941
         * @param array $original_args {
 
942
         *     Array of arguments passed to the function. Some or all of these may not be set.
 
943
         *
 
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.
 
948
         * }
 
949
         */
 
950
        return apply_filters( 'get_page_of_comment', (int) $page, $args, $original_args );
1635
951
}
1636
952
 
1637
953
/**
1704
1020
 *
1705
1021
 * @since 2.5.0
1706
1022
 *
1707
 
 * @global wpdb $wpdb
1708
 
 *
1709
1023
 * @param int $post_id Optional. Post ID.
1710
1024
 * @return object|array Comment stats.
1711
1025
 */
1712
1026
function wp_count_comments( $post_id = 0 ) {
1713
 
        global $wpdb;
1714
 
 
1715
1027
        $post_id = (int) $post_id;
1716
1028
 
1717
1029
        /**
1722
1034
         * @param array $count   An empty array.
1723
1035
         * @param int   $post_id The post ID.
1724
1036
         */
1725
 
        $stats = apply_filters( 'wp_count_comments', array(), $post_id );
1726
 
        if ( !empty($stats) )
1727
 
                return $stats;
1728
 
 
1729
 
        $count = wp_cache_get("comments-{$post_id}", 'counts');
1730
 
 
1731
 
        if ( false !== $count )
 
1037
        $filtered = apply_filters( 'wp_count_comments', array(), $post_id );
 
1038
        if ( ! empty( $filtered ) ) {
 
1039
                return $filtered;
 
1040
        }
 
1041
 
 
1042
        $count = wp_cache_get( "comments-{$post_id}", 'counts' );
 
1043
        if ( false !== $count ) {
1732
1044
                return $count;
1733
 
 
1734
 
        $where = '';
1735
 
        if ( $post_id > 0 )
1736
 
                $where = $wpdb->prepare( "WHERE comment_post_ID = %d", $post_id );
1737
 
 
1738
 
        $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
1739
 
 
1740
 
        $total = 0;
1741
 
        $approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
1742
 
        foreach ( (array) $count as $row ) {
1743
 
                // Don't count post-trashed toward totals
1744
 
                if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] )
1745
 
                        $total += $row['num_comments'];
1746
 
                if ( isset( $approved[$row['comment_approved']] ) )
1747
 
                        $stats[$approved[$row['comment_approved']]] = $row['num_comments'];
1748
 
        }
1749
 
 
1750
 
        $stats['total_comments'] = $total;
1751
 
        foreach ( $approved as $key ) {
1752
 
                if ( empty($stats[$key]) )
1753
 
                        $stats[$key] = 0;
1754
 
        }
1755
 
 
1756
 
        $stats = (object) $stats;
1757
 
        wp_cache_set("comments-{$post_id}", $stats, 'counts');
1758
 
 
1759
 
        return $stats;
 
1045
        }
 
1046
 
 
1047
        $stats = get_comment_count( $post_id );
 
1048
        $stats['moderated'] = $stats['awaiting_moderation'];
 
1049
        unset( $stats['awaiting_moderation'] );
 
1050
 
 
1051
        $stats_object = (object) $stats;
 
1052
        wp_cache_set( "comments-{$post_id}", $stats_object, 'counts' );
 
1053
 
 
1054
        return $stats_object;
1760
1055
}
1761
1056
 
1762
1057
/**
1772
1067
 *
1773
1068
 * @global wpdb $wpdb WordPress database abstraction object.
1774
1069
 *
1775
 
 * @param int $comment_id Comment ID
1776
 
 * @param bool $force_delete Whether to bypass trash and force deletion. Default is false.
 
1070
 * @param int|WP_Comment $comment_id   Comment ID or WP_Comment object.
 
1071
 * @param bool           $force_delete Whether to bypass trash and force deletion. Default is false.
1777
1072
 * @return bool True on success, false on failure.
1778
1073
 */
1779
1074
function wp_delete_comment($comment_id, $force_delete = false) {
1781
1076
        if (!$comment = get_comment($comment_id))
1782
1077
                return false;
1783
1078
 
1784
 
        if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status($comment_id), array( 'trash', 'spam' ) ) )
 
1079
        if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ) ) )
1785
1080
                return wp_trash_comment($comment_id);
1786
1081
 
1787
1082
        /**
1791
1086
         *
1792
1087
         * @param int $comment_id The comment ID.
1793
1088
         */
1794
 
        do_action( 'delete_comment', $comment_id );
 
1089
        do_action( 'delete_comment', $comment->comment_ID );
1795
1090
 
1796
1091
        // Move children up a level.
1797
 
        $children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment_id) );
 
1092
        $children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment->comment_ID) );
1798
1093
        if ( !empty($children) ) {
1799
 
                $wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment_id));
 
1094
                $wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment->comment_ID));
1800
1095
                clean_comment_cache($children);
1801
1096
        }
1802
1097
 
1803
1098
        // Delete metadata
1804
 
        $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment_id ) );
 
1099
        $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
1805
1100
        foreach ( $meta_ids as $mid )
1806
1101
                delete_metadata_by_mid( 'comment', $mid );
1807
1102
 
1808
 
        if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment_id ) ) )
 
1103
        if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment->comment_ID ) ) )
1809
1104
                return false;
1810
1105
 
1811
1106
        /**
1815
1110
         *
1816
1111
         * @param int $comment_id The comment ID.
1817
1112
         */
1818
 
        do_action( 'deleted_comment', $comment_id );
 
1113
        do_action( 'deleted_comment', $comment->comment_ID );
1819
1114
 
1820
1115
        $post_id = $comment->comment_post_ID;
1821
1116
        if ( $post_id && $comment->comment_approved == 1 )
1822
1117
                wp_update_comment_count($post_id);
1823
1118
 
1824
 
        clean_comment_cache($comment_id);
 
1119
        clean_comment_cache( $comment->comment_ID );
1825
1120
 
1826
1121
        /** This action is documented in wp-includes/comment.php */
1827
 
        do_action( 'wp_set_comment_status', $comment_id, 'delete' );
 
1122
        do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
1828
1123
 
1829
1124
        wp_transition_comment_status('delete', $comment->comment_approved, $comment);
1830
1125
        return true;
1837
1132
 *
1838
1133
 * @since 2.9.0
1839
1134
 *
1840
 
 * @param int $comment_id Comment ID.
 
1135
 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
1841
1136
 * @return bool True on success, false on failure.
1842
1137
 */
1843
1138
function wp_trash_comment($comment_id) {
1854
1149
         *
1855
1150
         * @param int $comment_id The comment ID.
1856
1151
         */
1857
 
        do_action( 'trash_comment', $comment_id );
 
1152
        do_action( 'trash_comment', $comment->comment_ID );
1858
1153
 
1859
 
        if ( wp_set_comment_status($comment_id, 'trash') ) {
1860
 
                add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
1861
 
                add_comment_meta($comment_id, '_wp_trash_meta_time', time() );
 
1154
        if ( wp_set_comment_status( $comment, 'trash' ) ) {
 
1155
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
 
1156
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
 
1157
                add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
 
1158
                add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
1862
1159
 
1863
1160
                /**
1864
1161
                 * Fires immediately after a comment is sent to Trash.
1867
1164
                 *
1868
1165
                 * @param int $comment_id The comment ID.
1869
1166
                 */
1870
 
                do_action( 'trashed_comment', $comment_id );
 
1167
                do_action( 'trashed_comment', $comment->comment_ID );
1871
1168
                return true;
1872
1169
        }
1873
1170
 
1879
1176
 *
1880
1177
 * @since 2.9.0
1881
1178
 *
1882
 
 * @param int $comment_id Comment ID.
 
1179
 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
1883
1180
 * @return bool True on success, false on failure.
1884
1181
 */
1885
1182
function wp_untrash_comment($comment_id) {
1886
 
        if ( ! (int)$comment_id )
 
1183
        $comment = get_comment( $comment_id );
 
1184
        if ( ! $comment ) {
1887
1185
                return false;
 
1186
        }
1888
1187
 
1889
1188
        /**
1890
1189
         * Fires immediately before a comment is restored from the Trash.
1893
1192
         *
1894
1193
         * @param int $comment_id The comment ID.
1895
1194
         */
1896
 
        do_action( 'untrash_comment', $comment_id );
 
1195
        do_action( 'untrash_comment', $comment->comment_ID );
1897
1196
 
1898
 
        $status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
 
1197
        $status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
1899
1198
        if ( empty($status) )
1900
1199
                $status = '0';
1901
1200
 
1902
 
        if ( wp_set_comment_status($comment_id, $status) ) {
1903
 
                delete_comment_meta($comment_id, '_wp_trash_meta_time');
1904
 
                delete_comment_meta($comment_id, '_wp_trash_meta_status');
 
1201
        if ( wp_set_comment_status( $comment, $status ) ) {
 
1202
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
 
1203
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
1905
1204
                /**
1906
1205
                 * Fires immediately after a comment is restored from the Trash.
1907
1206
                 *
1909
1208
                 *
1910
1209
                 * @param int $comment_id The comment ID.
1911
1210
                 */
1912
 
                do_action( 'untrashed_comment', $comment_id );
 
1211
                do_action( 'untrashed_comment', $comment->comment_ID );
1913
1212
                return true;
1914
1213
        }
1915
1214
 
1921
1220
 *
1922
1221
 * @since 2.9.0
1923
1222
 *
1924
 
 * @param int $comment_id Comment ID.
 
1223
 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
1925
1224
 * @return bool True on success, false on failure.
1926
1225
 */
1927
 
function wp_spam_comment($comment_id) {
1928
 
        if ( !$comment = get_comment($comment_id) )
 
1226
function wp_spam_comment( $comment_id ) {
 
1227
        $comment = get_comment( $comment_id );
 
1228
        if ( ! $comment ) {
1929
1229
                return false;
 
1230
        }
1930
1231
 
1931
1232
        /**
1932
1233
         * Fires immediately before a comment is marked as Spam.
1935
1236
         *
1936
1237
         * @param int $comment_id The comment ID.
1937
1238
         */
1938
 
        do_action( 'spam_comment', $comment_id );
 
1239
        do_action( 'spam_comment', $comment->comment_ID );
1939
1240
 
1940
 
        if ( wp_set_comment_status($comment_id, 'spam') ) {
1941
 
                add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
 
1241
        if ( wp_set_comment_status( $comment, 'spam' ) ) {
 
1242
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
 
1243
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
 
1244
                add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
 
1245
                add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
1942
1246
                /**
1943
1247
                 * Fires immediately after a comment is marked as Spam.
1944
1248
                 *
1946
1250
                 *
1947
1251
                 * @param int $comment_id The comment ID.
1948
1252
                 */
1949
 
                do_action( 'spammed_comment', $comment_id );
 
1253
                do_action( 'spammed_comment', $comment->comment_ID );
1950
1254
                return true;
1951
1255
        }
1952
1256
 
1958
1262
 *
1959
1263
 * @since 2.9.0
1960
1264
 *
1961
 
 * @param int $comment_id Comment ID.
 
1265
 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
1962
1266
 * @return bool True on success, false on failure.
1963
1267
 */
1964
 
function wp_unspam_comment($comment_id) {
1965
 
        if ( ! (int)$comment_id )
 
1268
function wp_unspam_comment( $comment_id ) {
 
1269
        $comment = get_comment( $comment_id );
 
1270
        if ( ! $comment ) {
1966
1271
                return false;
 
1272
        }
1967
1273
 
1968
1274
        /**
1969
1275
         * Fires immediately before a comment is unmarked as Spam.
1972
1278
         *
1973
1279
         * @param int $comment_id The comment ID.
1974
1280
         */
1975
 
        do_action( 'unspam_comment', $comment_id );
 
1281
        do_action( 'unspam_comment', $comment->comment_ID );
1976
1282
 
1977
 
        $status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
 
1283
        $status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
1978
1284
        if ( empty($status) )
1979
1285
                $status = '0';
1980
1286
 
1981
 
        if ( wp_set_comment_status($comment_id, $status) ) {
1982
 
                delete_comment_meta($comment_id, '_wp_trash_meta_status');
 
1287
        if ( wp_set_comment_status( $comment, $status ) ) {
 
1288
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
 
1289
                delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
1983
1290
                /**
1984
1291
                 * Fires immediately after a comment is unmarked as Spam.
1985
1292
                 *
1987
1294
                 *
1988
1295
                 * @param int $comment_id The comment ID.
1989
1296
                 */
1990
 
                do_action( 'unspammed_comment', $comment_id );
 
1297
                do_action( 'unspammed_comment', $comment->comment_ID );
1991
1298
                return true;
1992
1299
        }
1993
1300
 
1999
1306
 *
2000
1307
 * @since 1.0.0
2001
1308
 *
2002
 
 * @param int $comment_id Comment ID
 
1309
 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object
2003
1310
 * @return false|string Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
2004
1311
 */
2005
1312
function wp_get_comment_status($comment_id) {
2078
1385
                 *
2079
1386
                 * @since 2.7.0
2080
1387
                 *
2081
 
                 * @param object $comment Comment object.
 
1388
                 * @param WP_Comment $comment Comment object.
2082
1389
                 */
2083
1390
                do_action( "comment_{$old_status}_to_{$new_status}", $comment );
2084
1391
        }
2093
1400
         *
2094
1401
         * @since 2.7.0
2095
1402
         *
2096
 
         * @param int $comment_ID The comment ID.
2097
 
         * @param obj $comment    Comment object.
 
1403
         * @param int        $comment_ID The comment ID.
 
1404
         * @param WP_Comment $comment    Comment object.
2098
1405
         */
2099
1406
        do_action( "comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment );
2100
1407
}
2131
1438
         *
2132
1439
         * @since 3.1.0
2133
1440
         *
2134
 
         * @param string $comment_author       Comment author's name.
2135
 
         * @param string $comment_author_email Comment author's email.
2136
 
         * @param string $comment_author_url   Comment author's URL.
 
1441
         * @param array $comment_author_data {
 
1442
         *     An array of current commenter variables.
 
1443
         *
 
1444
         *     @type string $comment_author       The name of the author of the comment. Default empty.
 
1445
         *     @type string $comment_author_email The email address of the `$comment_author`. Default empty.
 
1446
         *     @type string $comment_author_url   The URL address of the `$comment_author`. Default empty.
 
1447
         * }
2137
1448
         */
2138
1449
        return apply_filters( 'wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url') );
2139
1450
}
2142
1453
 * Inserts a comment into the database.
2143
1454
 *
2144
1455
 * @since 2.0.0
 
1456
 * @since 4.4.0 Introduced `$comment_meta` argument.
2145
1457
 *
2146
1458
 * @global wpdb $wpdb WordPress database abstraction object.
2147
1459
 *
2166
1478
 *     @type int        $comment_post_ID      ID of the post that relates to the comment, if any.
2167
1479
 *                                            Default empty.
2168
1480
 *     @type string     $comment_type         Comment type. Default empty.
 
1481
 *     @type array      $comment_meta         Optional. Array of key/value pairs to be stored in commentmeta for the
 
1482
 *                                            new comment.
2169
1483
 *     @type int        $user_id              ID of the user who submitted the comment. Default 0.
2170
1484
 * }
2171
1485
 * @return int|false The new comment's ID on success, false on failure.
2204
1518
        }
2205
1519
        $comment = get_comment( $id );
2206
1520
 
 
1521
        // If metadata is provided, store it.
 
1522
        if ( isset( $commentdata['comment_meta'] ) && is_array( $commentdata['comment_meta'] ) ) {
 
1523
                foreach ( $commentdata['comment_meta'] as $meta_key => $meta_value ) {
 
1524
                        add_comment_meta( $comment->comment_ID, $meta_key, $meta_value, true );
 
1525
                }
 
1526
        }
 
1527
 
2207
1528
        /**
2208
1529
         * Fires immediately after a comment is inserted into the database.
2209
1530
         *
2210
1531
         * @since 2.8.0
2211
1532
         *
2212
 
         * @param int $id      The comment ID.
2213
 
         * @param obj $comment Comment object.
 
1533
         * @param int        $id      The comment ID.
 
1534
         * @param WP_Comment $comment Comment object.
2214
1535
         */
2215
1536
        do_action( 'wp_insert_comment', $id, $comment );
2216
1537
 
2317
1638
 * @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
2318
1639
 *
2319
1640
 * @see wp_insert_comment()
2320
 
 *
2321
 
 * @global wpdb $wpdb
2322
 
 *
2323
 
 * @param array $commentdata Contains information on the comment. See wp_insert_comment()
2324
 
 *                           for information on accepted arguments.
 
1641
 * @global wpdb $wpdb WordPress database abstraction object.
 
1642
 *
 
1643
 * @param array $commentdata {
 
1644
 *     Comment data.
 
1645
 *
 
1646
 *     @type string $comment_author       The name of the comment author.
 
1647
 *     @type string $comment_author_email The comment author email address.
 
1648
 *     @type string $comment_author_url   The comment author URL.
 
1649
 *     @type string $comment_content      The content of the comment.
 
1650
 *     @type string $comment_date         The date the comment was submitted. Default is the current time.
 
1651
 *     @type string $comment_date_gmt     The date the comment was submitted in the GMT timezone.
 
1652
 *                                        Default is `$comment_date` in the GMT timezone.
 
1653
 *     @type int    $comment_parent       The ID of this comment's parent, if any. Default 0.
 
1654
 *     @type int    $comment_post_ID      The ID of the post that relates to the comment.
 
1655
 *     @type int    $user_id              The ID of the user who submitted the comment. Default 0.
 
1656
 *     @type int    $user_ID              Kept for backward-compatibility. Use `$user_id` instead.
 
1657
 *     @type string $comment_agent        Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
 
1658
 *                                        in the `$_SERVER` superglobal sent in the original request.
 
1659
 *     @type string $comment_author_IP    Comment author IP address in IPv4 format. Default is the value of
 
1660
 *                                        'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
 
1661
 * }
2325
1662
 * @return int|false The ID of the comment on success, false on failure.
2326
1663
 */
2327
1664
function wp_new_comment( $commentdata ) {
2379
1716
        if ( ! $comment_ID ) {
2380
1717
                $fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
2381
1718
 
2382
 
                foreach( $fields as $field ) {
 
1719
                foreach ( $fields as $field ) {
2383
1720
                        if ( isset( $commentdata[ $field ] ) ) {
2384
1721
                                $commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
2385
1722
                        }
2400
1737
         *
2401
1738
         * @since 1.2.0
2402
1739
         *
2403
 
         * @param int $comment_ID       The comment ID.
2404
 
         * @param int $comment_approved 1 (true) if the comment is approved, 0 (false) if not.
 
1740
         * @param int        $comment_ID       The comment ID.
 
1741
         * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
2405
1742
         */
2406
1743
        do_action( 'comment_post', $comment_ID, $commentdata['comment_approved'] );
2407
1744
 
2408
 
        if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching
2409
 
                if ( '0' == $commentdata['comment_approved'] ) {
2410
 
                        wp_notify_moderator( $comment_ID );
2411
 
                }
2412
 
 
2413
 
                // wp_notify_postauthor() checks if notifying the author of their own comment.
2414
 
                // By default, it won't, but filters can override this.
2415
 
                if ( get_option( 'comments_notify' ) && $commentdata['comment_approved'] ) {
2416
 
                        wp_notify_postauthor( $comment_ID );
2417
 
                }
2418
 
        }
2419
 
 
2420
1745
        return $comment_ID;
2421
1746
}
2422
1747
 
2423
1748
/**
 
1749
 * Send a comment moderation notification to the comment moderator.
 
1750
 *
 
1751
 * @since 4.4.0
 
1752
 *
 
1753
 * @param int $comment_ID ID of the comment.
 
1754
 * @return bool True on success, false on failure.
 
1755
 */
 
1756
function wp_new_comment_notify_moderator( $comment_ID ) {
 
1757
        $comment = get_comment( $comment_ID );
 
1758
 
 
1759
        // Only send notifications for pending comments.
 
1760
        $maybe_notify = ( '0' == $comment->comment_approved );
 
1761
 
 
1762
        /** This filter is documented in wp-includes/comment.php */
 
1763
        $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_ID );
 
1764
 
 
1765
        if ( ! $maybe_notify ) {
 
1766
                return false;
 
1767
        }
 
1768
 
 
1769
        return wp_notify_moderator( $comment_ID );
 
1770
}
 
1771
 
 
1772
/**
 
1773
 * Send a notification of a new comment to the post author.
 
1774
 *
 
1775
 * @since 4.4.0
 
1776
 *
 
1777
 * Uses the {@see 'notify_post_author'} filter to determine whether the post author
 
1778
 * should be notified when a new comment is added, overriding site setting.
 
1779
 *
 
1780
 * @param int $comment_ID Comment ID.
 
1781
 * @return bool True on success, false on failure.
 
1782
 */
 
1783
function wp_new_comment_notify_postauthor( $comment_ID ) {
 
1784
        $comment = get_comment( $comment_ID );
 
1785
 
 
1786
        $maybe_notify = get_option( 'comments_notify' );
 
1787
 
 
1788
        /**
 
1789
         * Filter whether to send the post author new comment notification emails,
 
1790
         * overriding the site setting.
 
1791
         *
 
1792
         * @since 4.4.0
 
1793
         *
 
1794
         * @param bool $maybe_notify Whether to notify the post author about the new comment.
 
1795
         * @param int  $comment_ID   The ID of the comment for the notification.
 
1796
         */
 
1797
        $maybe_notify = apply_filters( 'notify_post_author', $maybe_notify, $comment_ID );
 
1798
 
 
1799
        /*
 
1800
         * wp_notify_postauthor() checks if notifying the author of their own comment.
 
1801
         * By default, it won't, but filters can override this.
 
1802
         */
 
1803
        if ( ! $maybe_notify ) {
 
1804
                return false;
 
1805
        }
 
1806
 
 
1807
        // Only send notifications for approved comments.
 
1808
        if ( ! isset( $comment->comment_approved ) || 'spam' === $comment->comment_approved || ! $comment->comment_approved ) {
 
1809
                return false;
 
1810
        }
 
1811
 
 
1812
        return wp_notify_postauthor( $comment_ID );
 
1813
}
 
1814
 
 
1815
/**
2424
1816
 * Sets the status of a comment.
2425
1817
 *
2426
1818
 * The 'wp_set_comment_status' action is called after the comment is handled.
2428
1820
 *
2429
1821
 * @since 1.0.0
2430
1822
 *
2431
 
 * global wpdb $wpdb
 
1823
 * @global wpdb $wpdb WordPress database abstraction object.
2432
1824
 *
2433
 
 * @param int $comment_id Comment ID.
2434
 
 * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
2435
 
 * @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default is false.
 
1825
 * @param int|WP_Comment $comment_id     Comment ID or WP_Comment object.
 
1826
 * @param string         $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
 
1827
 * @param bool           $wp_error       Whether to return a WP_Error object if there is a failure. Default is false.
2436
1828
 * @return bool|WP_Error True on success, false or WP_Error on failure.
2437
1829
 */
2438
1830
function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
2446
1838
                case 'approve':
2447
1839
                case '1':
2448
1840
                        $status = '1';
2449
 
                        if ( get_option('comments_notify') ) {
2450
 
                                wp_notify_postauthor( $comment_id );
2451
 
                        }
 
1841
                        add_action( 'wp_set_comment_status', 'wp_new_comment_notify_postauthor' );
2452
1842
                        break;
2453
1843
                case 'spam':
2454
1844
                        $status = 'spam';
2462
1852
 
2463
1853
        $comment_old = clone get_comment($comment_id);
2464
1854
 
2465
 
        if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array('comment_ID' => $comment_id) ) ) {
 
1855
        if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array( 'comment_ID' => $comment_old->comment_ID ) ) ) {
2466
1856
                if ( $wp_error )
2467
1857
                        return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
2468
1858
                else
2469
1859
                        return false;
2470
1860
        }
2471
1861
 
2472
 
        clean_comment_cache($comment_id);
 
1862
        clean_comment_cache( $comment_old->comment_ID );
2473
1863
 
2474
 
        $comment = get_comment($comment_id);
 
1864
        $comment = get_comment( $comment_old->comment_ID );
2475
1865
 
2476
1866
        /**
2477
1867
         * Fires immediately before transitioning a comment's status from one to another
2483
1873
         * @param string|bool $comment_status Current comment status. Possible values include
2484
1874
         *                                    'hold', 'approve', 'spam', 'trash', or false.
2485
1875
         */
2486
 
        do_action( 'wp_set_comment_status', $comment_id, $comment_status );
 
1876
        do_action( 'wp_set_comment_status', $comment->comment_ID, $comment_status );
2487
1877
 
2488
1878
        wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
2489
1879
 
2656
2046
        $post_id = (int) $post_id;
2657
2047
        if ( !$post_id )
2658
2048
                return false;
 
2049
 
 
2050
        wp_cache_delete( 'comments-0', 'counts' );
 
2051
        wp_cache_delete( "comments-{$post_id}", 'counts' );
 
2052
 
2659
2053
        if ( !$post = get_post($post_id) )
2660
2054
                return false;
2661
2055
 
2984
2378
                return;
2985
2379
 
2986
2380
        $options = array();
2987
 
        $options['timeout'] = 4;
 
2381
        $options['timeout'] = 10;
2988
2382
        $options['body'] = array(
2989
2383
                'title' => $title,
2990
2384
                'url' => get_permalink($ID),
3071
2465
 * @param int|array $ids Comment ID or array of comment IDs to remove from cache
3072
2466
 */
3073
2467
function clean_comment_cache($ids) {
3074
 
        foreach ( (array) $ids as $id )
3075
 
                wp_cache_delete($id, 'comment');
 
2468
        foreach ( (array) $ids as $id ) {
 
2469
                wp_cache_delete( $id, 'comment' );
 
2470
        }
3076
2471
 
3077
2472
        wp_cache_set( 'last_changed', microtime(), 'comment' );
3078
2473
}
3085
2480
 * cache using the comment group with the key using the ID of the comments.
3086
2481
 *
3087
2482
 * @since 2.3.0
 
2483
 * @since 4.4.0 Introduced the `$update_meta_cache` parameter.
3088
2484
 *
3089
 
 * @param array $comments Array of comment row objects
 
2485
 * @param array $comments          Array of comment row objects
 
2486
 * @param bool  $update_meta_cache Whether to update commentmeta cache. Default true.
3090
2487
 */
3091
 
function update_comment_cache($comments) {
 
2488
function update_comment_cache( $comments, $update_meta_cache = true ) {
3092
2489
        foreach ( (array) $comments as $comment )
3093
2490
                wp_cache_add($comment->comment_ID, $comment, 'comment');
 
2491
 
 
2492
        if ( $update_meta_cache ) {
 
2493
                // Avoid `wp_list_pluck()` in case `$comments` is passed by reference.
 
2494
                $comment_ids = array();
 
2495
                foreach ( $comments as $comment ) {
 
2496
                        $comment_ids[] = $comment->comment_ID;
 
2497
                }
 
2498
                update_meta_cache( 'comment', $comment_ids );
 
2499
        }
 
2500
}
 
2501
 
 
2502
/**
 
2503
 * Adds any comments from the given IDs to the cache that do not already exist in cache.
 
2504
 *
 
2505
 * @since 4.4.0
 
2506
 * @access private
 
2507
 *
 
2508
 * @see update_comment_cache()
 
2509
 * @global wpdb $wpdb WordPress database abstraction object.
 
2510
 *
 
2511
 * @param array $comment_ids       Array of comment IDs.
 
2512
 * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
 
2513
 */
 
2514
function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) {
 
2515
        global $wpdb;
 
2516
 
 
2517
        $non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' );
 
2518
        if ( !empty( $non_cached_ids ) ) {
 
2519
                $fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
 
2520
 
 
2521
                update_comment_cache( $fresh_comments, $update_meta_cache );
 
2522
        }
3094
2523
}
3095
2524
 
3096
2525
//
3162
2591
        if ( ! in_array( $post->post_type, $post_types ) )
3163
2592
                return $open;
3164
2593
 
 
2594
        // Undated drafts should not show up as comments closed.
 
2595
        if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
 
2596
                return $open;
 
2597
        }
 
2598
 
3165
2599
        if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
3166
2600
                return false;
3167
2601
 
3168
2602
        return $open;
3169
2603
}
 
2604
 
 
2605
/**
 
2606
 * Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form.
 
2607
 *
 
2608
 * This function expects unslashed data, as opposed to functions such as `wp_new_comment()` which
 
2609
 * expect slashed data.
 
2610
 *
 
2611
 * @since 4.4.0
 
2612
 *
 
2613
 * @param array $comment_data {
 
2614
 *     Comment data.
 
2615
 *
 
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.
 
2623
 * }
 
2624
 * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
 
2625
 */
 
2626
function wp_handle_comment_submission( $comment_data ) {
 
2627
 
 
2628
        $comment_post_ID = $comment_parent = 0;
 
2629
        $comment_author = $comment_author_email = $comment_author_url = $comment_content = $_wp_unfiltered_html_comment = null;
 
2630
 
 
2631
        if ( isset( $comment_data['comment_post_ID'] ) ) {
 
2632
                $comment_post_ID = (int) $comment_data['comment_post_ID'];
 
2633
        }
 
2634
        if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
 
2635
                $comment_author = trim( strip_tags( $comment_data['author'] ) );
 
2636
        }
 
2637
        if ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) ) {
 
2638
                $comment_author_email = trim( $comment_data['email'] );
 
2639
        }
 
2640
        if ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) ) {
 
2641
                $comment_author_url = trim( $comment_data['url'] );
 
2642
        }
 
2643
        if ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) ) {
 
2644
                $comment_content = trim( $comment_data['comment'] );
 
2645
        }
 
2646
        if ( isset( $comment_data['comment_parent'] ) ) {
 
2647
                $comment_parent = absint( $comment_data['comment_parent'] );
 
2648
        }
 
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'] );
 
2651
        }
 
2652
 
 
2653
        $post = get_post( $comment_post_ID );
 
2654
 
 
2655
        if ( empty( $post->comment_status ) ) {
 
2656
 
 
2657
                /**
 
2658
                 * Fires when a comment is attempted on a post that does not exist.
 
2659
                 *
 
2660
                 * @since 1.5.0
 
2661
                 *
 
2662
                 * @param int $comment_post_ID Post ID.
 
2663
                 */
 
2664
                do_action( 'comment_id_not_found', $comment_post_ID );
 
2665
 
 
2666
                return new WP_Error( 'comment_id_not_found' );
 
2667
 
 
2668
        }
 
2669
 
 
2670
        // get_post_status() will get the parent status for attachments.
 
2671
        $status = get_post_status( $post );
 
2672
 
 
2673
        if ( ( 'private' == $status ) && ! current_user_can( 'read_post', $comment_post_ID ) ) {
 
2674
                return new WP_Error( 'comment_id_not_found' );
 
2675
        }
 
2676
 
 
2677
        $status_obj = get_post_status_object( $status );
 
2678
 
 
2679
        if ( ! comments_open( $comment_post_ID ) ) {
 
2680
 
 
2681
                /**
 
2682
                 * Fires when a comment is attempted on a post that has comments closed.
 
2683
                 *
 
2684
                 * @since 1.5.0
 
2685
                 *
 
2686
                 * @param int $comment_post_ID Post ID.
 
2687
                 */
 
2688
                do_action( 'comment_closed', $comment_post_ID );
 
2689
 
 
2690
                return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
 
2691
 
 
2692
        } elseif ( 'trash' == $status ) {
 
2693
 
 
2694
                /**
 
2695
                 * Fires when a comment is attempted on a trashed post.
 
2696
                 *
 
2697
                 * @since 2.9.0
 
2698
                 *
 
2699
                 * @param int $comment_post_ID Post ID.
 
2700
                 */
 
2701
                do_action( 'comment_on_trash', $comment_post_ID );
 
2702
 
 
2703
                return new WP_Error( 'comment_on_trash' );
 
2704
 
 
2705
        } elseif ( ! $status_obj->public && ! $status_obj->private ) {
 
2706
 
 
2707
                /**
 
2708
                 * Fires when a comment is attempted on a post in draft mode.
 
2709
                 *
 
2710
                 * @since 1.5.1
 
2711
                 *
 
2712
                 * @param int $comment_post_ID Post ID.
 
2713
                 */
 
2714
                do_action( 'comment_on_draft', $comment_post_ID );
 
2715
 
 
2716
                return new WP_Error( 'comment_on_draft' );
 
2717
 
 
2718
        } elseif ( post_password_required( $comment_post_ID ) ) {
 
2719
 
 
2720
                /**
 
2721
                 * Fires when a comment is attempted on a password-protected post.
 
2722
                 *
 
2723
                 * @since 2.9.0
 
2724
                 *
 
2725
                 * @param int $comment_post_ID Post ID.
 
2726
                 */
 
2727
                do_action( 'comment_on_password_protected', $comment_post_ID );
 
2728
 
 
2729
                return new WP_Error( 'comment_on_password_protected' );
 
2730
 
 
2731
        } else {
 
2732
 
 
2733
                /**
 
2734
                 * Fires before a comment is posted.
 
2735
                 *
 
2736
                 * @since 2.8.0
 
2737
                 *
 
2738
                 * @param int $comment_post_ID Post ID.
 
2739
                 */
 
2740
                do_action( 'pre_comment_on_post', $comment_post_ID );
 
2741
 
 
2742
        }
 
2743
 
 
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;
 
2749
                }
 
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 )
 
2757
                        ) {
 
2758
                                kses_remove_filters(); // start with a clean slate
 
2759
                                kses_init_filters(); // set up the filters
 
2760
                        }
 
2761
                }
 
2762
        } else {
 
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 );
 
2765
                }
 
2766
        }
 
2767
 
 
2768
        $comment_type = '';
 
2769
 
 
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 );
 
2775
                }
 
2776
        }
 
2777
 
 
2778
        if ( '' == $comment_content ) {
 
2779
                return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
 
2780
        }
 
2781
 
 
2782
        $commentdata = compact(
 
2783
                'comment_post_ID',
 
2784
                'comment_author',
 
2785
                'comment_author_email',
 
2786
                'comment_author_url',
 
2787
                'comment_content',
 
2788
                'comment_type',
 
2789
                'comment_parent',
 
2790
                'user_id'
 
2791
        );
 
2792
 
 
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 );
 
2796
        }
 
2797
 
 
2798
        return get_comment( $comment_id );
 
2799
 
 
2800
}