wp/wp-includes/comment.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * Manages WordPress comments
     3  * Core Comment API
     4  *
     4  *
     5  * @package WordPress
     5  * @package WordPress
     6  * @subpackage Comment
     6  * @subpackage Comment
     7  */
     7  */
     8 
     8 
    42 	// If manual moderation is enabled, skip all checks and return false.
    42 	// If manual moderation is enabled, skip all checks and return false.
    43 	if ( 1 == get_option('comment_moderation') )
    43 	if ( 1 == get_option('comment_moderation') )
    44 		return false;
    44 		return false;
    45 
    45 
    46 	/** This filter is documented in wp-includes/comment-template.php */
    46 	/** This filter is documented in wp-includes/comment-template.php */
    47 	$comment = apply_filters( 'comment_text', $comment );
    47 	$comment = apply_filters( 'comment_text', $comment, null, array() );
    48 
    48 
    49 	// Check for the number of external links if a max allowed number is set.
    49 	// Check for the number of external links if a max allowed number is set.
    50 	if ( $max_links = get_option( 'comment_max_links' ) ) {
    50 	if ( $max_links = get_option( 'comment_max_links' ) ) {
    51 		$num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
    51 		$num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
    52 
    52 
    53 		/**
    53 		/**
    54 		 * Filter the maximum number of links allowed in a comment.
    54 		 * Filters the number of links found in a comment.
    55 		 *
    55 		 *
    56 		 * @since 3.0.0
    56 		 * @since 3.0.0
    57 		 *
    57 		 * @since 4.7.0 Added the `$comment` parameter.
    58 		 * @param int    $num_links The number of links allowed.
    58 		 *
       
    59 		 * @param int    $num_links The number of links found.
    59 		 * @param string $url       Comment author's URL. Included in allowed links total.
    60 		 * @param string $url       Comment author's URL. Included in allowed links total.
       
    61 		 * @param string $comment   Content of the comment.
    60 		 */
    62 		 */
    61 		$num_links = apply_filters( 'comment_max_links_url', $num_links, $url );
    63 		$num_links = apply_filters( 'comment_max_links_url', $num_links, $url, $comment );
    62 
    64 
    63 		/*
    65 		/*
    64 		 * If the number of links in the comment exceeds the allowed amount,
    66 		 * If the number of links in the comment exceeds the allowed amount,
    65 		 * fail the check by returning false.
    67 		 * fail the check by returning false.
    66 		 */
    68 		 */
   108 	 * as well as whether there are any moderation keywords (if set) present in the author
   110 	 * as well as whether there are any moderation keywords (if set) present in the author
   109 	 * email address. If both checks pass, return true. Otherwise, return false.
   111 	 * email address. If both checks pass, return true. Otherwise, return false.
   110 	 */
   112 	 */
   111 	if ( 1 == get_option('comment_whitelist')) {
   113 	if ( 1 == get_option('comment_whitelist')) {
   112 		if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
   114 		if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
   113 			// expected_slashed ($author, $email)
   115 			$comment_user = get_user_by( 'email', wp_unslash( $email ) );
   114 			$ok_to_comment = $wpdb->get_var("SELECT comment_approved FROM $wpdb->comments WHERE comment_author = '$author' AND comment_author_email = '$email' and comment_approved = '1' LIMIT 1");
   116 			if ( ! empty( $comment_user->ID ) ) {
       
   117 				$ok_to_comment = $wpdb->get_var( $wpdb->prepare( "SELECT comment_approved FROM $wpdb->comments WHERE user_id = %d AND comment_approved = '1' LIMIT 1", $comment_user->ID ) );
       
   118 			} else {
       
   119 				// expected_slashed ($author, $email)
       
   120 				$ok_to_comment = $wpdb->get_var( $wpdb->prepare( "SELECT comment_approved FROM $wpdb->comments WHERE comment_author = %s AND comment_author_email = %s and comment_approved = '1' LIMIT 1", $author, $email ) );
       
   121 			}
   115 			if ( ( 1 == $ok_to_comment ) &&
   122 			if ( ( 1 == $ok_to_comment ) &&
   116 				( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
   123 				( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
   117 					return true;
   124 					return true;
   118 			else
   125 			else
   119 				return false;
   126 				return false;
   126 
   133 
   127 /**
   134 /**
   128  * Retrieve the approved comments for post $post_id.
   135  * Retrieve the approved comments for post $post_id.
   129  *
   136  *
   130  * @since 2.0.0
   137  * @since 2.0.0
   131  * @since 4.1.0 Refactored to leverage {@see WP_Comment_Query} over a direct query.
   138  * @since 4.1.0 Refactored to leverage WP_Comment_Query over a direct query.
   132  *
   139  *
   133  * @param  int   $post_id The ID of the post.
   140  * @param  int   $post_id The ID of the post.
   134  * @param  array $args    Optional. See {@see WP_Comment_Query::query()} for information
   141  * @param  array $args    Optional. See WP_Comment_Query::__construct() for information on accepted arguments.
   135  *                        on accepted arguments.
       
   136  * @return int|array $comments The approved comments, or number of comments if `$count`
   142  * @return int|array $comments The approved comments, or number of comments if `$count`
   137  *                             argument is true.
   143  *                             argument is true.
   138  */
   144  */
   139 function get_approved_comments( $post_id, $args = array() ) {
   145 function get_approved_comments( $post_id, $args = array() ) {
   140 	if ( ! $post_id ) {
   146 	if ( ! $post_id ) {
   159  * after being passed through a filter. If the comment is empty, then the global
   165  * after being passed through a filter. If the comment is empty, then the global
   160  * comment variable will be used, if it is set.
   166  * comment variable will be used, if it is set.
   161  *
   167  *
   162  * @since 2.0.0
   168  * @since 2.0.0
   163  *
   169  *
   164  * @global wpdb $wpdb WordPress database abstraction object.
   170  * @global WP_Comment $comment
   165  *
   171  *
   166  * @param object|string|int $comment Comment to retrieve.
   172  * @param WP_Comment|string|int $comment Comment to retrieve.
   167  * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
   173  * @param string                $output  Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
   168  * @return object|array|null Depends on $output value.
   174  *                                       a WP_Comment object, an associative array, or a numeric array, respectively. Default OBJECT.
   169  */
   175  * @return WP_Comment|array|null Depends on $output value.
   170 function get_comment(&$comment, $output = OBJECT) {
   176  */
   171 	global $wpdb;
   177 function get_comment( &$comment = null, $output = OBJECT ) {
   172 
   178 	if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
   173 	if ( empty($comment) ) {
   179 		$comment = $GLOBALS['comment'];
   174 		if ( isset($GLOBALS['comment']) )
   180 	}
   175 			$_comment = & $GLOBALS['comment'];
   181 
   176 		else
   182 	if ( $comment instanceof WP_Comment ) {
   177 			$_comment = null;
       
   178 	} elseif ( is_object($comment) ) {
       
   179 		wp_cache_add($comment->comment_ID, $comment, 'comment');
       
   180 		$_comment = $comment;
   183 		$_comment = $comment;
       
   184 	} elseif ( is_object( $comment ) ) {
       
   185 		$_comment = new WP_Comment( $comment );
   181 	} else {
   186 	} else {
   182 		if ( isset($GLOBALS['comment']) && ($GLOBALS['comment']->comment_ID == $comment) ) {
   187 		$_comment = WP_Comment::get_instance( $comment );
   183 			$_comment = & $GLOBALS['comment'];
   188 	}
   184 		} elseif ( ! $_comment = wp_cache_get($comment, 'comment') ) {
   189 
   185 			$_comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID = %d LIMIT 1", $comment));
   190 	if ( ! $_comment ) {
   186 			if ( ! $_comment )
   191 		return null;
   187 				return null;
       
   188 			wp_cache_add($_comment->comment_ID, $_comment, 'comment');
       
   189 		}
       
   190 	}
   192 	}
   191 
   193 
   192 	/**
   194 	/**
   193 	 * Fires after a comment is retrieved.
   195 	 * Fires after a comment is retrieved.
   194 	 *
   196 	 *
   199 	$_comment = apply_filters( 'get_comment', $_comment );
   201 	$_comment = apply_filters( 'get_comment', $_comment );
   200 
   202 
   201 	if ( $output == OBJECT ) {
   203 	if ( $output == OBJECT ) {
   202 		return $_comment;
   204 		return $_comment;
   203 	} elseif ( $output == ARRAY_A ) {
   205 	} elseif ( $output == ARRAY_A ) {
   204 		$__comment = get_object_vars($_comment);
   206 		return $_comment->to_array();
   205 		return $__comment;
       
   206 	} elseif ( $output == ARRAY_N ) {
   207 	} elseif ( $output == ARRAY_N ) {
   207 		$__comment = array_values(get_object_vars($_comment));
   208 		return array_values( $_comment->to_array() );
   208 		return $__comment;
   209 	}
   209 	} else {
   210 	return $_comment;
   210 		return $_comment;
       
   211 	}
       
   212 }
   211 }
   213 
   212 
   214 /**
   213 /**
   215  * Retrieve a list of comments.
   214  * Retrieve a list of comments.
   216  *
   215  *
   217  * The comment list can be for the blog as a whole or for an individual post.
   216  * The comment list can be for the blog as a whole or for an individual post.
   218  *
   217  *
   219  * @since 2.7.0
   218  * @since 2.7.0
   220  *
   219  *
   221  * @param string|array $args Optional. Array or string of arguments. See {@see WP_Comment_Query::parse_query()}
   220  * @param string|array $args Optional. Array or string of arguments. See WP_Comment_Query::__construct()
   222  *                           for information on accepted arguments. Default empty.
   221  *                           for information on accepted arguments. Default empty.
   223  * @return int|array List of comments or number of found comments if `$count` argument is true.
   222  * @return int|array List of comments or number of found comments if `$count` argument is true.
   224  */
   223  */
   225 function get_comments( $args = '' ) {
   224 function get_comments( $args = '' ) {
   226 	$query = new WP_Comment_Query;
   225 	$query = new WP_Comment_Query;
   227 	return $query->query( $args );
   226 	return $query->query( $args );
   228 }
   227 }
   229 
   228 
   230 /**
   229 /**
   231  * WordPress Comment Query class.
       
   232  *
       
   233  * See WP_Comment_Query::__construct() for accepted arguments.
       
   234  *
       
   235  * @since 3.1.0
       
   236  */
       
   237 class WP_Comment_Query {
       
   238 	/**
       
   239 	 * SQL for database query.
       
   240 	 *
       
   241 	 * @since 4.0.1
       
   242 	 * @access public
       
   243 	 * @var string
       
   244 	 */
       
   245 	public $request;
       
   246 
       
   247 	/**
       
   248 	 * Metadata query container
       
   249 	 *
       
   250 	 * @since 3.5.0
       
   251 	 * @access public
       
   252 	 * @var object WP_Meta_Query
       
   253 	 */
       
   254 	public $meta_query = false;
       
   255 
       
   256 	/**
       
   257 	 * Date query container
       
   258 	 *
       
   259 	 * @since 3.7.0
       
   260 	 * @access public
       
   261 	 * @var object WP_Date_Query
       
   262 	 */
       
   263 	public $date_query = false;
       
   264 
       
   265 	/**
       
   266 	 * Query vars set by the user.
       
   267 	 *
       
   268 	 * @since 3.1.0
       
   269 	 * @access public
       
   270 	 * @var array
       
   271 	 */
       
   272 	public $query_vars;
       
   273 
       
   274 	/**
       
   275 	 * Default values for query vars.
       
   276 	 *
       
   277 	 * @since 4.2.0
       
   278 	 * @access public
       
   279 	 * @var array
       
   280 	 */
       
   281 	public $query_var_defaults;
       
   282 
       
   283 	/**
       
   284 	 * List of comments located by the query.
       
   285 	 *
       
   286 	 * @since 4.0.0
       
   287 	 * @access public
       
   288 	 * @var array
       
   289 	 */
       
   290 	public $comments;
       
   291 
       
   292 	/**
       
   293 	 * Make private/protected methods readable for backwards compatibility.
       
   294 	 *
       
   295 	 * @since 4.0.0
       
   296 	 * @access public
       
   297 	 *
       
   298 	 * @param callable $name      Method to call.
       
   299 	 * @param array    $arguments Arguments to pass when calling.
       
   300 	 * @return mixed|bool Return value of the callback, false otherwise.
       
   301 	 */
       
   302 	public function __call( $name, $arguments ) {
       
   303 		if ( 'get_search_sql' === $name ) {
       
   304 			return call_user_func_array( array( $this, $name ), $arguments );
       
   305 		}
       
   306 		return false;
       
   307 	}
       
   308 
       
   309 	/**
       
   310 	 * Constructor.
       
   311 	 *
       
   312 	 * Sets up the comment query, based on the query vars passed.
       
   313 	 *
       
   314 	 * @since  4.2.0
       
   315 	 * @access public
       
   316 	 *
       
   317 	 * @param string|array $query {
       
   318 	 *     Optional. Array or query string of comment query parameters. Default empty.
       
   319 	 *
       
   320 	 *     @type string       $author_email        Comment author email address. Default empty.
       
   321 	 *     @type array        $author__in          Array of author IDs to include comments for. Default empty.
       
   322 	 *     @type array        $author__not_in      Array of author IDs to exclude comments for. Default empty.
       
   323 	 *     @type array        $comment__in         Array of comment IDs to include. Default empty.
       
   324 	 *     @type array        $comment__not_in     Array of comment IDs to exclude. Default empty.
       
   325 	 *     @type bool         $count               Whether to return a comment count (true) or array of comment
       
   326 	 *                                             objects (false). Default false.
       
   327 	 *     @type array        $date_query          Date query clauses to limit comments by. See WP_Date_Query.
       
   328 	 *                                             Default null.
       
   329 	 *     @type string       $fields              Comment fields to return. Accepts 'ids' for comment IDs only or
       
   330 	 *                                             empty for all fields. Default empty.
       
   331 	 *     @type int          $ID                  Currently unused.
       
   332 	 *     @type array        $include_unapproved  Array of IDs or email addresses of users whose unapproved comments
       
   333 	 *                                             will be returned by the query regardless of `$status`. Default empty.
       
   334 	 *     @type int          $karma               Karma score to retrieve matching comments for. Default empty.
       
   335 	 *     @type string       $meta_key            Include comments with a matching comment meta key. Default empty.
       
   336 	 *     @type string       $meta_value          Include comments with a matching comment meta value. Requires
       
   337 	 *                                             `$meta_key` to be set. Default empty.
       
   338 	 *     @type array        $meta_query          Meta query clauses to limit retrieved comments by.
       
   339 	 *                                             See WP_Meta_Query. Default empty.
       
   340 	 *     @type int          $number              Maximum number of comments to retrieve. Default null (no limit).
       
   341 	 *     @type int          $offset              Number of comments to offset the query. Used to build LIMIT clause.
       
   342 	 *                                             Default 0.
       
   343 	 *     @type string|array $orderby             Comment status or array of statuses. To use 'meta_value' or
       
   344 	 *                                             'meta_value_num', `$meta_key` must also be defined. To sort by
       
   345 	 *                                             a specific `$meta_query` clause, use that clause's array key.
       
   346 	 *                                             Accepts 'comment_agent', 'comment_approved', 'comment_author',
       
   347 	 *                                             'comment_author_email', 'comment_author_IP',
       
   348 	 *                                             'comment_author_url', 'comment_content', 'comment_date',
       
   349 	 *                                             'comment_date_gmt', 'comment_ID', 'comment_karma',
       
   350 	 *                                             'comment_parent', 'comment_post_ID', 'comment_type', 'user_id',
       
   351 	 *                                             'meta_value', 'meta_value_num', the value of $meta_key, and the
       
   352 	 *                                             array keys of `$meta_query`. Also accepts false, an empty array,
       
   353 	 *                                             or 'none' to disable `ORDER BY` clause.
       
   354 	 *                                             Default: 'comment_date_gmt'.
       
   355 	 *     @type string       $order               How to order retrieved comments. Accepts 'ASC', 'DESC'.
       
   356 	 *                                             Default: 'DESC'.
       
   357 	 *     @type int          $parent              Parent ID of comment to retrieve children of. Default empty.
       
   358 	 *     @type array        $post_author__in     Array of author IDs to retrieve comments for. Default empty.
       
   359 	 *     @type array        $post_author__not_in Array of author IDs *not* to retrieve comments for. Default empty.
       
   360 	 *     @type int          $post_ID             Currently unused.
       
   361 	 *     @type int          $post_id             Limit results to those affiliated with a given post ID. Default 0.
       
   362 	 *     @type array        $post__in            Array of post IDs to include affiliated comments for. Default empty.
       
   363 	 *     @type array        $post__not_in        Array of post IDs to exclude affiliated comments for. Default empty.
       
   364 	 *     @type int          $post_author         Comment author ID to limit results by. Default empty.
       
   365 	 *     @type string       $post_status         Post status to retrieve affiliated comments for. Default empty.
       
   366 	 *     @type string       $post_type           Post type to retrieve affiliated comments for. Default empty.
       
   367 	 *     @type string       $post_name           Post name to retrieve affiliated comments for. Default empty.
       
   368 	 *     @type int          $post_parent         Post parent ID to retrieve affiliated comments for. Default empty.
       
   369 	 *     @type string       $search              Search term(s) to retrieve matching comments for. Default empty.
       
   370 	 *     @type string       $status              Comment status to limit results by. Accepts 'hold'
       
   371 	 *                                             (`comment_status=0`), 'approve' (`comment_status=1`), 'all', or a
       
   372 	 *                                             custom comment status. Default 'all'.
       
   373 	 *     @type string|array $type                Include comments of a given type, or array of types. Accepts
       
   374 	 *                                             'comment', 'pings' (includes 'pingback' and 'trackback'), or any
       
   375 	 *                                             custom type string. Default empty.
       
   376 	 *     @type array        $type__in            Include comments from a given array of comment types. Default empty.
       
   377 	 *     @type array        $type__not_in        Exclude comments from a given array of comment types. Default empty.
       
   378 	 *     @type int          $user_id             Include comments for a specific user ID. Default empty.
       
   379 	 * }
       
   380 	 * @return WP_Comment_Query WP_Comment_Query instance.
       
   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 List of comments.
       
   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 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 		if ( ! empty( $this->meta_query->queries ) ) {
       
   486 			$meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
       
   487 		}
       
   488 
       
   489 		/**
       
   490 		 * Fires before comments are retrieved.
       
   491 		 *
       
   492 		 * @since 3.1.0
       
   493 		 *
       
   494 		 * @param WP_Comment_Query &$this Current instance of WP_Comment_Query, passed by reference.
       
   495 		 */
       
   496 		do_action_ref_array( 'pre_get_comments', array( &$this ) );
       
   497 
       
   498 		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
       
   499 		$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
       
   500 		$last_changed = wp_cache_get( 'last_changed', 'comment' );
       
   501 		if ( ! $last_changed ) {
       
   502 			$last_changed = microtime();
       
   503 			wp_cache_set( 'last_changed', $last_changed, 'comment' );
       
   504 		}
       
   505 		$cache_key = "get_comments:$key:$last_changed";
       
   506 
       
   507 		if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
       
   508 			$this->comments = $cache;
       
   509 			return $this->comments;
       
   510 		}
       
   511 
       
   512 		$where = array();
       
   513 
       
   514 		// Assemble clauses related to 'comment_approved'.
       
   515 		$approved_clauses = array();
       
   516 
       
   517 		// 'status' accepts an array or a comma-separated string.
       
   518 		$status_clauses = array();
       
   519 		$statuses = $this->query_vars['status'];
       
   520 		if ( ! is_array( $statuses ) ) {
       
   521 			$statuses = preg_split( '/[\s,]+/', $statuses );
       
   522 		}
       
   523 
       
   524 		// 'any' overrides other statuses.
       
   525 		if ( ! in_array( 'any', $statuses ) ) {
       
   526 			foreach ( $statuses as $status ) {
       
   527 				switch ( $status ) {
       
   528 					case 'hold' :
       
   529 						$status_clauses[] = "comment_approved = '0'";
       
   530 						break;
       
   531 
       
   532 					case 'approve' :
       
   533 						$status_clauses[] = "comment_approved = '1'";
       
   534 						break;
       
   535 
       
   536 					case 'all' :
       
   537 					case '' :
       
   538 						$status_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )";
       
   539 						break;
       
   540 
       
   541 					default :
       
   542 						$status_clauses[] = $wpdb->prepare( "comment_approved = %s", $status );
       
   543 						break;
       
   544 				}
       
   545 			}
       
   546 
       
   547 			if ( ! empty( $status_clauses ) ) {
       
   548 				$approved_clauses[] = '( ' . implode( ' OR ', $status_clauses ) . ' )';
       
   549 			}
       
   550 		}
       
   551 
       
   552 		// User IDs or emails whose unapproved comments are included, regardless of $status.
       
   553 		if ( ! empty( $this->query_vars['include_unapproved'] ) ) {
       
   554 			$include_unapproved = $this->query_vars['include_unapproved'];
       
   555 
       
   556 			// Accepts arrays or comma-separated strings.
       
   557 			if ( ! is_array( $include_unapproved ) ) {
       
   558 				$include_unapproved = preg_split( '/[\s,]+/', $include_unapproved );
       
   559 			}
       
   560 
       
   561 			$unapproved_ids = $unapproved_emails = array();
       
   562 			foreach ( $include_unapproved as $unapproved_identifier ) {
       
   563 				// Numeric values are assumed to be user ids.
       
   564 				if ( is_numeric( $unapproved_identifier ) ) {
       
   565 					$approved_clauses[] = $wpdb->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier );
       
   566 
       
   567 				// Otherwise we match against email addresses.
       
   568 				} else {
       
   569 					$approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier );
       
   570 				}
       
   571 			}
       
   572 		}
       
   573 
       
   574 		// Collapse comment_approved clauses into a single OR-separated clause.
       
   575 		if ( ! empty( $approved_clauses ) ) {
       
   576 			if ( 1 === count( $approved_clauses ) ) {
       
   577 				$where[] = $approved_clauses[0];
       
   578 			} else {
       
   579 				$where[] = '( ' . implode( ' OR ', $approved_clauses ) . ' )';
       
   580 			}
       
   581 		}
       
   582 
       
   583 		$order = ( 'ASC' == strtoupper( $this->query_vars['order'] ) ) ? 'ASC' : 'DESC';
       
   584 
       
   585 		// Disable ORDER BY with 'none', an empty array, or boolean false.
       
   586 		if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
       
   587 			$orderby = '';
       
   588 		} elseif ( ! empty( $this->query_vars['orderby'] ) ) {
       
   589 			$ordersby = is_array( $this->query_vars['orderby'] ) ?
       
   590 				$this->query_vars['orderby'] :
       
   591 				preg_split( '/[,\s]/', $this->query_vars['orderby'] );
       
   592 
       
   593 			$orderby_array = array();
       
   594 			$found_orderby_comment_ID = false;
       
   595 			foreach ( $ordersby as $_key => $_value ) {
       
   596 				if ( ! $_value ) {
       
   597 					continue;
       
   598 				}
       
   599 
       
   600 				if ( is_int( $_key ) ) {
       
   601 					$_orderby = $_value;
       
   602 					$_order = $order;
       
   603 				} else {
       
   604 					$_orderby = $_key;
       
   605 					$_order = $_value;
       
   606 				}
       
   607 
       
   608 				if ( ! $found_orderby_comment_ID && 'comment_ID' === $_orderby ) {
       
   609 					$found_orderby_comment_ID = true;
       
   610 				}
       
   611 
       
   612 				$parsed = $this->parse_orderby( $_orderby );
       
   613 
       
   614 				if ( ! $parsed ) {
       
   615 					continue;
       
   616 				}
       
   617 
       
   618 				$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
       
   619 			}
       
   620 
       
   621 			// If no valid clauses were found, order by comment_date_gmt.
       
   622 			if ( empty( $orderby_array ) ) {
       
   623 				$orderby_array[] = "$wpdb->comments.comment_date_gmt $order";
       
   624 			}
       
   625 
       
   626 			// To ensure determinate sorting, always include a comment_ID clause.
       
   627 			if ( ! $found_orderby_comment_ID ) {
       
   628 				$comment_ID_order = '';
       
   629 
       
   630 				// Inherit order from comment_date or comment_date_gmt, if available.
       
   631 				foreach ( $orderby_array as $orderby_clause ) {
       
   632 					if ( preg_match( '/comment_date(?:_gmt)*\ (ASC|DESC)/', $orderby_clause, $match ) ) {
       
   633 						$comment_ID_order = $match[1];
       
   634 						break;
       
   635 					}
       
   636 				}
       
   637 
       
   638 				// If no date-related order is available, use the date from the first available clause.
       
   639 				if ( ! $comment_ID_order ) {
       
   640 					foreach ( $orderby_array as $orderby_clause ) {
       
   641 						if ( false !== strpos( 'ASC', $orderby_clause ) ) {
       
   642 							$comment_ID_order = 'ASC';
       
   643 						} else {
       
   644 							$comment_ID_order = 'DESC';
       
   645 						}
       
   646 
       
   647 						break;
       
   648 					}
       
   649 				}
       
   650 
       
   651 				// Default to DESC.
       
   652 				if ( ! $comment_ID_order ) {
       
   653 					$comment_ID_order = 'DESC';
       
   654 				}
       
   655 
       
   656 				$orderby_array[] = "$wpdb->comments.comment_ID $comment_ID_order";
       
   657 			}
       
   658 
       
   659 			$orderby = implode( ', ', $orderby_array );
       
   660 		} else {
       
   661 			$orderby = "$wpdb->comments.comment_date_gmt $order";
       
   662 		}
       
   663 
       
   664 		$number = absint( $this->query_vars['number'] );
       
   665 		$offset = absint( $this->query_vars['offset'] );
       
   666 
       
   667 		if ( ! empty( $number ) ) {
       
   668 			if ( $offset ) {
       
   669 				$limits = 'LIMIT ' . $offset . ',' . $number;
       
   670 			} else {
       
   671 				$limits = 'LIMIT ' . $number;
       
   672 			}
       
   673 		} else {
       
   674 			$limits = '';
       
   675 		}
       
   676 
       
   677 		if ( $this->query_vars['count'] ) {
       
   678 			$fields = 'COUNT(*)';
       
   679 		} else {
       
   680 			switch ( strtolower( $this->query_vars['fields'] ) ) {
       
   681 				case 'ids':
       
   682 					$fields = "$wpdb->comments.comment_ID";
       
   683 					break;
       
   684 				default:
       
   685 					$fields = "*";
       
   686 					break;
       
   687 			}
       
   688 		}
       
   689 
       
   690 		$join = '';
       
   691 
       
   692 		$post_id = absint( $this->query_vars['post_id'] );
       
   693 		if ( ! empty( $post_id ) ) {
       
   694 			$where[] = $wpdb->prepare( 'comment_post_ID = %d', $post_id );
       
   695 		}
       
   696 
       
   697 		// Parse comment IDs for an IN clause.
       
   698 		if ( ! empty( $this->query_vars['comment__in'] ) ) {
       
   699 			$where[] = 'comment_ID IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['comment__in'] ) ) . ' )';
       
   700 		}
       
   701 
       
   702 		// Parse comment IDs for a NOT IN clause.
       
   703 		if ( ! empty( $this->query_vars['comment__not_in'] ) ) {
       
   704 			$where[] = 'comment_ID NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['comment__not_in'] ) ) . ' )';
       
   705 		}
       
   706 
       
   707 		// Parse comment post IDs for an IN clause.
       
   708 		if ( ! empty( $this->query_vars['post__in'] ) ) {
       
   709 			$where[] = 'comment_post_ID IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post__in'] ) ) . ' )';
       
   710 		}
       
   711 
       
   712 		// Parse comment post IDs for a NOT IN clause.
       
   713 		if ( ! empty( $this->query_vars['post__not_in'] ) ) {
       
   714 			$where[] = 'comment_post_ID NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post__not_in'] ) ) . ' )';
       
   715 		}
       
   716 
       
   717 		if ( '' !== $this->query_vars['author_email'] ) {
       
   718 			$where[] = $wpdb->prepare( 'comment_author_email = %s', $this->query_vars['author_email'] );
       
   719 		}
       
   720 
       
   721 		if ( '' !== $this->query_vars['karma'] ) {
       
   722 			$where[] = $wpdb->prepare( 'comment_karma = %d', $this->query_vars['karma'] );
       
   723 		}
       
   724 
       
   725 		// Filtering by comment_type: 'type', 'type__in', 'type__not_in'.
       
   726 		$raw_types = array(
       
   727 			'IN' => array_merge( (array) $this->query_vars['type'], (array) $this->query_vars['type__in'] ),
       
   728 			'NOT IN' => (array) $this->query_vars['type__not_in'],
       
   729 		);
       
   730 
       
   731 		$comment_types = array();
       
   732 		foreach ( $raw_types as $operator => $_raw_types ) {
       
   733 			$_raw_types = array_unique( $_raw_types );
       
   734 
       
   735 			foreach ( $_raw_types as $type ) {
       
   736 				switch ( $type ) {
       
   737 					// An empty translates to 'all', for backward compatibility
       
   738 					case '':
       
   739 					case 'all' :
       
   740 						break;
       
   741 
       
   742 					case 'comment':
       
   743 					case 'comments':
       
   744 						$comment_types[ $operator ][] = "''";
       
   745 						break;
       
   746 
       
   747 					case 'pings':
       
   748 						$comment_types[ $operator ][] = "'pingback'";
       
   749 						$comment_types[ $operator ][] = "'trackback'";
       
   750 						break;
       
   751 
       
   752 					default:
       
   753 						$comment_types[ $operator ][] = $wpdb->prepare( '%s', $type );
       
   754 						break;
       
   755 				}
       
   756 			}
       
   757 
       
   758 			if ( ! empty( $comment_types[ $operator ] ) ) {
       
   759 				$types_sql = implode( ', ', $comment_types[ $operator ] );
       
   760 				$where[] = "comment_type $operator ($types_sql)";
       
   761 			}
       
   762 		}
       
   763 
       
   764 		if ( '' !== $this->query_vars['parent'] ) {
       
   765 			$where[] = $wpdb->prepare( 'comment_parent = %d', $this->query_vars['parent'] );
       
   766 		}
       
   767 
       
   768 		if ( is_array( $this->query_vars['user_id'] ) ) {
       
   769 			$where[] = 'user_id IN (' . implode( ',', array_map( 'absint', $this->query_vars['user_id'] ) ) . ')';
       
   770 		} elseif ( '' !== $this->query_vars['user_id'] ) {
       
   771 			$where[] = $wpdb->prepare( 'user_id = %d', $this->query_vars['user_id'] );
       
   772 		}
       
   773 
       
   774 		if ( '' !== $this->query_vars['search'] ) {
       
   775 			$search_sql = $this->get_search_sql(
       
   776 				$this->query_vars['search'],
       
   777 				array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_content' )
       
   778 			);
       
   779 
       
   780 			// Strip leading 'AND'.
       
   781 			$where[] = preg_replace( '/^\s*AND\s*/', '', $search_sql );
       
   782 		}
       
   783 
       
   784 		// If any post-related query vars are passed, join the posts table.
       
   785 		$join_posts_table = false;
       
   786 		$plucked = wp_array_slice_assoc( $this->query_vars, array( 'post_author', 'post_name', 'post_parent', 'post_status', 'post_type' ) );
       
   787 		$post_fields = array_filter( $plucked );
       
   788 
       
   789 		if ( ! empty( $post_fields ) ) {
       
   790 			$join_posts_table = true;
       
   791 			foreach ( $post_fields as $field_name => $field_value ) {
       
   792 				// $field_value may be an array.
       
   793 				$esses = array_fill( 0, count( (array) $field_value ), '%s' );
       
   794 				$where[] = $wpdb->prepare( " {$wpdb->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $field_value );
       
   795 			}
       
   796 		}
       
   797 
       
   798 		// Comment author IDs for an IN clause.
       
   799 		if ( ! empty( $this->query_vars['author__in'] ) ) {
       
   800 			$where[] = 'user_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['author__in'] ) ) . ' )';
       
   801 		}
       
   802 
       
   803 		// Comment author IDs for a NOT IN clause.
       
   804 		if ( ! empty( $this->query_vars['author__not_in'] ) ) {
       
   805 			$where[] = 'user_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['author__not_in'] ) ) . ' )';
       
   806 		}
       
   807 
       
   808 		// Post author IDs for an IN clause.
       
   809 		if ( ! empty( $this->query_vars['post_author__in'] ) ) {
       
   810 			$join_posts_table = true;
       
   811 			$where[] = 'post_author IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post_author__in'] ) ) . ' )';
       
   812 		}
       
   813 
       
   814 		// Post author IDs for a NOT IN clause.
       
   815 		if ( ! empty( $this->query_vars['post_author__not_in'] ) ) {
       
   816 			$join_posts_table = true;
       
   817 			$where[] = 'post_author NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['post_author__not_in'] ) ) . ' )';
       
   818 		}
       
   819 
       
   820 		if ( $join_posts_table ) {
       
   821 			$join = "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
       
   822 		}
       
   823 
       
   824 		if ( ! empty( $meta_query_clauses ) ) {
       
   825 			$join .= $meta_query_clauses['join'];
       
   826 
       
   827 			// Strip leading 'AND'.
       
   828 			$where[] = preg_replace( '/^\s*AND\s*/', '', $meta_query_clauses['where'] );
       
   829 
       
   830 			if ( ! $this->query_vars['count'] ) {
       
   831 				$groupby = "{$wpdb->comments}.comment_ID";
       
   832 			}
       
   833 		}
       
   834 
       
   835 		$date_query = $this->query_vars['date_query'];
       
   836 		if ( ! empty( $date_query ) && is_array( $date_query ) ) {
       
   837 			$date_query_object = new WP_Date_Query( $date_query, 'comment_date' );
       
   838 			$where[] = preg_replace( '/^\s*AND\s*/', '', $date_query_object->get_sql() );
       
   839 		}
       
   840 
       
   841 		$where = implode( ' AND ', $where );
       
   842 
       
   843 		$pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
       
   844 		/**
       
   845 		 * Filter the comment query clauses.
       
   846 		 *
       
   847 		 * @since 3.1.0
       
   848 		 *
       
   849 		 * @param array            $pieces A compacted array of comment query clauses.
       
   850 		 * @param WP_Comment_Query &$this  Current instance of WP_Comment_Query, passed by reference.
       
   851 		 */
       
   852 		$clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
       
   853 
       
   854 		$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
       
   855 		$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
       
   856 		$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
       
   857 		$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
       
   858 		$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
       
   859 		$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
       
   860 
       
   861 		if ( $where ) {
       
   862 			$where = 'WHERE ' . $where;
       
   863 		}
       
   864 
       
   865 		if ( $groupby ) {
       
   866 			$groupby = 'GROUP BY ' . $groupby;
       
   867 		}
       
   868 
       
   869 		if ( $orderby ) {
       
   870 			$orderby = "ORDER BY $orderby";
       
   871 		}
       
   872 
       
   873 		$this->request = "SELECT $fields FROM $wpdb->comments $join $where $groupby $orderby $limits";
       
   874 
       
   875 		if ( $this->query_vars['count'] ) {
       
   876 			return $wpdb->get_var( $this->request );
       
   877 		}
       
   878 
       
   879 		if ( 'ids' == $this->query_vars['fields'] ) {
       
   880 			$this->comments = $wpdb->get_col( $this->request );
       
   881 			return array_map( 'intval', $this->comments );
       
   882 		}
       
   883 
       
   884 		$results = $wpdb->get_results( $this->request );
       
   885 		/**
       
   886 		 * Filter the comment query results.
       
   887 		 *
       
   888 		 * @since 3.1.0
       
   889 		 *
       
   890 		 * @param array            $results  An array of comments.
       
   891 		 * @param WP_Comment_Query &$this    Current instance of WP_Comment_Query, passed by reference.
       
   892 		 */
       
   893 		$comments = apply_filters_ref_array( 'the_comments', array( $results, &$this ) );
       
   894 
       
   895 		wp_cache_add( $cache_key, $comments, 'comment' );
       
   896 
       
   897 		$this->comments = $comments;
       
   898 		return $this->comments;
       
   899 	}
       
   900 
       
   901 	/**
       
   902 	 * Used internally to generate an SQL string for searching across multiple columns
       
   903 	 *
       
   904 	 * @access protected
       
   905 	 * @since 3.1.0
       
   906 	 *
       
   907 	 * @param string $string
       
   908 	 * @param array $cols
       
   909 	 * @return string
       
   910 	 */
       
   911 	protected function get_search_sql( $string, $cols ) {
       
   912 		global $wpdb;
       
   913 
       
   914 		$like = '%' . $wpdb->esc_like( $string ) . '%';
       
   915 
       
   916 		$searches = array();
       
   917 		foreach ( $cols as $col ) {
       
   918 			$searches[] = $wpdb->prepare( "$col LIKE %s", $like );
       
   919 		}
       
   920 
       
   921 		return ' AND (' . implode(' OR ', $searches) . ')';
       
   922 	}
       
   923 
       
   924 	/**
       
   925 	 * Parse and sanitize 'orderby' keys passed to the comment query.
       
   926 	 *
       
   927 	 * @since 4.2.0
       
   928 	 * @access protected
       
   929 	 *
       
   930 	 * @global wpdb $wpdb WordPress database abstraction object.
       
   931 	 *
       
   932 	 * @param string $orderby Alias for the field to order by.
       
   933 	 * @return string|bool Value to used in the ORDER clause. False otherwise.
       
   934 	 */
       
   935 	protected function parse_orderby( $orderby ) {
       
   936 		global $wpdb;
       
   937 
       
   938 		$allowed_keys = array(
       
   939 			'comment_agent',
       
   940 			'comment_approved',
       
   941 			'comment_author',
       
   942 			'comment_author_email',
       
   943 			'comment_author_IP',
       
   944 			'comment_author_url',
       
   945 			'comment_content',
       
   946 			'comment_date',
       
   947 			'comment_date_gmt',
       
   948 			'comment_ID',
       
   949 			'comment_karma',
       
   950 			'comment_parent',
       
   951 			'comment_post_ID',
       
   952 			'comment_type',
       
   953 			'user_id',
       
   954 		);
       
   955 
       
   956 		if ( ! empty( $this->query_vars['meta_key'] ) ) {
       
   957 			$allowed_keys[] = $this->query_vars['meta_key'];
       
   958 			$allowed_keys[] = 'meta_value';
       
   959 			$allowed_keys[] = 'meta_value_num';
       
   960 		}
       
   961 
       
   962 		$meta_query_clauses = $this->meta_query->get_clauses();
       
   963 		if ( $meta_query_clauses ) {
       
   964 			$allowed_keys = array_merge( $allowed_keys, array_keys( $meta_query_clauses ) );
       
   965 		}
       
   966 
       
   967 		$parsed = false;
       
   968 		if ( $orderby == $this->query_vars['meta_key'] || $orderby == 'meta_value' ) {
       
   969 			$parsed = "$wpdb->commentmeta.meta_value";
       
   970 		} else if ( $orderby == 'meta_value_num' ) {
       
   971 			$parsed = "$wpdb->commentmeta.meta_value+0";
       
   972 		} else if ( in_array( $orderby, $allowed_keys ) ) {
       
   973 
       
   974 			if ( isset( $meta_query_clauses[ $orderby ] ) ) {
       
   975 				$meta_clause = $meta_query_clauses[ $orderby ];
       
   976 				$parsed = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
       
   977 			} else {
       
   978 				$parsed = "$wpdb->comments.$orderby";
       
   979 			}
       
   980 		}
       
   981 
       
   982 		return $parsed;
       
   983 	}
       
   984 
       
   985 	/**
       
   986 	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
       
   987 	 *
       
   988 	 * @since 4.2.0
       
   989 	 * @access protected
       
   990 	 *
       
   991 	 * @param string $order The 'order' query variable.
       
   992 	 * @return string The sanitized 'order' query variable.
       
   993 	 */
       
   994 	protected function parse_order( $order ) {
       
   995 		if ( ! is_string( $order ) || empty( $order ) ) {
       
   996 			return 'DESC';
       
   997 		}
       
   998 
       
   999 		if ( 'ASC' === strtoupper( $order ) ) {
       
  1000 			return 'ASC';
       
  1001 		} else {
       
  1002 			return 'DESC';
       
  1003 		}
       
  1004 	}
       
  1005 }
       
  1006 
       
  1007 /**
       
  1008  * Retrieve all of the WordPress supported comment statuses.
   230  * Retrieve all of the WordPress supported comment statuses.
  1009  *
   231  *
  1010  * Comments have a limited set of valid status values, this provides the comment
   232  * Comments have a limited set of valid status values, this provides the comment
  1011  * status values and descriptions.
   233  * status values and descriptions.
  1012  *
   234  *
  1014  *
   236  *
  1015  * @return array List of comment statuses.
   237  * @return array List of comment statuses.
  1016  */
   238  */
  1017 function get_comment_statuses() {
   239 function get_comment_statuses() {
  1018 	$status = array(
   240 	$status = array(
  1019 		'hold'		=> __('Unapproved'),
   241 		'hold'		=> __( 'Unapproved' ),
  1020 		/* translators: comment status  */
   242 		'approve'	=> _x( 'Approved', 'comment status' ),
  1021 		'approve'	=> _x('Approved', 'adjective'),
   243 		'spam'		=> _x( 'Spam', 'comment status' ),
  1022 		/* translators: comment status */
   244 		'trash'		=> _x( 'Trash', 'comment status' ),
  1023 		'spam'		=> _x('Spam', 'adjective'),
       
  1024 	);
   245 	);
  1025 
   246 
  1026 	return $status;
   247 	return $status;
  1027 }
   248 }
  1028 
   249 
  1029 /**
   250 /**
       
   251  * Gets the default comment status for a post type.
       
   252  *
       
   253  * @since 4.3.0
       
   254  *
       
   255  * @param string $post_type    Optional. Post type. Default 'post'.
       
   256  * @param string $comment_type Optional. Comment type. Default 'comment'.
       
   257  * @return string Expected return value is 'open' or 'closed'.
       
   258  */
       
   259 function get_default_comment_status( $post_type = 'post', $comment_type = 'comment' ) {
       
   260 	switch ( $comment_type ) {
       
   261 		case 'pingback' :
       
   262 		case 'trackback' :
       
   263 			$supports = 'trackbacks';
       
   264 			$option = 'ping';
       
   265 			break;
       
   266 		default :
       
   267 			$supports = 'comments';
       
   268 			$option = 'comment';
       
   269 	}
       
   270 
       
   271 	// Set the status.
       
   272 	if ( 'page' === $post_type ) {
       
   273 		$status = 'closed';
       
   274 	} elseif ( post_type_supports( $post_type, $supports ) ) {
       
   275 		$status = get_option( "default_{$option}_status" );
       
   276 	} else {
       
   277 		$status = 'closed';
       
   278 	}
       
   279 
       
   280 	/**
       
   281 	 * Filters the default comment status for the given post type.
       
   282 	 *
       
   283 	 * @since 4.3.0
       
   284 	 *
       
   285 	 * @param string $status       Default status for the given post type,
       
   286 	 *                             either 'open' or 'closed'.
       
   287 	 * @param string $post_type    Post type. Default is `post`.
       
   288 	 * @param string $comment_type Type of comment. Default is `comment`.
       
   289 	 */
       
   290 	return apply_filters( 'get_default_comment_status' , $status, $post_type, $comment_type );
       
   291 }
       
   292 
       
   293 /**
  1030  * The date the last comment was modified.
   294  * The date the last comment was modified.
  1031  *
   295  *
  1032  * @since 1.5.0
   296  * @since 1.5.0
       
   297  * @since 4.7.0 Replaced caching the modified date in a local static variable
       
   298  *              with the Object Cache API.
  1033  *
   299  *
  1034  * @global wpdb $wpdb WordPress database abstraction object.
   300  * @global wpdb $wpdb WordPress database abstraction object.
  1035  *
   301  *
  1036  * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
   302  * @param string $timezone Which timezone to use in reference to 'gmt', 'blog', or 'server' locations.
  1037  *		or 'server' locations.
   303  * @return string|false Last comment modified date on success, false on failure.
  1038  * @return string Last comment modified date.
   304  */
  1039  */
   305 function get_lastcommentmodified( $timezone = 'server' ) {
  1040 function get_lastcommentmodified($timezone = 'server') {
       
  1041 	global $wpdb;
   306 	global $wpdb;
  1042 	static $cache_lastcommentmodified = array();
   307 
  1043 
   308 	$timezone = strtolower( $timezone );
  1044 	if ( isset($cache_lastcommentmodified[$timezone]) )
   309 	$key = "lastcommentmodified:$timezone";
  1045 		return $cache_lastcommentmodified[$timezone];
   310 
  1046 
   311 	$comment_modified_date = wp_cache_get( $key, 'timeinfo' );
  1047 	$add_seconds_server = date('Z');
   312 	if ( false !== $comment_modified_date ) {
  1048 
   313 		return $comment_modified_date;
  1049 	switch ( strtolower($timezone)) {
   314 	}
       
   315 
       
   316 	switch ( $timezone ) {
  1050 		case 'gmt':
   317 		case 'gmt':
  1051 			$lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
   318 			$comment_modified_date = $wpdb->get_var( "SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
  1052 			break;
   319 			break;
  1053 		case 'blog':
   320 		case 'blog':
  1054 			$lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
   321 			$comment_modified_date = $wpdb->get_var( "SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
  1055 			break;
   322 			break;
  1056 		case 'server':
   323 		case 'server':
  1057 			$lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
   324 			$add_seconds_server = date( 'Z' );
       
   325 
       
   326 			$comment_modified_date = $wpdb->get_var( $wpdb->prepare( "SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server ) );
  1058 			break;
   327 			break;
  1059 	}
   328 	}
  1060 
   329 
  1061 	$cache_lastcommentmodified[$timezone] = $lastcommentmodified;
   330 	if ( $comment_modified_date ) {
  1062 
   331 		wp_cache_set( $key, $comment_modified_date, 'timeinfo' );
  1063 	return $lastcommentmodified;
   332 
       
   333 		return $comment_modified_date;
       
   334 	}
       
   335 
       
   336 	return false;
  1064 }
   337 }
  1065 
   338 
  1066 /**
   339 /**
  1067  * The amount of comments in a post or total comments.
   340  * The amount of comments in a post or total comments.
  1068  *
   341  *
  1069  * A lot like {@link wp_count_comments()}, in that they both return comment
   342  * A lot like wp_count_comments(), in that they both return comment stats (albeit with different types).
  1070  * stats (albeit with different types). The {@link wp_count_comments()} actual
   343  * The wp_count_comments() actually caches, but this function does not.
  1071  * caches, but this function does not.
       
  1072  *
   344  *
  1073  * @since 2.0.0
   345  * @since 2.0.0
  1074  *
   346  *
  1075  * @global wpdb $wpdb WordPress database abstraction object.
   347  * @global wpdb $wpdb WordPress database abstraction object.
  1076  *
   348  *
  1093 		{$where}
   365 		{$where}
  1094 		GROUP BY comment_approved
   366 		GROUP BY comment_approved
  1095 	", ARRAY_A);
   367 	", ARRAY_A);
  1096 
   368 
  1097 	$comment_count = array(
   369 	$comment_count = array(
  1098 		"approved"              => 0,
   370 		'approved'            => 0,
  1099 		"awaiting_moderation"   => 0,
   371 		'awaiting_moderation' => 0,
  1100 		"spam"                  => 0,
   372 		'spam'                => 0,
  1101 		"total_comments"        => 0
   373 		'trash'               => 0,
       
   374 		'post-trashed'        => 0,
       
   375 		'total_comments'      => 0,
       
   376 		'all'                 => 0,
  1102 	);
   377 	);
  1103 
   378 
  1104 	foreach ( $totals as $row ) {
   379 	foreach ( $totals as $row ) {
  1105 		switch ( $row['comment_approved'] ) {
   380 		switch ( $row['comment_approved'] ) {
       
   381 			case 'trash':
       
   382 				$comment_count['trash'] = $row['total'];
       
   383 				break;
       
   384 			case 'post-trashed':
       
   385 				$comment_count['post-trashed'] = $row['total'];
       
   386 				break;
  1106 			case 'spam':
   387 			case 'spam':
  1107 				$comment_count['spam'] = $row['total'];
   388 				$comment_count['spam'] = $row['total'];
  1108 				$comment_count["total_comments"] += $row['total'];
   389 				$comment_count['total_comments'] += $row['total'];
  1109 				break;
   390 				break;
  1110 			case 1:
   391 			case '1':
  1111 				$comment_count['approved'] = $row['total'];
   392 				$comment_count['approved'] = $row['total'];
  1112 				$comment_count['total_comments'] += $row['total'];
   393 				$comment_count['total_comments'] += $row['total'];
       
   394 				$comment_count['all'] += $row['total'];
  1113 				break;
   395 				break;
  1114 			case 0:
   396 			case '0':
  1115 				$comment_count['awaiting_moderation'] = $row['total'];
   397 				$comment_count['awaiting_moderation'] = $row['total'];
  1116 				$comment_count['total_comments'] += $row['total'];
   398 				$comment_count['total_comments'] += $row['total'];
       
   399 				$comment_count['all'] += $row['total'];
  1117 				break;
   400 				break;
  1118 			default:
   401 			default:
  1119 				break;
   402 				break;
  1120 		}
   403 		}
  1121 	}
   404 	}
  1138  * @param mixed $meta_value Metadata value.
   421  * @param mixed $meta_value Metadata value.
  1139  * @param bool $unique Optional, default is false. Whether the same key should not be added.
   422  * @param bool $unique Optional, default is false. Whether the same key should not be added.
  1140  * @return int|bool Meta ID on success, false on failure.
   423  * @return int|bool Meta ID on success, false on failure.
  1141  */
   424  */
  1142 function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
   425 function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
  1143 	return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
   426 	$added = add_metadata( 'comment', $comment_id, $meta_key, $meta_value, $unique );
       
   427 	if ( $added ) {
       
   428 		wp_cache_set( 'last_changed', microtime(), 'comment' );
       
   429 	}
       
   430 	return $added;
  1144 }
   431 }
  1145 
   432 
  1146 /**
   433 /**
  1147  * Remove metadata matching criteria from a comment.
   434  * Remove metadata matching criteria from a comment.
  1148  *
   435  *
  1157  * @param string $meta_key Metadata name.
   444  * @param string $meta_key Metadata name.
  1158  * @param mixed $meta_value Optional. Metadata value.
   445  * @param mixed $meta_value Optional. Metadata value.
  1159  * @return bool True on success, false on failure.
   446  * @return bool True on success, false on failure.
  1160  */
   447  */
  1161 function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
   448 function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
  1162 	return delete_metadata('comment', $comment_id, $meta_key, $meta_value);
   449 	$deleted = delete_metadata( 'comment', $comment_id, $meta_key, $meta_value );
       
   450 	if ( $deleted ) {
       
   451 		wp_cache_set( 'last_changed', microtime(), 'comment' );
       
   452 	}
       
   453 	return $deleted;
  1163 }
   454 }
  1164 
   455 
  1165 /**
   456 /**
  1166  * Retrieve comment meta field for a comment.
   457  * Retrieve comment meta field for a comment.
  1167  *
   458  *
  1194  * @param mixed $meta_value Metadata value.
   485  * @param mixed $meta_value Metadata value.
  1195  * @param mixed $prev_value Optional. Previous value to check before removing.
   486  * @param mixed $prev_value Optional. Previous value to check before removing.
  1196  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
   487  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
  1197  */
   488  */
  1198 function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
   489 function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
  1199 	return update_metadata('comment', $comment_id, $meta_key, $meta_value, $prev_value);
   490 	$updated = update_metadata( 'comment', $comment_id, $meta_key, $meta_value, $prev_value );
       
   491 	if ( $updated ) {
       
   492 		wp_cache_set( 'last_changed', microtime(), 'comment' );
       
   493 	}
       
   494 	return $updated;
       
   495 }
       
   496 
       
   497 /**
       
   498  * Queues comments for metadata lazy-loading.
       
   499  *
       
   500  * @since 4.5.0
       
   501  *
       
   502  * @param array $comments Array of comment objects.
       
   503  */
       
   504 function wp_queue_comments_for_comment_meta_lazyload( $comments ) {
       
   505 	// Don't use `wp_list_pluck()` to avoid by-reference manipulation.
       
   506 	$comment_ids = array();
       
   507 	if ( is_array( $comments ) ) {
       
   508 		foreach ( $comments as $comment ) {
       
   509 			if ( $comment instanceof WP_Comment ) {
       
   510 				$comment_ids[] = $comment->comment_ID;
       
   511 			}
       
   512 		}
       
   513 	}
       
   514 
       
   515 	if ( $comment_ids ) {
       
   516 		$lazyloader = wp_metadata_lazyloader();
       
   517 		$lazyloader->queue_objects( 'comment', $comment_ids );
       
   518 	}
  1200 }
   519 }
  1201 
   520 
  1202 /**
   521 /**
  1203  * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
   522  * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
  1204  * to recall previous comments by this commentator that are still held in moderation.
   523  * to recall previous comments by this commentator that are still held in moderation.
  1205  *
   524  *
  1206  * @param object $comment Comment object.
       
  1207  * @param object $user Comment author's object.
       
  1208  *
       
  1209  * @since 3.4.0
   525  * @since 3.4.0
  1210  */
   526  * @since 4.9.6 The `$cookies_consent` parameter was added.
  1211 function wp_set_comment_cookies($comment, $user) {
   527  *
  1212 	if ( $user->exists() )
   528  * @param WP_Comment $comment         Comment object.
       
   529  * @param WP_User    $user            Comment author's user object. The user may not exist.
       
   530  * @param boolean    $cookies_consent Optional. Comment author's consent to store cookies. Default true.
       
   531  */
       
   532 function wp_set_comment_cookies( $comment, $user, $cookies_consent = true ) {
       
   533 	// If the user already exists, or the user opted out of cookies, don't set cookies.
       
   534 	if ( $user->exists() ) {
  1213 		return;
   535 		return;
       
   536 	}
       
   537 
       
   538 	if ( false === $cookies_consent ) {
       
   539 		// Remove any existing cookies.
       
   540 		$past = time() - YEAR_IN_SECONDS;
       
   541 		setcookie( 'comment_author_' . COOKIEHASH, ' ', $past, COOKIEPATH, COOKIE_DOMAIN );
       
   542 		setcookie( 'comment_author_email_' . COOKIEHASH, ' ', $past, COOKIEPATH, COOKIE_DOMAIN );
       
   543 		setcookie( 'comment_author_url_' . COOKIEHASH, ' ', $past, COOKIEPATH, COOKIE_DOMAIN );
       
   544 
       
   545 		return;
       
   546 	}
  1214 
   547 
  1215 	/**
   548 	/**
  1216 	 * Filter the lifetime of the comment cookie in seconds.
   549 	 * Filters the lifetime of the comment cookie in seconds.
  1217 	 *
   550 	 *
  1218 	 * @since 2.8.0
   551 	 * @since 2.8.0
  1219 	 *
   552 	 *
  1220 	 * @param int $seconds Comment cookie lifetime. Default 30000000.
   553 	 * @param int $seconds Comment cookie lifetime. Default 30000000.
  1221 	 */
   554 	 */
  1222 	$comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
   555 	$comment_cookie_lifetime = time() + apply_filters( 'comment_cookie_lifetime', 30000000 );
  1223 	$secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
   556 	$secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
  1224 	setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   557 	setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
  1225 	setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   558 	setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
  1226 	setcookie( 'comment_author_url_' . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   559 	setcookie( 'comment_author_url_' . COOKIEHASH, esc_url( $comment->comment_author_url ), $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
  1227 }
   560 }
  1228 
   561 
  1229 /**
   562 /**
  1230  * Sanitizes the cookies sent to the user already.
   563  * Sanitizes the cookies sent to the user already.
  1231  *
   564  *
  1235  * @since 2.0.4
   568  * @since 2.0.4
  1236  */
   569  */
  1237 function sanitize_comment_cookies() {
   570 function sanitize_comment_cookies() {
  1238 	if ( isset( $_COOKIE['comment_author_' . COOKIEHASH] ) ) {
   571 	if ( isset( $_COOKIE['comment_author_' . COOKIEHASH] ) ) {
  1239 		/**
   572 		/**
  1240 		 * Filter the comment author's name cookie before it is set.
   573 		 * Filters the comment author's name cookie before it is set.
  1241 		 *
   574 		 *
  1242 		 * When this filter hook is evaluated in wp_filter_comment(),
   575 		 * When this filter hook is evaluated in wp_filter_comment(),
  1243 		 * the comment author's name string is passed.
   576 		 * the comment author's name string is passed.
  1244 		 *
   577 		 *
  1245 		 * @since 1.5.0
   578 		 * @since 1.5.0
  1252 		$_COOKIE['comment_author_' . COOKIEHASH] = $comment_author;
   585 		$_COOKIE['comment_author_' . COOKIEHASH] = $comment_author;
  1253 	}
   586 	}
  1254 
   587 
  1255 	if ( isset( $_COOKIE['comment_author_email_' . COOKIEHASH] ) ) {
   588 	if ( isset( $_COOKIE['comment_author_email_' . COOKIEHASH] ) ) {
  1256 		/**
   589 		/**
  1257 		 * Filter the comment author's email cookie before it is set.
   590 		 * Filters the comment author's email cookie before it is set.
  1258 		 *
   591 		 *
  1259 		 * When this filter hook is evaluated in wp_filter_comment(),
   592 		 * When this filter hook is evaluated in wp_filter_comment(),
  1260 		 * the comment author's email string is passed.
   593 		 * the comment author's email string is passed.
  1261 		 *
   594 		 *
  1262 		 * @since 1.5.0
   595 		 * @since 1.5.0
  1269 		$_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
   602 		$_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
  1270 	}
   603 	}
  1271 
   604 
  1272 	if ( isset( $_COOKIE['comment_author_url_' . COOKIEHASH] ) ) {
   605 	if ( isset( $_COOKIE['comment_author_url_' . COOKIEHASH] ) ) {
  1273 		/**
   606 		/**
  1274 		 * Filter the comment author's URL cookie before it is set.
   607 		 * Filters the comment author's URL cookie before it is set.
  1275 		 *
   608 		 *
  1276 		 * When this filter hook is evaluated in wp_filter_comment(),
   609 		 * When this filter hook is evaluated in wp_filter_comment(),
  1277 		 * the comment author's URL string is passed.
   610 		 * the comment author's URL string is passed.
  1278 		 *
   611 		 *
  1279 		 * @since 1.5.0
   612 		 * @since 1.5.0
  1288 
   621 
  1289 /**
   622 /**
  1290  * Validates whether this comment is allowed to be made.
   623  * Validates whether this comment is allowed to be made.
  1291  *
   624  *
  1292  * @since 2.0.0
   625  * @since 2.0.0
       
   626  * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function to
       
   627  *              return a WP_Error object instead of dying.
  1293  *
   628  *
  1294  * @global wpdb $wpdb WordPress database abstraction object.
   629  * @global wpdb $wpdb WordPress database abstraction object.
  1295  *
   630  *
  1296  * @param array $commentdata Contains information on the comment
   631  * @param array $commentdata Contains information on the comment.
  1297  * @return mixed Signifies the approval status (0|1|'spam')
   632  * @param bool  $avoid_die   When true, a disallowed comment will result in the function
  1298  */
   633  *                           returning a WP_Error object, rather than executing wp_die().
  1299 function wp_allow_comment( $commentdata ) {
   634  *                           Default false.
       
   635  * @return int|string|WP_Error Allowed comments return the approval status (0|1|'spam').
       
   636  *                             If `$avoid_die` is true, disallowed comments return a WP_Error.
       
   637  */
       
   638 function wp_allow_comment( $commentdata, $avoid_die = false ) {
  1300 	global $wpdb;
   639 	global $wpdb;
  1301 
   640 
  1302 	// Simple duplicate check
   641 	// Simple duplicate check
  1303 	// expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
   642 	// expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
  1304 	$dupe = $wpdb->prepare(
   643 	$dupe = $wpdb->prepare(
  1307 		wp_unslash( $commentdata['comment_parent'] ),
   646 		wp_unslash( $commentdata['comment_parent'] ),
  1308 		wp_unslash( $commentdata['comment_author'] )
   647 		wp_unslash( $commentdata['comment_author'] )
  1309 	);
   648 	);
  1310 	if ( $commentdata['comment_author_email'] ) {
   649 	if ( $commentdata['comment_author_email'] ) {
  1311 		$dupe .= $wpdb->prepare(
   650 		$dupe .= $wpdb->prepare(
  1312 			"OR comment_author_email = %s ",
   651 			"AND comment_author_email = %s ",
  1313 			wp_unslash( $commentdata['comment_author_email'] )
   652 			wp_unslash( $commentdata['comment_author_email'] )
  1314 		);
   653 		);
  1315 	}
   654 	}
  1316 	$dupe .= $wpdb->prepare(
   655 	$dupe .= $wpdb->prepare(
  1317 		") AND comment_content = %s LIMIT 1",
   656 		") AND comment_content = %s LIMIT 1",
  1318 		wp_unslash( $commentdata['comment_content'] )
   657 		wp_unslash( $commentdata['comment_content'] )
  1319 	);
   658 	);
  1320 	if ( $wpdb->get_var( $dupe ) ) {
   659 
       
   660 	$dupe_id = $wpdb->get_var( $dupe );
       
   661 
       
   662 	/**
       
   663 	 * Filters the ID, if any, of the duplicate comment found when creating a new comment.
       
   664 	 *
       
   665 	 * Return an empty value from this filter to allow what WP considers a duplicate comment.
       
   666 	 *
       
   667 	 * @since 4.4.0
       
   668 	 *
       
   669 	 * @param int   $dupe_id     ID of the comment identified as a duplicate.
       
   670 	 * @param array $commentdata Data for the comment being created.
       
   671 	 */
       
   672 	$dupe_id = apply_filters( 'duplicate_comment_id', $dupe_id, $commentdata );
       
   673 
       
   674 	if ( $dupe_id ) {
  1321 		/**
   675 		/**
  1322 		 * Fires immediately after a duplicate comment is detected.
   676 		 * Fires immediately after a duplicate comment is detected.
  1323 		 *
   677 		 *
  1324 		 * @since 3.0.0
   678 		 * @since 3.0.0
  1325 		 *
   679 		 *
  1326 		 * @param array $commentdata Comment data.
   680 		 * @param array $commentdata Comment data.
  1327 		 */
   681 		 */
  1328 		do_action( 'comment_duplicate_trigger', $commentdata );
   682 		do_action( 'comment_duplicate_trigger', $commentdata );
  1329 		if ( defined( 'DOING_AJAX' ) ) {
   683 		if ( true === $avoid_die ) {
  1330 			die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
   684 			return new WP_Error( 'comment_duplicate', __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ), 409 );
       
   685 		} else {
       
   686 			if ( wp_doing_ajax() ) {
       
   687 				die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
       
   688 			}
       
   689 
       
   690 			wp_die( __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ), 409 );
  1331 		}
   691 		}
  1332 		wp_die( __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ), 409 );
       
  1333 	}
   692 	}
  1334 
   693 
  1335 	/**
   694 	/**
  1336 	 * Fires immediately before a comment is marked approved.
   695 	 * Fires immediately before a comment is marked approved.
  1337 	 *
   696 	 *
  1338 	 * Allows checking for comment flooding.
   697 	 * Allows checking for comment flooding.
  1339 	 *
   698 	 *
  1340 	 * @since 2.3.0
   699 	 * @since 2.3.0
       
   700 	 * @since 4.7.0 The `$avoid_die` parameter was added.
  1341 	 *
   701 	 *
  1342 	 * @param string $comment_author_IP    Comment author's IP address.
   702 	 * @param string $comment_author_IP    Comment author's IP address.
  1343 	 * @param string $comment_author_email Comment author's email.
   703 	 * @param string $comment_author_email Comment author's email.
  1344 	 * @param string $comment_date_gmt     GMT date the comment was posted.
   704 	 * @param string $comment_date_gmt     GMT date the comment was posted.
       
   705 	 * @param bool   $avoid_die            Whether to prevent executing wp_die()
       
   706 	 *                                     or die() if a comment flood is occurring.
  1345 	 */
   707 	 */
  1346 	do_action(
   708 	do_action(
  1347 		'check_comment_flood',
   709 		'check_comment_flood',
  1348 		$commentdata['comment_author_IP'],
   710 		$commentdata['comment_author_IP'],
  1349 		$commentdata['comment_author_email'],
   711 		$commentdata['comment_author_email'],
  1350 		$commentdata['comment_date_gmt']
   712 		$commentdata['comment_date_gmt'],
       
   713 		$avoid_die
  1351 	);
   714 	);
       
   715 
       
   716 	/**
       
   717 	 * Filters whether a comment is part of a comment flood.
       
   718 	 *
       
   719 	 * The default check is wp_check_comment_flood(). See check_comment_flood_db().
       
   720 	 *
       
   721 	 * @since 4.7.0
       
   722 	 *
       
   723 	 * @param bool   $is_flood             Is a comment flooding occurring? Default false.
       
   724 	 * @param string $comment_author_IP    Comment author's IP address.
       
   725 	 * @param string $comment_author_email Comment author's email.
       
   726 	 * @param string $comment_date_gmt     GMT date the comment was posted.
       
   727 	 * @param bool   $avoid_die            Whether to prevent executing wp_die()
       
   728 	 *                                     or die() if a comment flood is occurring.
       
   729 	 */
       
   730 	$is_flood = apply_filters(
       
   731 		'wp_is_comment_flood',
       
   732 		false,
       
   733 		$commentdata['comment_author_IP'],
       
   734 		$commentdata['comment_author_email'],
       
   735 		$commentdata['comment_date_gmt'],
       
   736 		$avoid_die
       
   737 	);
       
   738 
       
   739 	if ( $is_flood ) {
       
   740 		return new WP_Error( 'comment_flood', __( 'You are posting comments too quickly. Slow down.' ), 429 );
       
   741 	}
  1352 
   742 
  1353 	if ( ! empty( $commentdata['user_id'] ) ) {
   743 	if ( ! empty( $commentdata['user_id'] ) ) {
  1354 		$user = get_userdata( $commentdata['user_id'] );
   744 		$user = get_userdata( $commentdata['user_id'] );
  1355 		$post_author = $wpdb->get_var( $wpdb->prepare(
   745 		$post_author = $wpdb->get_var( $wpdb->prepare(
  1356 			"SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1",
   746 			"SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1",
  1383 			$commentdata['comment_author_url'],
   773 			$commentdata['comment_author_url'],
  1384 			$commentdata['comment_content'],
   774 			$commentdata['comment_content'],
  1385 			$commentdata['comment_author_IP'],
   775 			$commentdata['comment_author_IP'],
  1386 			$commentdata['comment_agent']
   776 			$commentdata['comment_agent']
  1387 		) ) {
   777 		) ) {
  1388 			$approved = 'spam';
   778 			$approved = EMPTY_TRASH_DAYS ? 'trash' : 'spam';
  1389 		}
   779 		}
  1390 	}
   780 	}
  1391 
   781 
  1392 	/**
   782 	/**
  1393 	 * Filter a comment's approval status before it is set.
   783 	 * Filters a comment's approval status before it is set.
  1394 	 *
   784 	 *
  1395 	 * @since 2.1.0
   785 	 * @since 2.1.0
  1396 	 *
   786 	 * @since 4.9.0 Returning a WP_Error value from the filter will shortcircuit comment insertion and
  1397 	 * @param bool|string $approved    The approval status. Accepts 1, 0, or 'spam'.
   787 	 *              allow skipping further processing.
  1398 	 * @param array       $commentdata Comment data.
   788 	 *
       
   789 	 * @param bool|string|WP_Error $approved    The approval status. Accepts 1, 0, 'spam' or WP_Error.
       
   790 	 * @param array                $commentdata Comment data.
  1399 	 */
   791 	 */
  1400 	$approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
   792 	$approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
  1401 	return $approved;
   793 	return $approved;
  1402 }
   794 }
  1403 
   795 
  1404 /**
   796 /**
  1405  * Check whether comment flooding is occurring.
   797  * Hooks WP's native database-based comment-flood check.
       
   798  *
       
   799  * This wrapper maintains backward compatibility with plugins that expect to
       
   800  * be able to unhook the legacy check_comment_flood_db() function from
       
   801  * 'check_comment_flood' using remove_action().
       
   802  *
       
   803  * @since 2.3.0
       
   804  * @since 4.7.0 Converted to be an add_filter() wrapper.
       
   805  */
       
   806 function check_comment_flood_db() {
       
   807 	add_filter( 'wp_is_comment_flood', 'wp_check_comment_flood', 10, 5 );
       
   808 }
       
   809 
       
   810 /**
       
   811  * Checks whether comment flooding is occurring.
  1406  *
   812  *
  1407  * Won't run, if current user can manage options, so to not block
   813  * Won't run, if current user can manage options, so to not block
  1408  * administrators.
   814  * administrators.
  1409  *
   815  *
  1410  * @since 2.3.0
   816  * @since 4.7.0
  1411  *
   817  *
  1412  * @global wpdb $wpdb WordPress database abstraction object.
   818  * @global wpdb $wpdb WordPress database abstraction object.
  1413  *
   819  *
  1414  * @param string $ip Comment IP.
   820  * @param bool   $is_flood  Is a comment flooding occurring?
  1415  * @param string $email Comment author email address.
   821  * @param string $ip        Comment author's IP address.
  1416  * @param string $date MySQL time string.
   822  * @param string $email     Comment author's email address.
  1417  */
   823  * @param string $date      MySQL time string.
  1418 function check_comment_flood_db( $ip, $email, $date ) {
   824  * @param bool   $avoid_die When true, a disallowed comment will result in the function
       
   825  *                          returning a WP_Error object, rather than executing wp_die().
       
   826  *                          Default false.
       
   827  * @return bool Whether comment flooding is occurring.
       
   828  */
       
   829 function wp_check_comment_flood( $is_flood, $ip, $email, $date, $avoid_die = false ) {
       
   830 
  1419 	global $wpdb;
   831 	global $wpdb;
  1420 	if ( current_user_can( 'manage_options' ) )
   832 
  1421 		return; // don't throttle admins
   833 	// Another callback has declared a flood. Trust it.
       
   834 	if ( true === $is_flood ) {
       
   835 		return $is_flood;
       
   836 	}
       
   837 
       
   838 	// don't throttle admins or moderators
       
   839 	if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
       
   840 		return false;
       
   841 	}
  1422 	$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
   842 	$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
  1423 	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 ) ) ) {
   843 
       
   844 	if ( is_user_logged_in() ) {
       
   845 		$user = get_current_user_id();
       
   846 		$check_column = '`user_id`';
       
   847 	} else {
       
   848 		$user = $ip;
       
   849 		$check_column = '`comment_author_IP`';
       
   850 	}
       
   851 
       
   852 	$sql = $wpdb->prepare(
       
   853 		"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",
       
   854 		$hour_ago,
       
   855 		$user,
       
   856 		$email
       
   857 	);
       
   858 	$lasttime = $wpdb->get_var( $sql );
       
   859 	if ( $lasttime ) {
  1424 		$time_lastcomment = mysql2date('U', $lasttime, false);
   860 		$time_lastcomment = mysql2date('U', $lasttime, false);
  1425 		$time_newcomment  = mysql2date('U', $date, false);
   861 		$time_newcomment  = mysql2date('U', $date, false);
  1426 		/**
   862 		/**
  1427 		 * Filter the comment flood status.
   863 		 * Filters the comment flood status.
  1428 		 *
   864 		 *
  1429 		 * @since 2.1.0
   865 		 * @since 2.1.0
  1430 		 *
   866 		 *
  1431 		 * @param bool $bool             Whether a comment flood is occurring. Default false.
   867 		 * @param bool $bool             Whether a comment flood is occurring. Default false.
  1432 		 * @param int  $time_lastcomment Timestamp of when the last comment was posted.
   868 		 * @param int  $time_lastcomment Timestamp of when the last comment was posted.
  1441 			 *
   877 			 *
  1442 			 * @param int $time_lastcomment Timestamp of when the last comment was posted.
   878 			 * @param int $time_lastcomment Timestamp of when the last comment was posted.
  1443 			 * @param int $time_newcomment  Timestamp of when the new comment was posted.
   879 			 * @param int $time_newcomment  Timestamp of when the new comment was posted.
  1444 			 */
   880 			 */
  1445 			do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
   881 			do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
  1446 
   882 			if ( true === $avoid_die ) {
  1447 			if ( defined('DOING_AJAX') )
   883 				return true;
  1448 				die( __('You are posting comments too quickly. Slow down.') );
   884 			} else {
  1449 
   885 				if ( wp_doing_ajax() ) {
  1450 			wp_die( __( 'You are posting comments too quickly. Slow down.' ), 429 );
   886 					die( __('You are posting comments too quickly. Slow down.') );
       
   887 				}
       
   888 
       
   889 				wp_die( __( 'You are posting comments too quickly. Slow down.' ), 429 );
       
   890 			}
  1451 		}
   891 		}
  1452 	}
   892 	}
       
   893 
       
   894 	return false;
  1453 }
   895 }
  1454 
   896 
  1455 /**
   897 /**
  1456  * Separates an array of comments into an array keyed by comment_type.
   898  * Separates an array of comments into an array keyed by comment_type.
  1457  *
   899  *
  1480  *
   922  *
  1481  * @since 2.7.0
   923  * @since 2.7.0
  1482  *
   924  *
  1483  * @uses Walker_Comment
   925  * @uses Walker_Comment
  1484  *
   926  *
  1485  * @param array $comments Optional array of comment objects. Defaults to $wp_query->comments
   927  * @global WP_Query $wp_query
  1486  * @param int $per_page Optional comments per page.
   928  *
  1487  * @param boolean $threaded Optional control over flat or threaded comments.
   929  * @param array $comments Optional array of WP_Comment objects. Defaults to $wp_query->comments
       
   930  * @param int   $per_page Optional comments per page.
       
   931  * @param bool  $threaded Optional control over flat or threaded comments.
  1488  * @return int Number of comment pages.
   932  * @return int Number of comment pages.
  1489  */
   933  */
  1490 function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
   934 function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
  1491 	global $wp_query;
   935 	global $wp_query;
  1492 
   936 
  1497 		$comments = $wp_query->comments;
   941 		$comments = $wp_query->comments;
  1498 
   942 
  1499 	if ( empty($comments) )
   943 	if ( empty($comments) )
  1500 		return 0;
   944 		return 0;
  1501 
   945 
  1502 	if ( ! get_option( 'page_comments' ) )
   946 	if ( ! get_option( 'page_comments' ) ) {
  1503 		return 1;
   947 		return 1;
       
   948 	}
  1504 
   949 
  1505 	if ( !isset($per_page) )
   950 	if ( !isset($per_page) )
  1506 		$per_page = (int) get_query_var('comments_per_page');
   951 		$per_page = (int) get_query_var('comments_per_page');
  1507 	if ( 0 === $per_page )
   952 	if ( 0 === $per_page )
  1508 		$per_page = (int) get_option('comments_per_page');
   953 		$per_page = (int) get_option('comments_per_page');
  1525 /**
   970 /**
  1526  * Calculate what page number a comment will appear on for comment paging.
   971  * Calculate what page number a comment will appear on for comment paging.
  1527  *
   972  *
  1528  * @since 2.7.0
   973  * @since 2.7.0
  1529  *
   974  *
  1530  * @param int $comment_ID Comment ID.
   975  * @global wpdb $wpdb WordPress database abstraction object.
  1531  * @param array $args Optional args.
   976  *
       
   977  * @param int   $comment_ID Comment ID.
       
   978  * @param array $args {
       
   979  *      Array of optional arguments.
       
   980  *      @type string     $type      Limit paginated comments to those matching a given type. Accepts 'comment',
       
   981  *                                  'trackback', 'pingback', 'pings' (trackbacks and pingbacks), or 'all'.
       
   982  *                                  Default is 'all'.
       
   983  *      @type int        $per_page  Per-page count to use when calculating pagination. Defaults to the value of the
       
   984  *                                  'comments_per_page' option.
       
   985  *      @type int|string $max_depth If greater than 1, comment page will be determined for the top-level parent of
       
   986  *                                  `$comment_ID`. Defaults to the value of the 'thread_comments_depth' option.
       
   987  * } *
  1532  * @return int|null Comment page number or null on error.
   988  * @return int|null Comment page number or null on error.
  1533  */
   989  */
  1534 function get_page_of_comment( $comment_ID, $args = array() ) {
   990 function get_page_of_comment( $comment_ID, $args = array() ) {
  1535 	global $wpdb;
   991 	global $wpdb;
  1536 
   992 
       
   993 	$page = null;
       
   994 
  1537 	if ( !$comment = get_comment( $comment_ID ) )
   995 	if ( !$comment = get_comment( $comment_ID ) )
  1538 		return;
   996 		return;
  1539 
   997 
  1540 	$defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
   998 	$defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
  1541 	$args = wp_parse_args( $args, $defaults );
   999 	$args = wp_parse_args( $args, $defaults );
  1542 
  1000 	$original_args = $args;
  1543 	if ( '' === $args['per_page'] && get_option('page_comments') )
  1001 
  1544 		$args['per_page'] = get_query_var('comments_per_page');
  1002 	// Order of precedence: 1. `$args['per_page']`, 2. 'comments_per_page' query_var, 3. 'comments_per_page' option.
       
  1003 	if ( get_option( 'page_comments' ) ) {
       
  1004 		if ( '' === $args['per_page'] ) {
       
  1005 			$args['per_page'] = get_query_var( 'comments_per_page' );
       
  1006 		}
       
  1007 
       
  1008 		if ( '' === $args['per_page'] ) {
       
  1009 			$args['per_page'] = get_option( 'comments_per_page' );
       
  1010 		}
       
  1011 	}
       
  1012 
  1545 	if ( empty($args['per_page']) ) {
  1013 	if ( empty($args['per_page']) ) {
  1546 		$args['per_page'] = 0;
  1014 		$args['per_page'] = 0;
  1547 		$args['page'] = 0;
  1015 		$args['page'] = 0;
  1548 	}
  1016 	}
  1549 	if ( $args['per_page'] < 1 )
  1017 
  1550 		return 1;
  1018 	if ( $args['per_page'] < 1 ) {
  1551 
  1019 		$page = 1;
  1552 	if ( '' === $args['max_depth'] ) {
  1020 	}
  1553 		if ( get_option('thread_comments') )
  1021 
  1554 			$args['max_depth'] = get_option('thread_comments_depth');
  1022 	if ( null === $page ) {
  1555 		else
  1023 		if ( '' === $args['max_depth'] ) {
  1556 			$args['max_depth'] = -1;
  1024 			if ( get_option('thread_comments') )
  1557 	}
  1025 				$args['max_depth'] = get_option('thread_comments_depth');
  1558 
  1026 			else
  1559 	// Find this comment's top level parent if threading is enabled
  1027 				$args['max_depth'] = -1;
  1560 	if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
  1028 		}
  1561 		return get_page_of_comment( $comment->comment_parent, $args );
  1029 
  1562 
  1030 		// Find this comment's top level parent if threading is enabled
  1563 	$allowedtypes = array(
  1031 		if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
  1564 		'comment' => '',
  1032 			return get_page_of_comment( $comment->comment_parent, $args );
  1565 		'pingback' => 'pingback',
  1033 
  1566 		'trackback' => 'trackback',
  1034 		$comment_args = array(
       
  1035 			'type'       => $args['type'],
       
  1036 			'post_id'    => $comment->comment_post_ID,
       
  1037 			'fields'     => 'ids',
       
  1038 			'count'      => true,
       
  1039 			'status'     => 'approve',
       
  1040 			'parent'     => 0,
       
  1041 			'date_query' => array(
       
  1042 				array(
       
  1043 					'column' => "$wpdb->comments.comment_date_gmt",
       
  1044 					'before' => $comment->comment_date_gmt,
       
  1045 				)
       
  1046 			),
       
  1047 		);
       
  1048 
       
  1049 		$comment_query = new WP_Comment_Query();
       
  1050 		$older_comment_count = $comment_query->query( $comment_args );
       
  1051 
       
  1052 		// No older comments? Then it's page #1.
       
  1053 		if ( 0 == $older_comment_count ) {
       
  1054 			$page = 1;
       
  1055 
       
  1056 		// Divide comments older than this one by comments per page to get this comment's page number
       
  1057 		} else {
       
  1058 			$page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
       
  1059 		}
       
  1060 	}
       
  1061 
       
  1062 	/**
       
  1063 	 * Filters the calculated page on which a comment appears.
       
  1064 	 *
       
  1065 	 * @since 4.4.0
       
  1066 	 * @since 4.7.0 Introduced the `$comment_ID` parameter.
       
  1067 	 *
       
  1068 	 * @param int   $page          Comment page.
       
  1069 	 * @param array $args {
       
  1070 	 *     Arguments used to calculate pagination. These include arguments auto-detected by the function,
       
  1071 	 *     based on query vars, system settings, etc. For pristine arguments passed to the function,
       
  1072 	 *     see `$original_args`.
       
  1073 	 *
       
  1074 	 *     @type string $type      Type of comments to count.
       
  1075 	 *     @type int    $page      Calculated current page.
       
  1076 	 *     @type int    $per_page  Calculated number of comments per page.
       
  1077 	 *     @type int    $max_depth Maximum comment threading depth allowed.
       
  1078 	 * }
       
  1079 	 * @param array $original_args {
       
  1080 	 *     Array of arguments passed to the function. Some or all of these may not be set.
       
  1081 	 *
       
  1082 	 *     @type string $type      Type of comments to count.
       
  1083 	 *     @type int    $page      Current comment page.
       
  1084 	 *     @type int    $per_page  Number of comments per page.
       
  1085 	 *     @type int    $max_depth Maximum comment threading depth allowed.
       
  1086 	 * }
       
  1087 	 * @param int $comment_ID ID of the comment.
       
  1088 	 */
       
  1089 	return apply_filters( 'get_page_of_comment', (int) $page, $args, $original_args, $comment_ID );
       
  1090 }
       
  1091 
       
  1092 /**
       
  1093  * Retrieves the maximum character lengths for the comment form fields.
       
  1094  *
       
  1095  * @since 4.5.0
       
  1096  *
       
  1097  * @global wpdb $wpdb WordPress database abstraction object.
       
  1098  *
       
  1099  * @return array Maximum character length for the comment form fields.
       
  1100  */
       
  1101 function wp_get_comment_fields_max_lengths() {
       
  1102 	global $wpdb;
       
  1103 
       
  1104 	$lengths = array(
       
  1105 		'comment_author'       => 245,
       
  1106 		'comment_author_email' => 100,
       
  1107 		'comment_author_url'   => 200,
       
  1108 		'comment_content'      => 65525,
  1567 	);
  1109 	);
  1568 
  1110 
  1569 	$comtypewhere = ( 'all' != $args['type'] && isset($allowedtypes[$args['type']]) ) ? " AND comment_type = '" . $allowedtypes[$args['type']] . "'" : '';
  1111 	if ( $wpdb->is_mysql ) {
  1570 
  1112 		foreach ( $lengths as $column => $length ) {
  1571 	// Count comments older than this one
  1113 			$col_length = $wpdb->get_col_length( $wpdb->comments, $column );
  1572 	$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 ) );
  1114 			$max_length = 0;
  1573 
  1115 
  1574 	// No older comments? Then it's page #1.
  1116 			// No point if we can't get the DB column lengths
  1575 	if ( 0 == $oldercoms )
  1117 			if ( is_wp_error( $col_length ) ) {
  1576 		return 1;
  1118 				break;
  1577 
  1119 			}
  1578 	// Divide comments older than this one by comments per page to get this comment's page number
  1120 
  1579 	return ceil( ( $oldercoms + 1 ) / $args['per_page'] );
  1121 			if ( ! is_array( $col_length ) && (int) $col_length > 0 ) {
       
  1122 				$max_length = (int) $col_length;
       
  1123 			} elseif ( is_array( $col_length ) && isset( $col_length['length'] ) && intval( $col_length['length'] ) > 0 ) {
       
  1124 				$max_length = (int) $col_length['length'];
       
  1125 
       
  1126 				if ( ! empty( $col_length['type'] ) && 'byte' === $col_length['type'] ) {
       
  1127 					$max_length = $max_length - 10;
       
  1128 				}
       
  1129 			}
       
  1130 
       
  1131 			if ( $max_length > 0 ) {
       
  1132 				$lengths[ $column ] = $max_length;
       
  1133 			}
       
  1134 		}
       
  1135 	}
       
  1136 
       
  1137 	/**
       
  1138 	 * Filters the lengths for the comment form fields.
       
  1139 	 *
       
  1140 	 * @since 4.5.0
       
  1141 	 *
       
  1142 	 * @param array $lengths Associative array `'field_name' => 'maximum length'`.
       
  1143 	 */
       
  1144 	return apply_filters( 'wp_get_comment_fields_max_lengths', $lengths );
       
  1145 }
       
  1146 
       
  1147 /**
       
  1148  * Compares the lengths of comment data against the maximum character limits.
       
  1149  *
       
  1150  * @since 4.7.0
       
  1151  *
       
  1152  * @param array $comment_data Array of arguments for inserting a comment.
       
  1153  * @return WP_Error|true WP_Error when a comment field exceeds the limit,
       
  1154  *                       otherwise true.
       
  1155  */
       
  1156 function wp_check_comment_data_max_lengths( $comment_data ) {
       
  1157 	$max_lengths = wp_get_comment_fields_max_lengths();
       
  1158 
       
  1159 	if ( isset( $comment_data['comment_author'] ) && mb_strlen( $comment_data['comment_author'], '8bit' ) > $max_lengths['comment_author'] ) {
       
  1160 		return new WP_Error( 'comment_author_column_length', __( '<strong>ERROR</strong>: your name is too long.' ), 200 );
       
  1161 	}
       
  1162 
       
  1163 	if ( isset( $comment_data['comment_author_email'] ) && strlen( $comment_data['comment_author_email'] ) > $max_lengths['comment_author_email'] ) {
       
  1164 		return new WP_Error( 'comment_author_email_column_length', __( '<strong>ERROR</strong>: your email address is too long.' ), 200 );
       
  1165 	}
       
  1166 
       
  1167 	if ( isset( $comment_data['comment_author_url'] ) && strlen( $comment_data['comment_author_url'] ) > $max_lengths['comment_author_url'] ) {
       
  1168 		return new WP_Error( 'comment_author_url_column_length', __( '<strong>ERROR</strong>: your url is too long.' ), 200 );
       
  1169 	}
       
  1170 
       
  1171 	if ( isset( $comment_data['comment_content'] ) && mb_strlen( $comment_data['comment_content'], '8bit' ) > $max_lengths['comment_content'] ) {
       
  1172 		return new WP_Error( 'comment_content_column_length', __( '<strong>ERROR</strong>: your comment is too long.' ), 200 );
       
  1173 	}
       
  1174 
       
  1175 	return true;
  1580 }
  1176 }
  1581 
  1177 
  1582 /**
  1178 /**
  1583  * Does comment contain blacklisted characters or words.
  1179  * Does comment contain blacklisted characters or words.
  1584  *
  1180  *
  1586  *
  1182  *
  1587  * @param string $author The author of the comment
  1183  * @param string $author The author of the comment
  1588  * @param string $email The email of the comment
  1184  * @param string $email The email of the comment
  1589  * @param string $url The url used in the comment
  1185  * @param string $url The url used in the comment
  1590  * @param string $comment The comment content
  1186  * @param string $comment The comment content
  1591  * @param string $user_ip The comment author IP address
  1187  * @param string $user_ip The comment author's IP address
  1592  * @param string $user_agent The author's browser user agent
  1188  * @param string $user_agent The author's browser user agent
  1593  * @return bool True if comment contains blacklisted content, false if comment does not
  1189  * @return bool True if comment contains blacklisted content, false if comment does not
  1594  */
  1190  */
  1595 function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
  1191 function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
  1596 	/**
  1192 	/**
  1608 	do_action( 'wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent );
  1204 	do_action( 'wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent );
  1609 
  1205 
  1610 	$mod_keys = trim( get_option('blacklist_keys') );
  1206 	$mod_keys = trim( get_option('blacklist_keys') );
  1611 	if ( '' == $mod_keys )
  1207 	if ( '' == $mod_keys )
  1612 		return false; // If moderation keys are empty
  1208 		return false; // If moderation keys are empty
       
  1209 
       
  1210 	// Ensure HTML tags are not being used to bypass the blacklist.
       
  1211 	$comment_without_html = wp_strip_all_tags( $comment );
       
  1212 
  1613 	$words = explode("\n", $mod_keys );
  1213 	$words = explode("\n", $mod_keys );
  1614 
  1214 
  1615 	foreach ( (array) $words as $word ) {
  1215 	foreach ( (array) $words as $word ) {
  1616 		$word = trim($word);
  1216 		$word = trim($word);
  1617 
  1217 
  1626 		if (
  1226 		if (
  1627 			   preg_match($pattern, $author)
  1227 			   preg_match($pattern, $author)
  1628 			|| preg_match($pattern, $email)
  1228 			|| preg_match($pattern, $email)
  1629 			|| preg_match($pattern, $url)
  1229 			|| preg_match($pattern, $url)
  1630 			|| preg_match($pattern, $comment)
  1230 			|| preg_match($pattern, $comment)
       
  1231 			|| preg_match($pattern, $comment_without_html)
  1631 			|| preg_match($pattern, $user_ip)
  1232 			|| preg_match($pattern, $user_ip)
  1632 			|| preg_match($pattern, $user_agent)
  1233 			|| preg_match($pattern, $user_agent)
  1633 		 )
  1234 		 )
  1634 			return true;
  1235 			return true;
  1635 	}
  1236 	}
  1648  * cache.
  1249  * cache.
  1649  *
  1250  *
  1650  * @since 2.5.0
  1251  * @since 2.5.0
  1651  *
  1252  *
  1652  * @param int $post_id Optional. Post ID.
  1253  * @param int $post_id Optional. Post ID.
  1653  * @return object Comment stats.
  1254  * @return object|array Comment stats.
  1654  */
  1255  */
  1655 function wp_count_comments( $post_id = 0 ) {
  1256 function wp_count_comments( $post_id = 0 ) {
  1656 	global $wpdb;
       
  1657 
       
  1658 	$post_id = (int) $post_id;
  1257 	$post_id = (int) $post_id;
  1659 
  1258 
  1660 	/**
  1259 	/**
  1661 	 * Filter the comments count for a given post.
  1260 	 * Filters the comments count for a given post.
  1662 	 *
  1261 	 *
  1663 	 * @since 2.7.0
  1262 	 * @since 2.7.0
  1664 	 *
  1263 	 *
  1665 	 * @param array $count   An empty array.
  1264 	 * @param array $count   An empty array.
  1666 	 * @param int   $post_id The post ID.
  1265 	 * @param int   $post_id The post ID.
  1667 	 */
  1266 	 */
  1668 	$stats = apply_filters( 'wp_count_comments', array(), $post_id );
  1267 	$filtered = apply_filters( 'wp_count_comments', array(), $post_id );
  1669 	if ( !empty($stats) )
  1268 	if ( ! empty( $filtered ) ) {
  1670 		return $stats;
  1269 		return $filtered;
  1671 
  1270 	}
  1672 	$count = wp_cache_get("comments-{$post_id}", 'counts');
  1271 
  1673 
  1272 	$count = wp_cache_get( "comments-{$post_id}", 'counts' );
  1674 	if ( false !== $count )
  1273 	if ( false !== $count ) {
  1675 		return $count;
  1274 		return $count;
  1676 
  1275 	}
  1677 	$where = '';
  1276 
  1678 	if ( $post_id > 0 )
  1277 	$stats = get_comment_count( $post_id );
  1679 		$where = $wpdb->prepare( "WHERE comment_post_ID = %d", $post_id );
  1278 	$stats['moderated'] = $stats['awaiting_moderation'];
  1680 
  1279 	unset( $stats['awaiting_moderation'] );
  1681 	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
  1280 
  1682 
  1281 	$stats_object = (object) $stats;
  1683 	$total = 0;
  1282 	wp_cache_set( "comments-{$post_id}", $stats_object, 'counts' );
  1684 	$approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
  1283 
  1685 	foreach ( (array) $count as $row ) {
  1284 	return $stats_object;
  1686 		// Don't count post-trashed toward totals
       
  1687 		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] )
       
  1688 			$total += $row['num_comments'];
       
  1689 		if ( isset( $approved[$row['comment_approved']] ) )
       
  1690 			$stats[$approved[$row['comment_approved']]] = $row['num_comments'];
       
  1691 	}
       
  1692 
       
  1693 	$stats['total_comments'] = $total;
       
  1694 	foreach ( $approved as $key ) {
       
  1695 		if ( empty($stats[$key]) )
       
  1696 			$stats[$key] = 0;
       
  1697 	}
       
  1698 
       
  1699 	$stats = (object) $stats;
       
  1700 	wp_cache_set("comments-{$post_id}", $stats, 'counts');
       
  1701 
       
  1702 	return $stats;
       
  1703 }
  1285 }
  1704 
  1286 
  1705 /**
  1287 /**
  1706  * Trashes or deletes a comment.
  1288  * Trashes or deletes a comment.
  1707  *
  1289  *
  1713  *
  1295  *
  1714  * @since 2.0.0
  1296  * @since 2.0.0
  1715  *
  1297  *
  1716  * @global wpdb $wpdb WordPress database abstraction object.
  1298  * @global wpdb $wpdb WordPress database abstraction object.
  1717  *
  1299  *
  1718  * @param int $comment_id Comment ID
  1300  * @param int|WP_Comment $comment_id   Comment ID or WP_Comment object.
  1719  * @param bool $force_delete Whether to bypass trash and force deletion. Default is false.
  1301  * @param bool           $force_delete Whether to bypass trash and force deletion. Default is false.
  1720  * @return bool True on success, false on failure.
  1302  * @return bool True on success, false on failure.
  1721  */
  1303  */
  1722 function wp_delete_comment($comment_id, $force_delete = false) {
  1304 function wp_delete_comment($comment_id, $force_delete = false) {
  1723 	global $wpdb;
  1305 	global $wpdb;
  1724 	if (!$comment = get_comment($comment_id))
  1306 	if (!$comment = get_comment($comment_id))
  1725 		return false;
  1307 		return false;
  1726 
  1308 
  1727 	if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status($comment_id), array( 'trash', 'spam' ) ) )
  1309 	if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ) ) )
  1728 		return wp_trash_comment($comment_id);
  1310 		return wp_trash_comment($comment_id);
  1729 
  1311 
  1730 	/**
  1312 	/**
  1731 	 * Fires immediately before a comment is deleted from the database.
  1313 	 * Fires immediately before a comment is deleted from the database.
  1732 	 *
  1314 	 *
  1733 	 * @since 1.2.0
  1315 	 * @since 1.2.0
  1734 	 *
  1316 	 * @since 4.9.0 Added the `$comment` parameter.
  1735 	 * @param int $comment_id The comment ID.
  1317 	 *
  1736 	 */
  1318 	 * @param int        $comment_id The comment ID.
  1737 	do_action( 'delete_comment', $comment_id );
  1319 	 * @param WP_Comment $comment    The comment to be deleted.
       
  1320 	 */
       
  1321 	do_action( 'delete_comment', $comment->comment_ID, $comment );
  1738 
  1322 
  1739 	// Move children up a level.
  1323 	// Move children up a level.
  1740 	$children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment_id) );
  1324 	$children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment->comment_ID) );
  1741 	if ( !empty($children) ) {
  1325 	if ( !empty($children) ) {
  1742 		$wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment_id));
  1326 		$wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment->comment_ID));
  1743 		clean_comment_cache($children);
  1327 		clean_comment_cache($children);
  1744 	}
  1328 	}
  1745 
  1329 
  1746 	// Delete metadata
  1330 	// Delete metadata
  1747 	$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment_id ) );
  1331 	$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
  1748 	foreach ( $meta_ids as $mid )
  1332 	foreach ( $meta_ids as $mid )
  1749 		delete_metadata_by_mid( 'comment', $mid );
  1333 		delete_metadata_by_mid( 'comment', $mid );
  1750 
  1334 
  1751 	if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment_id ) ) )
  1335 	if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment->comment_ID ) ) )
  1752 		return false;
  1336 		return false;
  1753 
  1337 
  1754 	/**
  1338 	/**
  1755 	 * Fires immediately after a comment is deleted from the database.
  1339 	 * Fires immediately after a comment is deleted from the database.
  1756 	 *
  1340 	 *
  1757 	 * @since 2.9.0
  1341 	 * @since 2.9.0
  1758 	 *
  1342 	 * @since 4.9.0 Added the `$comment` parameter.
  1759 	 * @param int $comment_id The comment ID.
  1343 	 *
  1760 	 */
  1344 	 * @param int        $comment_id The comment ID.
  1761 	do_action( 'deleted_comment', $comment_id );
  1345 	 * @param WP_Comment $comment    The deleted comment.
       
  1346 	 */
       
  1347 	do_action( 'deleted_comment', $comment->comment_ID, $comment );
  1762 
  1348 
  1763 	$post_id = $comment->comment_post_ID;
  1349 	$post_id = $comment->comment_post_ID;
  1764 	if ( $post_id && $comment->comment_approved == 1 )
  1350 	if ( $post_id && $comment->comment_approved == 1 )
  1765 		wp_update_comment_count($post_id);
  1351 		wp_update_comment_count($post_id);
  1766 
  1352 
  1767 	clean_comment_cache($comment_id);
  1353 	clean_comment_cache( $comment->comment_ID );
  1768 
  1354 
  1769 	/** This action is documented in wp-includes/comment.php */
  1355 	/** This action is documented in wp-includes/comment.php */
  1770 	do_action( 'wp_set_comment_status', $comment_id, 'delete' );
  1356 	do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
  1771 
  1357 
  1772 	wp_transition_comment_status('delete', $comment->comment_approved, $comment);
  1358 	wp_transition_comment_status('delete', $comment->comment_approved, $comment);
  1773 	return true;
  1359 	return true;
  1774 }
  1360 }
  1775 
  1361 
  1778  *
  1364  *
  1779  * If trash is disabled, comment is permanently deleted.
  1365  * If trash is disabled, comment is permanently deleted.
  1780  *
  1366  *
  1781  * @since 2.9.0
  1367  * @since 2.9.0
  1782  *
  1368  *
  1783  * @param int $comment_id Comment ID.
  1369  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1784  * @return bool True on success, false on failure.
  1370  * @return bool True on success, false on failure.
  1785  */
  1371  */
  1786 function wp_trash_comment($comment_id) {
  1372 function wp_trash_comment($comment_id) {
  1787 	if ( !EMPTY_TRASH_DAYS )
  1373 	if ( !EMPTY_TRASH_DAYS )
  1788 		return wp_delete_comment($comment_id, true);
  1374 		return wp_delete_comment($comment_id, true);
  1792 
  1378 
  1793 	/**
  1379 	/**
  1794 	 * Fires immediately before a comment is sent to the Trash.
  1380 	 * Fires immediately before a comment is sent to the Trash.
  1795 	 *
  1381 	 *
  1796 	 * @since 2.9.0
  1382 	 * @since 2.9.0
  1797 	 *
  1383 	 * @since 4.9.0 Added the `$comment` parameter.
  1798 	 * @param int $comment_id The comment ID.
  1384 	 *
  1799 	 */
  1385 	 * @param int        $comment_id The comment ID.
  1800 	do_action( 'trash_comment', $comment_id );
  1386 	 * @param WP_Comment $comment    The comment to be trashed.
  1801 
  1387 	 */
  1802 	if ( wp_set_comment_status($comment_id, 'trash') ) {
  1388 	do_action( 'trash_comment', $comment->comment_ID, $comment );
  1803 		add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
  1389 
  1804 		add_comment_meta($comment_id, '_wp_trash_meta_time', time() );
  1390 	if ( wp_set_comment_status( $comment, 'trash' ) ) {
       
  1391 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
       
  1392 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
       
  1393 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
       
  1394 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
  1805 
  1395 
  1806 		/**
  1396 		/**
  1807 		 * Fires immediately after a comment is sent to Trash.
  1397 		 * Fires immediately after a comment is sent to Trash.
  1808 		 *
  1398 		 *
  1809 		 * @since 2.9.0
  1399 		 * @since 2.9.0
  1810 		 *
  1400 		 * @since 4.9.0 Added the `$comment` parameter.
  1811 		 * @param int $comment_id The comment ID.
  1401 		 *
       
  1402 		 * @param int        $comment_id The comment ID.
       
  1403 		 * @param WP_Comment $comment    The trashed comment.
  1812 		 */
  1404 		 */
  1813 		do_action( 'trashed_comment', $comment_id );
  1405 		do_action( 'trashed_comment', $comment->comment_ID, $comment );
  1814 		return true;
  1406 		return true;
  1815 	}
  1407 	}
  1816 
  1408 
  1817 	return false;
  1409 	return false;
  1818 }
  1410 }
  1820 /**
  1412 /**
  1821  * Removes a comment from the Trash
  1413  * Removes a comment from the Trash
  1822  *
  1414  *
  1823  * @since 2.9.0
  1415  * @since 2.9.0
  1824  *
  1416  *
  1825  * @param int $comment_id Comment ID.
  1417  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1826  * @return bool True on success, false on failure.
  1418  * @return bool True on success, false on failure.
  1827  */
  1419  */
  1828 function wp_untrash_comment($comment_id) {
  1420 function wp_untrash_comment($comment_id) {
  1829 	if ( ! (int)$comment_id )
  1421 	$comment = get_comment( $comment_id );
       
  1422 	if ( ! $comment ) {
  1830 		return false;
  1423 		return false;
       
  1424 	}
  1831 
  1425 
  1832 	/**
  1426 	/**
  1833 	 * Fires immediately before a comment is restored from the Trash.
  1427 	 * Fires immediately before a comment is restored from the Trash.
  1834 	 *
  1428 	 *
  1835 	 * @since 2.9.0
  1429 	 * @since 2.9.0
  1836 	 *
  1430 	 * @since 4.9.0 Added the `$comment` parameter.
  1837 	 * @param int $comment_id The comment ID.
  1431 	 *
  1838 	 */
  1432 	 * @param int        $comment_id The comment ID.
  1839 	do_action( 'untrash_comment', $comment_id );
  1433 	 * @param WP_Comment $comment    The comment to be untrashed.
  1840 
  1434 	 */
  1841 	$status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
  1435 	do_action( 'untrash_comment', $comment->comment_ID, $comment );
       
  1436 
       
  1437 	$status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
  1842 	if ( empty($status) )
  1438 	if ( empty($status) )
  1843 		$status = '0';
  1439 		$status = '0';
  1844 
  1440 
  1845 	if ( wp_set_comment_status($comment_id, $status) ) {
  1441 	if ( wp_set_comment_status( $comment, $status ) ) {
  1846 		delete_comment_meta($comment_id, '_wp_trash_meta_time');
  1442 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1847 		delete_comment_meta($comment_id, '_wp_trash_meta_status');
  1443 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
  1848 		/**
  1444 		/**
  1849 		 * Fires immediately after a comment is restored from the Trash.
  1445 		 * Fires immediately after a comment is restored from the Trash.
  1850 		 *
  1446 		 *
  1851 		 * @since 2.9.0
  1447 		 * @since 2.9.0
  1852 		 *
  1448 		 * @since 4.9.0 Added the `$comment` parameter.
  1853 		 * @param int $comment_id The comment ID.
  1449 		 *
       
  1450 		 * @param int        $comment_id The comment ID.
       
  1451 		 * @param WP_Comment $comment    The untrashed comment.
  1854 		 */
  1452 		 */
  1855 		do_action( 'untrashed_comment', $comment_id );
  1453 		do_action( 'untrashed_comment', $comment->comment_ID, $comment );
  1856 		return true;
  1454 		return true;
  1857 	}
  1455 	}
  1858 
  1456 
  1859 	return false;
  1457 	return false;
  1860 }
  1458 }
  1862 /**
  1460 /**
  1863  * Marks a comment as Spam
  1461  * Marks a comment as Spam
  1864  *
  1462  *
  1865  * @since 2.9.0
  1463  * @since 2.9.0
  1866  *
  1464  *
  1867  * @param int $comment_id Comment ID.
  1465  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1868  * @return bool True on success, false on failure.
  1466  * @return bool True on success, false on failure.
  1869  */
  1467  */
  1870 function wp_spam_comment($comment_id) {
  1468 function wp_spam_comment( $comment_id ) {
  1871 	if ( !$comment = get_comment($comment_id) )
  1469 	$comment = get_comment( $comment_id );
       
  1470 	if ( ! $comment ) {
  1872 		return false;
  1471 		return false;
       
  1472 	}
  1873 
  1473 
  1874 	/**
  1474 	/**
  1875 	 * Fires immediately before a comment is marked as Spam.
  1475 	 * Fires immediately before a comment is marked as Spam.
  1876 	 *
  1476 	 *
  1877 	 * @since 2.9.0
  1477 	 * @since 2.9.0
  1878 	 *
  1478 	 * @since 4.9.0 Added the `$comment` parameter.
  1879 	 * @param int $comment_id The comment ID.
  1479 	 *
  1880 	 */
  1480 	 * @param int        $comment_id The comment ID.
  1881 	do_action( 'spam_comment', $comment_id );
  1481 	 * @param WP_Comment $comment    The comment to be marked as spam.
  1882 
  1482 	 */
  1883 	if ( wp_set_comment_status($comment_id, 'spam') ) {
  1483 	do_action( 'spam_comment', $comment->comment_ID, $comment );
  1884 		add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
  1484 
       
  1485 	if ( wp_set_comment_status( $comment, 'spam' ) ) {
       
  1486 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
       
  1487 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
       
  1488 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
       
  1489 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
  1885 		/**
  1490 		/**
  1886 		 * Fires immediately after a comment is marked as Spam.
  1491 		 * Fires immediately after a comment is marked as Spam.
  1887 		 *
  1492 		 *
  1888 		 * @since 2.9.0
  1493 		 * @since 2.9.0
  1889 		 *
  1494 		 * @since 4.9.0 Added the `$comment` parameter.
  1890 		 * @param int $comment_id The comment ID.
  1495 		 *
       
  1496 		 * @param int        $comment_id The comment ID.
       
  1497 		 * @param WP_Comment $comment    The comment marked as spam.
  1891 		 */
  1498 		 */
  1892 		do_action( 'spammed_comment', $comment_id );
  1499 		do_action( 'spammed_comment', $comment->comment_ID, $comment );
  1893 		return true;
  1500 		return true;
  1894 	}
  1501 	}
  1895 
  1502 
  1896 	return false;
  1503 	return false;
  1897 }
  1504 }
  1899 /**
  1506 /**
  1900  * Removes a comment from the Spam
  1507  * Removes a comment from the Spam
  1901  *
  1508  *
  1902  * @since 2.9.0
  1509  * @since 2.9.0
  1903  *
  1510  *
  1904  * @param int $comment_id Comment ID.
  1511  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1905  * @return bool True on success, false on failure.
  1512  * @return bool True on success, false on failure.
  1906  */
  1513  */
  1907 function wp_unspam_comment($comment_id) {
  1514 function wp_unspam_comment( $comment_id ) {
  1908 	if ( ! (int)$comment_id )
  1515 	$comment = get_comment( $comment_id );
       
  1516 	if ( ! $comment ) {
  1909 		return false;
  1517 		return false;
       
  1518 	}
  1910 
  1519 
  1911 	/**
  1520 	/**
  1912 	 * Fires immediately before a comment is unmarked as Spam.
  1521 	 * Fires immediately before a comment is unmarked as Spam.
  1913 	 *
  1522 	 *
  1914 	 * @since 2.9.0
  1523 	 * @since 2.9.0
  1915 	 *
  1524 	 * @since 4.9.0 Added the `$comment` parameter.
  1916 	 * @param int $comment_id The comment ID.
  1525 	 *
  1917 	 */
  1526 	 * @param int        $comment_id The comment ID.
  1918 	do_action( 'unspam_comment', $comment_id );
  1527 	 * @param WP_Comment $comment    The comment to be unmarked as spam.
  1919 
  1528 	 */
  1920 	$status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
  1529 	do_action( 'unspam_comment', $comment->comment_ID, $comment );
       
  1530 
       
  1531 	$status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
  1921 	if ( empty($status) )
  1532 	if ( empty($status) )
  1922 		$status = '0';
  1533 		$status = '0';
  1923 
  1534 
  1924 	if ( wp_set_comment_status($comment_id, $status) ) {
  1535 	if ( wp_set_comment_status( $comment, $status ) ) {
  1925 		delete_comment_meta($comment_id, '_wp_trash_meta_status');
  1536 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
       
  1537 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1926 		/**
  1538 		/**
  1927 		 * Fires immediately after a comment is unmarked as Spam.
  1539 		 * Fires immediately after a comment is unmarked as Spam.
  1928 		 *
  1540 		 *
  1929 		 * @since 2.9.0
  1541 		 * @since 2.9.0
  1930 		 *
  1542 		 * @since 4.9.0 Added the `$comment` parameter.
  1931 		 * @param int $comment_id The comment ID.
  1543 		 *
       
  1544 		 * @param int        $comment_id The comment ID.
       
  1545 		 * @param WP_Comment $comment    The comment unmarked as spam.
  1932 		 */
  1546 		 */
  1933 		do_action( 'unspammed_comment', $comment_id );
  1547 		do_action( 'unspammed_comment', $comment->comment_ID, $comment );
  1934 		return true;
  1548 		return true;
  1935 	}
  1549 	}
  1936 
  1550 
  1937 	return false;
  1551 	return false;
  1938 }
  1552 }
  1940 /**
  1554 /**
  1941  * The status of a comment by ID.
  1555  * The status of a comment by ID.
  1942  *
  1556  *
  1943  * @since 1.0.0
  1557  * @since 1.0.0
  1944  *
  1558  *
  1945  * @param int $comment_id Comment ID
  1559  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object
  1946  * @return false|string Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
  1560  * @return false|string Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
  1947  */
  1561  */
  1948 function wp_get_comment_status($comment_id) {
  1562 function wp_get_comment_status($comment_id) {
  1949 	$comment = get_comment($comment_id);
  1563 	$comment = get_comment($comment_id);
  1950 	if ( !$comment )
  1564 	if ( !$comment )
  1969 /**
  1583 /**
  1970  * Call hooks for when a comment status transition occurs.
  1584  * Call hooks for when a comment status transition occurs.
  1971  *
  1585  *
  1972  * Calls hooks for comment status transitions. If the new comment status is not the same
  1586  * Calls hooks for comment status transitions. If the new comment status is not the same
  1973  * as the previous comment status, then two hooks will be ran, the first is
  1587  * as the previous comment status, then two hooks will be ran, the first is
  1974  * 'transition_comment_status' with new status, old status, and comment data. The
  1588  * {@see 'transition_comment_status'} with new status, old status, and comment data. The
  1975  * next action called is 'comment_OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
  1589  * next action called is {@see comment_$old_status_to_$new_status'}. It has the
  1976  * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
       
  1977  * comment data.
  1590  * comment data.
  1978  *
  1591  *
  1979  * The final action will run whether or not the comment statuses are the same. The
  1592  * The final action will run whether or not the comment statuses are the same. The
  1980  * action is named 'comment_NEWSTATUS_COMMENTTYPE', NEWSTATUS is from the $new_status
  1593  * action is named {@see 'comment_$new_status_$comment->comment_type'}.
  1981  * parameter and COMMENTTYPE is comment_type comment data.
       
  1982  *
  1594  *
  1983  * @since 2.7.0
  1595  * @since 2.7.0
  1984  *
  1596  *
  1985  * @param string $new_status New comment status.
  1597  * @param string $new_status New comment status.
  1986  * @param string $old_status Previous comment status.
  1598  * @param string $old_status Previous comment status.
  2019 		 * The dynamic portions of the hook name, `$old_status`, and `$new_status`,
  1631 		 * The dynamic portions of the hook name, `$old_status`, and `$new_status`,
  2020 		 * refer to the old and new comment statuses, respectively.
  1632 		 * refer to the old and new comment statuses, respectively.
  2021 		 *
  1633 		 *
  2022 		 * @since 2.7.0
  1634 		 * @since 2.7.0
  2023 		 *
  1635 		 *
  2024 		 * @param object $comment Comment object.
  1636 		 * @param WP_Comment $comment Comment object.
  2025 		 */
  1637 		 */
  2026 		do_action( "comment_{$old_status}_to_{$new_status}", $comment );
  1638 		do_action( "comment_{$old_status}_to_{$new_status}", $comment );
  2027 	}
  1639 	}
  2028 	/**
  1640 	/**
  2029 	 * Fires when the status of a specific comment type is in transition.
  1641 	 * Fires when the status of a specific comment type is in transition.
  2034 	 * Typical comment types include an empty string (standard comment), 'pingback',
  1646 	 * Typical comment types include an empty string (standard comment), 'pingback',
  2035 	 * or 'trackback'.
  1647 	 * or 'trackback'.
  2036 	 *
  1648 	 *
  2037 	 * @since 2.7.0
  1649 	 * @since 2.7.0
  2038 	 *
  1650 	 *
  2039 	 * @param int $comment_ID The comment ID.
  1651 	 * @param int        $comment_ID The comment ID.
  2040 	 * @param obj $comment    Comment object.
  1652 	 * @param WP_Comment $comment    Comment object.
  2041 	 */
  1653 	 */
  2042 	do_action( "comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment );
  1654 	do_action( "comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment );
       
  1655 }
       
  1656 
       
  1657 /**
       
  1658  * Clear the lastcommentmodified cached value when a comment status is changed.
       
  1659  *
       
  1660  * Deletes the lastcommentmodified cache key when a comment enters or leaves
       
  1661  * 'approved' status.
       
  1662  *
       
  1663  * @since 4.7.0
       
  1664  * @access private
       
  1665  *
       
  1666  * @param string $new_status The new comment status.
       
  1667  * @param string $old_status The old comment status.
       
  1668  */
       
  1669 function _clear_modified_cache_on_transition_comment_status( $new_status, $old_status ) {
       
  1670 	if ( 'approved' === $new_status || 'approved' === $old_status ) {
       
  1671 		foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
       
  1672 			wp_cache_delete( "lastcommentmodified:$timezone", 'timeinfo' );
       
  1673 		}
       
  1674 	}
  2043 }
  1675 }
  2044 
  1676 
  2045 /**
  1677 /**
  2046  * Get current commenter's name, email, and URL.
  1678  * Get current commenter's name, email, and URL.
  2047  *
  1679  *
  2068 	$comment_author_url = '';
  1700 	$comment_author_url = '';
  2069 	if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
  1701 	if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
  2070 		$comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
  1702 		$comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
  2071 
  1703 
  2072 	/**
  1704 	/**
  2073 	 * Filter the current commenter's name, email, and URL.
  1705 	 * Filters the current commenter's name, email, and URL.
  2074 	 *
  1706 	 *
  2075 	 * @since 3.1.0
  1707 	 * @since 3.1.0
  2076 	 *
  1708 	 *
  2077 	 * @param string $comment_author       Comment author's name.
  1709 	 * @param array $comment_author_data {
  2078 	 * @param string $comment_author_email Comment author's email.
  1710 	 *     An array of current commenter variables.
  2079 	 * @param string $comment_author_url   Comment author's URL.
  1711 	 *
       
  1712 	 *     @type string $comment_author       The name of the author of the comment. Default empty.
       
  1713 	 *     @type string $comment_author_email The email address of the `$comment_author`. Default empty.
       
  1714 	 *     @type string $comment_author_url   The URL address of the `$comment_author`. Default empty.
       
  1715 	 * }
  2080 	 */
  1716 	 */
  2081 	return apply_filters( 'wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url') );
  1717 	return apply_filters( 'wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url') );
  2082 }
  1718 }
  2083 
  1719 
  2084 /**
  1720 /**
  2085  * Inserts a comment to the database.
  1721  * Inserts a comment into the database.
  2086  *
       
  2087  * The available comment data key names are 'comment_author_IP', 'comment_date',
       
  2088  * 'comment_date_gmt', 'comment_parent', 'comment_approved', and 'user_id'.
       
  2089  *
  1722  *
  2090  * @since 2.0.0
  1723  * @since 2.0.0
       
  1724  * @since 4.4.0 Introduced `$comment_meta` argument.
  2091  *
  1725  *
  2092  * @global wpdb $wpdb WordPress database abstraction object.
  1726  * @global wpdb $wpdb WordPress database abstraction object.
  2093  *
  1727  *
  2094  * @param array $commentdata Contains information on the comment.
  1728  * @param array $commentdata {
  2095  * @return int|bool The new comment's ID on success, false on failure.
  1729  *     Array of arguments for inserting a new comment.
       
  1730  *
       
  1731  *     @type string     $comment_agent        The HTTP user agent of the `$comment_author` when
       
  1732  *                                            the comment was submitted. Default empty.
       
  1733  *     @type int|string $comment_approved     Whether the comment has been approved. Default 1.
       
  1734  *     @type string     $comment_author       The name of the author of the comment. Default empty.
       
  1735  *     @type string     $comment_author_email The email address of the `$comment_author`. Default empty.
       
  1736  *     @type string     $comment_author_IP    The IP address of the `$comment_author`. Default empty.
       
  1737  *     @type string     $comment_author_url   The URL address of the `$comment_author`. Default empty.
       
  1738  *     @type string     $comment_content      The content of the comment. Default empty.
       
  1739  *     @type string     $comment_date         The date the comment was submitted. To set the date
       
  1740  *                                            manually, `$comment_date_gmt` must also be specified.
       
  1741  *                                            Default is the current time.
       
  1742  *     @type string     $comment_date_gmt     The date the comment was submitted in the GMT timezone.
       
  1743  *                                            Default is `$comment_date` in the site's GMT timezone.
       
  1744  *     @type int        $comment_karma        The karma of the comment. Default 0.
       
  1745  *     @type int        $comment_parent       ID of this comment's parent, if any. Default 0.
       
  1746  *     @type int        $comment_post_ID      ID of the post that relates to the comment, if any.
       
  1747  *                                            Default 0.
       
  1748  *     @type string     $comment_type         Comment type. Default empty.
       
  1749  *     @type array      $comment_meta         Optional. Array of key/value pairs to be stored in commentmeta for the
       
  1750  *                                            new comment.
       
  1751  *     @type int        $user_id              ID of the user who submitted the comment. Default 0.
       
  1752  * }
       
  1753  * @return int|false The new comment's ID on success, false on failure.
  2096  */
  1754  */
  2097 function wp_insert_comment( $commentdata ) {
  1755 function wp_insert_comment( $commentdata ) {
  2098 	global $wpdb;
  1756 	global $wpdb;
  2099 	$data = wp_unslash( $commentdata );
  1757 	$data = wp_unslash( $commentdata );
  2100 
  1758 
  2104 	$comment_author_IP    = ! isset( $data['comment_author_IP'] )    ? '' : $data['comment_author_IP'];
  1762 	$comment_author_IP    = ! isset( $data['comment_author_IP'] )    ? '' : $data['comment_author_IP'];
  2105 
  1763 
  2106 	$comment_date     = ! isset( $data['comment_date'] )     ? current_time( 'mysql' )            : $data['comment_date'];
  1764 	$comment_date     = ! isset( $data['comment_date'] )     ? current_time( 'mysql' )            : $data['comment_date'];
  2107 	$comment_date_gmt = ! isset( $data['comment_date_gmt'] ) ? get_gmt_from_date( $comment_date ) : $data['comment_date_gmt'];
  1765 	$comment_date_gmt = ! isset( $data['comment_date_gmt'] ) ? get_gmt_from_date( $comment_date ) : $data['comment_date_gmt'];
  2108 
  1766 
  2109 	$comment_post_ID  = ! isset( $data['comment_post_ID'] )  ? '' : $data['comment_post_ID'];
  1767 	$comment_post_ID  = ! isset( $data['comment_post_ID'] )  ? 0  : $data['comment_post_ID'];
  2110 	$comment_content  = ! isset( $data['comment_content'] )  ? '' : $data['comment_content'];
  1768 	$comment_content  = ! isset( $data['comment_content'] )  ? '' : $data['comment_content'];
  2111 	$comment_karma    = ! isset( $data['comment_karma'] )    ? 0  : $data['comment_karma'];
  1769 	$comment_karma    = ! isset( $data['comment_karma'] )    ? 0  : $data['comment_karma'];
  2112 	$comment_approved = ! isset( $data['comment_approved'] ) ? 1  : $data['comment_approved'];
  1770 	$comment_approved = ! isset( $data['comment_approved'] ) ? 1  : $data['comment_approved'];
  2113 	$comment_agent    = ! isset( $data['comment_agent'] )    ? '' : $data['comment_agent'];
  1771 	$comment_agent    = ! isset( $data['comment_agent'] )    ? '' : $data['comment_agent'];
  2114 	$comment_type     = ! isset( $data['comment_type'] )     ? '' : $data['comment_type'];
  1772 	$comment_type     = ! isset( $data['comment_type'] )     ? '' : $data['comment_type'];
  2123 
  1781 
  2124 	$id = (int) $wpdb->insert_id;
  1782 	$id = (int) $wpdb->insert_id;
  2125 
  1783 
  2126 	if ( $comment_approved == 1 ) {
  1784 	if ( $comment_approved == 1 ) {
  2127 		wp_update_comment_count( $comment_post_ID );
  1785 		wp_update_comment_count( $comment_post_ID );
  2128 	}
  1786 
       
  1787 		foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
       
  1788 			wp_cache_delete( "lastcommentmodified:$timezone", 'timeinfo' );
       
  1789 		}
       
  1790 	}
       
  1791 
       
  1792 	clean_comment_cache( $id );
       
  1793 
  2129 	$comment = get_comment( $id );
  1794 	$comment = get_comment( $id );
       
  1795 
       
  1796 	// If metadata is provided, store it.
       
  1797 	if ( isset( $commentdata['comment_meta'] ) && is_array( $commentdata['comment_meta'] ) ) {
       
  1798 		foreach ( $commentdata['comment_meta'] as $meta_key => $meta_value ) {
       
  1799 			add_comment_meta( $comment->comment_ID, $meta_key, $meta_value, true );
       
  1800 		}
       
  1801 	}
  2130 
  1802 
  2131 	/**
  1803 	/**
  2132 	 * Fires immediately after a comment is inserted into the database.
  1804 	 * Fires immediately after a comment is inserted into the database.
  2133 	 *
  1805 	 *
  2134 	 * @since 2.8.0
  1806 	 * @since 2.8.0
  2135 	 *
  1807 	 *
  2136 	 * @param int $id      The comment ID.
  1808 	 * @param int        $id      The comment ID.
  2137 	 * @param obj $comment Comment object.
  1809 	 * @param WP_Comment $comment Comment object.
  2138 	 */
  1810 	 */
  2139 	do_action( 'wp_insert_comment', $id, $comment );
  1811 	do_action( 'wp_insert_comment', $id, $comment );
  2140 
       
  2141 	wp_cache_set( 'last_changed', microtime(), 'comment' );
       
  2142 
  1812 
  2143 	return $id;
  1813 	return $id;
  2144 }
  1814 }
  2145 
  1815 
  2146 /**
  1816 /**
  2156  * @return array Parsed comment information.
  1826  * @return array Parsed comment information.
  2157  */
  1827  */
  2158 function wp_filter_comment($commentdata) {
  1828 function wp_filter_comment($commentdata) {
  2159 	if ( isset( $commentdata['user_ID'] ) ) {
  1829 	if ( isset( $commentdata['user_ID'] ) ) {
  2160 		/**
  1830 		/**
  2161 		 * Filter the comment author's user id before it is set.
  1831 		 * Filters the comment author's user id before it is set.
  2162 		 *
  1832 		 *
  2163 		 * The first time this filter is evaluated, 'user_ID' is checked
  1833 		 * The first time this filter is evaluated, 'user_ID' is checked
  2164 		 * (for back-compat), followed by the standard 'user_id' value.
  1834 		 * (for back-compat), followed by the standard 'user_id' value.
  2165 		 *
  1835 		 *
  2166 		 * @since 1.5.0
  1836 		 * @since 1.5.0
  2172 		/** This filter is documented in wp-includes/comment.php */
  1842 		/** This filter is documented in wp-includes/comment.php */
  2173 		$commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_id'] );
  1843 		$commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_id'] );
  2174 	}
  1844 	}
  2175 
  1845 
  2176 	/**
  1846 	/**
  2177 	 * Filter the comment author's browser user agent before it is set.
  1847 	 * Filters the comment author's browser user agent before it is set.
  2178 	 *
  1848 	 *
  2179 	 * @since 1.5.0
  1849 	 * @since 1.5.0
  2180 	 *
  1850 	 *
  2181 	 * @param int $comment_agent The comment author's browser user agent.
  1851 	 * @param string $comment_agent The comment author's browser user agent.
  2182 	 */
  1852 	 */
  2183 	$commentdata['comment_agent'] = apply_filters( 'pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
  1853 	$commentdata['comment_agent'] = apply_filters( 'pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
  2184 	/** This filter is documented in wp-includes/comment.php */
  1854 	/** This filter is documented in wp-includes/comment.php */
  2185 	$commentdata['comment_author'] = apply_filters( 'pre_comment_author_name', $commentdata['comment_author'] );
  1855 	$commentdata['comment_author'] = apply_filters( 'pre_comment_author_name', $commentdata['comment_author'] );
  2186 	/**
  1856 	/**
  2187 	 * Filter the comment content before it is set.
  1857 	 * Filters the comment content before it is set.
  2188 	 *
  1858 	 *
  2189 	 * @since 1.5.0
  1859 	 * @since 1.5.0
  2190 	 *
  1860 	 *
  2191 	 * @param int $comment_content The comment content.
  1861 	 * @param string $comment_content The comment content.
  2192 	 */
  1862 	 */
  2193 	$commentdata['comment_content'] = apply_filters( 'pre_comment_content', $commentdata['comment_content'] );
  1863 	$commentdata['comment_content'] = apply_filters( 'pre_comment_content', $commentdata['comment_content'] );
  2194 	/**
  1864 	/**
  2195 	 * Filter the comment author's IP before it is set.
  1865 	 * Filters the comment author's IP address before it is set.
  2196 	 *
  1866 	 *
  2197 	 * @since 1.5.0
  1867 	 * @since 1.5.0
  2198 	 *
  1868 	 *
  2199 	 * @param int $comment_author_ip The comment author's IP.
  1869 	 * @param string $comment_author_ip The comment author's IP address.
  2200 	 */
  1870 	 */
  2201 	$commentdata['comment_author_IP'] = apply_filters( 'pre_comment_user_ip', $commentdata['comment_author_IP'] );
  1871 	$commentdata['comment_author_IP'] = apply_filters( 'pre_comment_user_ip', $commentdata['comment_author_IP'] );
  2202 	/** This filter is documented in wp-includes/comment.php */
  1872 	/** This filter is documented in wp-includes/comment.php */
  2203 	$commentdata['comment_author_url'] = apply_filters( 'pre_comment_author_url', $commentdata['comment_author_url'] );
  1873 	$commentdata['comment_author_url'] = apply_filters( 'pre_comment_author_url', $commentdata['comment_author_url'] );
  2204 	/** This filter is documented in wp-includes/comment.php */
  1874 	/** This filter is documented in wp-includes/comment.php */
  2227 
  1897 
  2228 /**
  1898 /**
  2229  * Adds a new comment to the database.
  1899  * Adds a new comment to the database.
  2230  *
  1900  *
  2231  * Filters new comment to ensure that the fields are sanitized and valid before
  1901  * Filters new comment to ensure that the fields are sanitized and valid before
  2232  * inserting comment into database. Calls 'comment_post' action with comment ID
  1902  * inserting comment into database. Calls {@see 'comment_post'} action with comment ID
  2233  * and whether comment is approved by WordPress. Also has 'preprocess_comment'
  1903  * and whether comment is approved by WordPress. Also has {@see 'preprocess_comment'}
  2234  * filter for processing the comment data before the function handles it.
  1904  * filter for processing the comment data before the function handles it.
  2235  *
  1905  *
  2236  * We use REMOTE_ADDR here directly. If you are behind a proxy, you should ensure
  1906  * We use `REMOTE_ADDR` here directly. If you are behind a proxy, you should ensure
  2237  * that it is properly set, such as in wp-config.php, for your environment.
  1907  * that it is properly set, such as in wp-config.php, for your environment.
       
  1908  *
  2238  * See {@link https://core.trac.wordpress.org/ticket/9235}
  1909  * See {@link https://core.trac.wordpress.org/ticket/9235}
  2239  *
  1910  *
  2240  * @since 1.5.0
  1911  * @since 1.5.0
  2241  * @param array $commentdata Contains information on the comment.
  1912  * @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
  2242  * @return int|bool The ID of the comment on success, false on failure.
  1913  * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function to
  2243  */
  1914  *              return a WP_Error object instead of dying.
  2244 function wp_new_comment( $commentdata ) {
  1915  *
       
  1916  * @see wp_insert_comment()
       
  1917  * @global wpdb $wpdb WordPress database abstraction object.
       
  1918  *
       
  1919  * @param array $commentdata {
       
  1920  *     Comment data.
       
  1921  *
       
  1922  *     @type string $comment_author       The name of the comment author.
       
  1923  *     @type string $comment_author_email The comment author email address.
       
  1924  *     @type string $comment_author_url   The comment author URL.
       
  1925  *     @type string $comment_content      The content of the comment.
       
  1926  *     @type string $comment_date         The date the comment was submitted. Default is the current time.
       
  1927  *     @type string $comment_date_gmt     The date the comment was submitted in the GMT timezone.
       
  1928  *                                        Default is `$comment_date` in the GMT timezone.
       
  1929  *     @type int    $comment_parent       The ID of this comment's parent, if any. Default 0.
       
  1930  *     @type int    $comment_post_ID      The ID of the post that relates to the comment.
       
  1931  *     @type int    $user_id              The ID of the user who submitted the comment. Default 0.
       
  1932  *     @type int    $user_ID              Kept for backward-compatibility. Use `$user_id` instead.
       
  1933  *     @type string $comment_agent        Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
       
  1934  *                                        in the `$_SERVER` superglobal sent in the original request.
       
  1935  *     @type string $comment_author_IP    Comment author IP address in IPv4 format. Default is the value of
       
  1936  *                                        'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
       
  1937  * }
       
  1938  * @param bool $avoid_die Should errors be returned as WP_Error objects instead of
       
  1939  *                        executing wp_die()? Default false.
       
  1940  * @return int|false|WP_Error The ID of the comment on success, false or WP_Error on failure.
       
  1941  */
       
  1942 function wp_new_comment( $commentdata, $avoid_die = false ) {
  2245 	global $wpdb;
  1943 	global $wpdb;
  2246 
  1944 
  2247 	if ( isset( $commentdata['user_ID'] ) ) {
  1945 	if ( isset( $commentdata['user_ID'] ) ) {
  2248 		$commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
  1946 		$commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
  2249 	}
  1947 	}
  2250 
  1948 
  2251 	$prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
  1949 	$prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
  2252 
  1950 
  2253 	/**
  1951 	/**
  2254 	 * Filter a comment's data before it is sanitized and inserted into the database.
  1952 	 * Filters a comment's data before it is sanitized and inserted into the database.
  2255 	 *
  1953 	 *
  2256 	 * @since 1.5.0
  1954 	 * @since 1.5.0
  2257 	 *
  1955 	 *
  2258 	 * @param array $commentdata Comment data.
  1956 	 * @param array $commentdata Comment data.
  2259 	 */
  1957 	 */
  2268 
  1966 
  2269 	$commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
  1967 	$commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
  2270 	$parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
  1968 	$parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
  2271 	$commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
  1969 	$commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
  2272 
  1970 
  2273 	$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] );
  1971 	if ( ! isset( $commentdata['comment_author_IP'] ) ) {
  2274 	$commentdata['comment_agent']     = isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : '';
  1972 		$commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
       
  1973 	}
       
  1974 	$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
       
  1975 
       
  1976 	if ( ! isset( $commentdata['comment_agent'] ) ) {
       
  1977 		$commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT']: '';
       
  1978 	}
       
  1979 	$commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 );
  2275 
  1980 
  2276 	if ( empty( $commentdata['comment_date'] ) ) {
  1981 	if ( empty( $commentdata['comment_date'] ) ) {
  2277 		$commentdata['comment_date'] = current_time('mysql');
  1982 		$commentdata['comment_date'] = current_time('mysql');
  2278 	}
  1983 	}
  2279 
  1984 
  2281 		$commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
  1986 		$commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
  2282 	}
  1987 	}
  2283 
  1988 
  2284 	$commentdata = wp_filter_comment($commentdata);
  1989 	$commentdata = wp_filter_comment($commentdata);
  2285 
  1990 
  2286 	$commentdata['comment_approved'] = wp_allow_comment($commentdata);
  1991 	$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
       
  1992 	if ( is_wp_error( $commentdata['comment_approved'] ) ) {
       
  1993 		return $commentdata['comment_approved'];
       
  1994 	}
  2287 
  1995 
  2288 	$comment_ID = wp_insert_comment($commentdata);
  1996 	$comment_ID = wp_insert_comment($commentdata);
  2289 	if ( ! $comment_ID ) {
  1997 	if ( ! $comment_ID ) {
  2290 		$fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
  1998 		$fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
  2291 
  1999 
  2292 		foreach( $fields as $field ) {
  2000 		foreach ( $fields as $field ) {
  2293 			if ( isset( $commentdata[ $field ] ) ) {
  2001 			if ( isset( $commentdata[ $field ] ) ) {
  2294 				$commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
  2002 				$commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
  2295 			}
  2003 			}
  2296 		}
  2004 		}
  2297 
  2005 
  2298 		$commentdata = wp_filter_comment( $commentdata );
  2006 		$commentdata = wp_filter_comment( $commentdata );
  2299 
  2007 
  2300 		$commentdata['comment_approved'] = wp_allow_comment( $commentdata );
  2008 		$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
       
  2009 		if ( is_wp_error( $commentdata['comment_approved'] ) ) {
       
  2010 			return $commentdata['comment_approved'];
       
  2011 		}
  2301 
  2012 
  2302 		$comment_ID = wp_insert_comment( $commentdata );
  2013 		$comment_ID = wp_insert_comment( $commentdata );
  2303 		if ( ! $comment_ID ) {
  2014 		if ( ! $comment_ID ) {
  2304 			return false;
  2015 			return false;
  2305 		}
  2016 		}
  2307 
  2018 
  2308 	/**
  2019 	/**
  2309 	 * Fires immediately after a comment is inserted into the database.
  2020 	 * Fires immediately after a comment is inserted into the database.
  2310 	 *
  2021 	 *
  2311 	 * @since 1.2.0
  2022 	 * @since 1.2.0
  2312 	 *
  2023 	 * @since 4.5.0 The `$commentdata` parameter was added.
  2313 	 * @param int $comment_ID       The comment ID.
  2024 	 *
  2314 	 * @param int $comment_approved 1 (true) if the comment is approved, 0 (false) if not.
  2025 	 * @param int        $comment_ID       The comment ID.
  2315 	 */
  2026 	 * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
  2316 	do_action( 'comment_post', $comment_ID, $commentdata['comment_approved'] );
  2027 	 * @param array      $commentdata      Comment data.
  2317 
  2028 	 */
  2318 	if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching
  2029 	do_action( 'comment_post', $comment_ID, $commentdata['comment_approved'], $commentdata );
  2319 		if ( '0' == $commentdata['comment_approved'] ) {
       
  2320 			wp_notify_moderator( $comment_ID );
       
  2321 		}
       
  2322 
       
  2323 		// wp_notify_postauthor() checks if notifying the author of their own comment.
       
  2324 		// By default, it won't, but filters can override this.
       
  2325 		if ( get_option( 'comments_notify' ) && $commentdata['comment_approved'] ) {
       
  2326 			wp_notify_postauthor( $comment_ID );
       
  2327 		}
       
  2328 	}
       
  2329 
  2030 
  2330 	return $comment_ID;
  2031 	return $comment_ID;
  2331 }
  2032 }
  2332 
  2033 
  2333 /**
  2034 /**
       
  2035  * Send a comment moderation notification to the comment moderator.
       
  2036  *
       
  2037  * @since 4.4.0
       
  2038  *
       
  2039  * @param int $comment_ID ID of the comment.
       
  2040  * @return bool True on success, false on failure.
       
  2041  */
       
  2042 function wp_new_comment_notify_moderator( $comment_ID ) {
       
  2043 	$comment = get_comment( $comment_ID );
       
  2044 
       
  2045 	// Only send notifications for pending comments.
       
  2046 	$maybe_notify = ( '0' == $comment->comment_approved );
       
  2047 
       
  2048 	/** This filter is documented in wp-includes/comment.php */
       
  2049 	$maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_ID );
       
  2050 
       
  2051 	if ( ! $maybe_notify ) {
       
  2052 		return false;
       
  2053 	}
       
  2054 
       
  2055 	return wp_notify_moderator( $comment_ID );
       
  2056 }
       
  2057 
       
  2058 /**
       
  2059  * Send a notification of a new comment to the post author.
       
  2060  *
       
  2061  * @since 4.4.0
       
  2062  *
       
  2063  * Uses the {@see 'notify_post_author'} filter to determine whether the post author
       
  2064  * should be notified when a new comment is added, overriding site setting.
       
  2065  *
       
  2066  * @param int $comment_ID Comment ID.
       
  2067  * @return bool True on success, false on failure.
       
  2068  */
       
  2069 function wp_new_comment_notify_postauthor( $comment_ID ) {
       
  2070 	$comment = get_comment( $comment_ID );
       
  2071 
       
  2072 	$maybe_notify = get_option( 'comments_notify' );
       
  2073 
       
  2074 	/**
       
  2075 	 * Filters whether to send the post author new comment notification emails,
       
  2076 	 * overriding the site setting.
       
  2077 	 *
       
  2078 	 * @since 4.4.0
       
  2079 	 *
       
  2080 	 * @param bool $maybe_notify Whether to notify the post author about the new comment.
       
  2081 	 * @param int  $comment_ID   The ID of the comment for the notification.
       
  2082 	 */
       
  2083 	$maybe_notify = apply_filters( 'notify_post_author', $maybe_notify, $comment_ID );
       
  2084 
       
  2085 	/*
       
  2086 	 * wp_notify_postauthor() checks if notifying the author of their own comment.
       
  2087 	 * By default, it won't, but filters can override this.
       
  2088 	 */
       
  2089 	if ( ! $maybe_notify ) {
       
  2090 		return false;
       
  2091 	}
       
  2092 
       
  2093 	// Only send notifications for approved comments.
       
  2094 	if ( ! isset( $comment->comment_approved ) || '1' != $comment->comment_approved ) {
       
  2095 		return false;
       
  2096 	}
       
  2097 
       
  2098 	return wp_notify_postauthor( $comment_ID );
       
  2099 }
       
  2100 
       
  2101 /**
  2334  * Sets the status of a comment.
  2102  * Sets the status of a comment.
  2335  *
  2103  *
  2336  * The 'wp_set_comment_status' action is called after the comment is handled.
  2104  * The {@see 'wp_set_comment_status'} action is called after the comment is handled.
  2337  * If the comment status is not in the list, then false is returned.
  2105  * If the comment status is not in the list, then false is returned.
  2338  *
  2106  *
  2339  * @since 1.0.0
  2107  * @since 1.0.0
  2340  *
  2108  *
  2341  * @param int $comment_id Comment ID.
  2109  * @global wpdb $wpdb WordPress database abstraction object.
  2342  * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
  2110  *
  2343  * @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default is false.
  2111  * @param int|WP_Comment $comment_id     Comment ID or WP_Comment object.
       
  2112  * @param string         $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
       
  2113  * @param bool           $wp_error       Whether to return a WP_Error object if there is a failure. Default is false.
  2344  * @return bool|WP_Error True on success, false or WP_Error on failure.
  2114  * @return bool|WP_Error True on success, false or WP_Error on failure.
  2345  */
  2115  */
  2346 function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
  2116 function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
  2347 	global $wpdb;
  2117 	global $wpdb;
  2348 
  2118 
  2352 			$status = '0';
  2122 			$status = '0';
  2353 			break;
  2123 			break;
  2354 		case 'approve':
  2124 		case 'approve':
  2355 		case '1':
  2125 		case '1':
  2356 			$status = '1';
  2126 			$status = '1';
  2357 			if ( get_option('comments_notify') ) {
  2127 			add_action( 'wp_set_comment_status', 'wp_new_comment_notify_postauthor' );
  2358 				wp_notify_postauthor( $comment_id );
       
  2359 			}
       
  2360 			break;
  2128 			break;
  2361 		case 'spam':
  2129 		case 'spam':
  2362 			$status = 'spam';
  2130 			$status = 'spam';
  2363 			break;
  2131 			break;
  2364 		case 'trash':
  2132 		case 'trash':
  2368 			return false;
  2136 			return false;
  2369 	}
  2137 	}
  2370 
  2138 
  2371 	$comment_old = clone get_comment($comment_id);
  2139 	$comment_old = clone get_comment($comment_id);
  2372 
  2140 
  2373 	if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array('comment_ID' => $comment_id) ) ) {
  2141 	if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array( 'comment_ID' => $comment_old->comment_ID ) ) ) {
  2374 		if ( $wp_error )
  2142 		if ( $wp_error )
  2375 			return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
  2143 			return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
  2376 		else
  2144 		else
  2377 			return false;
  2145 			return false;
  2378 	}
  2146 	}
  2379 
  2147 
  2380 	clean_comment_cache($comment_id);
  2148 	clean_comment_cache( $comment_old->comment_ID );
  2381 
  2149 
  2382 	$comment = get_comment($comment_id);
  2150 	$comment = get_comment( $comment_old->comment_ID );
  2383 
  2151 
  2384 	/**
  2152 	/**
  2385 	 * Fires immediately before transitioning a comment's status from one to another
  2153 	 * Fires immediately before transitioning a comment's status from one to another
  2386 	 * in the database.
  2154 	 * in the database.
  2387 	 *
  2155 	 *
  2389 	 *
  2157 	 *
  2390 	 * @param int         $comment_id     Comment ID.
  2158 	 * @param int         $comment_id     Comment ID.
  2391 	 * @param string|bool $comment_status Current comment status. Possible values include
  2159 	 * @param string|bool $comment_status Current comment status. Possible values include
  2392 	 *                                    'hold', 'approve', 'spam', 'trash', or false.
  2160 	 *                                    'hold', 'approve', 'spam', 'trash', or false.
  2393 	 */
  2161 	 */
  2394 	do_action( 'wp_set_comment_status', $comment_id, $comment_status );
  2162 	do_action( 'wp_set_comment_status', $comment->comment_ID, $comment_status );
  2395 
  2163 
  2396 	wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
  2164 	wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
  2397 
  2165 
  2398 	wp_update_comment_count($comment->comment_post_ID);
  2166 	wp_update_comment_count($comment->comment_post_ID);
  2399 
  2167 
  2404  * Updates an existing comment in the database.
  2172  * Updates an existing comment in the database.
  2405  *
  2173  *
  2406  * Filters the comment and makes sure certain fields are valid before updating.
  2174  * Filters the comment and makes sure certain fields are valid before updating.
  2407  *
  2175  *
  2408  * @since 2.0.0
  2176  * @since 2.0.0
       
  2177  * @since 4.9.0 Add updating comment meta during comment update.
  2409  *
  2178  *
  2410  * @global wpdb $wpdb WordPress database abstraction object.
  2179  * @global wpdb $wpdb WordPress database abstraction object.
  2411  *
  2180  *
  2412  * @param array $commentarr Contains information on the comment.
  2181  * @param array $commentarr Contains information on the comment.
  2413  * @return int Comment was updated if value is 1, or was not updated if value is 0.
  2182  * @return int Comment was updated if value is 1, or was not updated if value is 0.
  2420 	if ( empty( $comment ) ) {
  2189 	if ( empty( $comment ) ) {
  2421 		return 0;
  2190 		return 0;
  2422 	}
  2191 	}
  2423 
  2192 
  2424 	// Make sure that the comment post ID is valid (if specified).
  2193 	// Make sure that the comment post ID is valid (if specified).
  2425 	if ( isset( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
  2194 	if ( ! empty( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
  2426 		return 0;
  2195 		return 0;
  2427 	}
  2196 	}
  2428 
  2197 
  2429 	// Escape data pulled from DB.
  2198 	// Escape data pulled from DB.
  2430 	$comment = wp_slash($comment);
  2199 	$comment = wp_slash($comment);
  2438 
  2207 
  2439 	// Now extract the merged array.
  2208 	// Now extract the merged array.
  2440 	$data = wp_unslash( $commentarr );
  2209 	$data = wp_unslash( $commentarr );
  2441 
  2210 
  2442 	/**
  2211 	/**
  2443 	 * Filter the comment content before it is updated in the database.
  2212 	 * Filters the comment content before it is updated in the database.
  2444 	 *
  2213 	 *
  2445 	 * @since 1.5.0
  2214 	 * @since 1.5.0
  2446 	 *
  2215 	 *
  2447 	 * @param string $comment_content The comment data.
  2216 	 * @param string $comment_content The comment data.
  2448 	 */
  2217 	 */
  2458 		$data['comment_approved'] = 1;
  2227 		$data['comment_approved'] = 1;
  2459 	}
  2228 	}
  2460 
  2229 
  2461 	$comment_ID = $data['comment_ID'];
  2230 	$comment_ID = $data['comment_ID'];
  2462 	$comment_post_ID = $data['comment_post_ID'];
  2231 	$comment_post_ID = $data['comment_post_ID'];
  2463 	$keys = array( 'comment_post_ID', 'comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_type', 'comment_parent', 'user_id' );
  2232 
       
  2233 	/**
       
  2234 	 * Filters the comment data immediately before it is updated in the database.
       
  2235 	 *
       
  2236 	 * Note: data being passed to the filter is already unslashed.
       
  2237 	 *
       
  2238 	 * @since 4.7.0
       
  2239 	 *
       
  2240 	 * @param array $data       The new, processed comment data.
       
  2241 	 * @param array $comment    The old, unslashed comment data.
       
  2242 	 * @param array $commentarr The new, raw comment data.
       
  2243 	 */
       
  2244 	$data = apply_filters( 'wp_update_comment_data', $data, $comment, $commentarr );
       
  2245 
       
  2246 	$keys = array( 'comment_post_ID', 'comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_type', 'comment_parent', 'user_id', 'comment_agent', 'comment_author_IP' );
  2464 	$data = wp_array_slice_assoc( $data, $keys );
  2247 	$data = wp_array_slice_assoc( $data, $keys );
       
  2248 
  2465 	$rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
  2249 	$rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
       
  2250 
       
  2251 	// If metadata is provided, store it.
       
  2252 	if ( isset( $commentarr['comment_meta'] ) && is_array( $commentarr['comment_meta'] ) ) {
       
  2253 		foreach ( $commentarr['comment_meta'] as $meta_key => $meta_value ) {
       
  2254 			update_comment_meta( $comment_ID, $meta_key, $meta_value );
       
  2255 		}
       
  2256 	}
  2466 
  2257 
  2467 	clean_comment_cache( $comment_ID );
  2258 	clean_comment_cache( $comment_ID );
  2468 	wp_update_comment_count( $comment_post_ID );
  2259 	wp_update_comment_count( $comment_post_ID );
  2469 	/**
  2260 	/**
  2470 	 * Fires immediately after a comment is updated in the database.
  2261 	 * Fires immediately after a comment is updated in the database.
  2471 	 *
  2262 	 *
  2472 	 * The hook also fires immediately before comment status transition hooks are fired.
  2263 	 * The hook also fires immediately before comment status transition hooks are fired.
  2473 	 *
  2264 	 *
  2474 	 * @since 1.2.0
  2265 	 * @since 1.2.0
  2475 	 *
  2266 	 * @since 4.6.0 Added the `$data` parameter.
  2476 	 * @param int $comment_ID The comment ID.
  2267 	 *
  2477 	 */
  2268 	 * @param int   $comment_ID The comment ID.
  2478 	do_action( 'edit_comment', $comment_ID );
  2269 	 * @param array $data       Comment data.
       
  2270 	 */
       
  2271 	do_action( 'edit_comment', $comment_ID, $data );
  2479 	$comment = get_comment($comment_ID);
  2272 	$comment = get_comment($comment_ID);
  2480 	wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
  2273 	wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
  2481 	return $rval;
  2274 	return $rval;
  2482 }
  2275 }
  2483 
  2276 
  2520  * IDs will be updated along with the current $post_id.
  2313  * IDs will be updated along with the current $post_id.
  2521  *
  2314  *
  2522  * @since 2.1.0
  2315  * @since 2.1.0
  2523  * @see wp_update_comment_count_now() For what could cause a false return value
  2316  * @see wp_update_comment_count_now() For what could cause a false return value
  2524  *
  2317  *
  2525  * @param int $post_id Post ID
  2318  * @staticvar array $_deferred
  2526  * @param bool $do_deferred Whether to process previously deferred post comment counts
  2319  *
  2527  * @return bool|null True on success, false on failure
  2320  * @param int|null $post_id     Post ID.
       
  2321  * @param bool     $do_deferred Optional. Whether to process previously deferred
       
  2322  *                              post comment counts. Default false.
       
  2323  * @return bool|void True on success, false on failure or if post with ID does
       
  2324  *                   not exist.
  2528  */
  2325  */
  2529 function wp_update_comment_count($post_id, $do_deferred=false) {
  2326 function wp_update_comment_count($post_id, $do_deferred=false) {
  2530 	static $_deferred = array();
  2327 	static $_deferred = array();
       
  2328 
       
  2329 	if ( empty( $post_id ) && ! $do_deferred ) {
       
  2330 		return false;
       
  2331 	}
  2531 
  2332 
  2532 	if ( $do_deferred ) {
  2333 	if ( $do_deferred ) {
  2533 		$_deferred = array_unique($_deferred);
  2334 		$_deferred = array_unique($_deferred);
  2534 		foreach ( $_deferred as $i => $_post_id ) {
  2335 		foreach ( $_deferred as $i => $_post_id ) {
  2535 			wp_update_comment_count_now($_post_id);
  2336 			wp_update_comment_count_now($_post_id);
  2560 function wp_update_comment_count_now($post_id) {
  2361 function wp_update_comment_count_now($post_id) {
  2561 	global $wpdb;
  2362 	global $wpdb;
  2562 	$post_id = (int) $post_id;
  2363 	$post_id = (int) $post_id;
  2563 	if ( !$post_id )
  2364 	if ( !$post_id )
  2564 		return false;
  2365 		return false;
       
  2366 
       
  2367 	wp_cache_delete( 'comments-0', 'counts' );
       
  2368 	wp_cache_delete( "comments-{$post_id}", 'counts' );
       
  2369 
  2565 	if ( !$post = get_post($post_id) )
  2370 	if ( !$post = get_post($post_id) )
  2566 		return false;
  2371 		return false;
  2567 
  2372 
  2568 	$old = (int) $post->comment_count;
  2373 	$old = (int) $post->comment_count;
  2569 	$new = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id) );
  2374 
       
  2375 	/**
       
  2376 	 * Filters a post's comment count before it is updated in the database.
       
  2377 	 *
       
  2378 	 * @since 4.5.0
       
  2379 	 *
       
  2380 	 * @param int $new     The new comment count. Default null.
       
  2381 	 * @param int $old     The old comment count.
       
  2382 	 * @param int $post_id Post ID.
       
  2383 	 */
       
  2384 	$new = apply_filters( 'pre_wp_update_comment_count_now', null, $old, $post_id );
       
  2385 
       
  2386 	if ( is_null( $new ) ) {
       
  2387 		$new = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id ) );
       
  2388 	} else {
       
  2389 		$new = (int) $new;
       
  2390 	}
       
  2391 
  2570 	$wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
  2392 	$wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
  2571 
  2393 
  2572 	clean_post_cache( $post );
  2394 	clean_post_cache( $post );
  2573 
  2395 
  2574 	/**
  2396 	/**
  2604  * @param int $deprecated Not Used.
  2426  * @param int $deprecated Not Used.
  2605  * @return false|string False on failure, string containing URI on success.
  2427  * @return false|string False on failure, string containing URI on success.
  2606  */
  2428  */
  2607 function discover_pingback_server_uri( $url, $deprecated = '' ) {
  2429 function discover_pingback_server_uri( $url, $deprecated = '' ) {
  2608 	if ( !empty( $deprecated ) )
  2430 	if ( !empty( $deprecated ) )
  2609 		_deprecated_argument( __FUNCTION__, '2.7' );
  2431 		_deprecated_argument( __FUNCTION__, '2.7.0' );
  2610 
  2432 
  2611 	$pingback_str_dquote = 'rel="pingback"';
  2433 	$pingback_str_dquote = 'rel="pingback"';
  2612 	$pingback_str_squote = 'rel=\'pingback\'';
  2434 	$pingback_str_squote = 'rel=\'pingback\'';
  2613 
  2435 
  2614 	/** @todo Should use Filter Extension or custom preg_match instead. */
  2436 	/** @todo Should use Filter Extension or custom preg_match instead. */
  2615 	$parsed_url = parse_url($url);
  2437 	$parsed_url = parse_url($url);
  2616 
  2438 
  2617 	if ( ! isset( $parsed_url['host'] ) ) // Not an URL. This should never happen.
  2439 	if ( ! isset( $parsed_url['host'] ) ) // Not a URL. This should never happen.
  2618 		return false;
  2440 		return false;
  2619 
  2441 
  2620 	//Do not search for a pingback server on our own uploads
  2442 	//Do not search for a pingback server on our own uploads
  2621 	$uploads_dir = wp_upload_dir();
  2443 	$uploads_dir = wp_get_upload_dir();
  2622 	if ( 0 === strpos($url, $uploads_dir['baseurl']) )
  2444 	if ( 0 === strpos($url, $uploads_dir['baseurl']) )
  2623 		return false;
  2445 		return false;
  2624 
  2446 
  2625 	$response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
  2447 	$response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
  2626 
  2448 
  2696 
  2518 
  2697 /**
  2519 /**
  2698  * Perform trackbacks.
  2520  * Perform trackbacks.
  2699  *
  2521  *
  2700  * @since 1.5.0
  2522  * @since 1.5.0
       
  2523  * @since 4.7.0 $post_id can be a WP_Post object.
  2701  *
  2524  *
  2702  * @global wpdb $wpdb WordPress database abstraction object.
  2525  * @global wpdb $wpdb WordPress database abstraction object.
  2703  *
  2526  *
  2704  * @param int $post_id Post ID to do trackbacks on.
  2527  * @param int|WP_Post $post_id Post object or ID to do trackbacks on.
  2705  */
  2528  */
  2706 function do_trackbacks($post_id) {
  2529 function do_trackbacks( $post_id ) {
  2707 	global $wpdb;
  2530 	global $wpdb;
  2708 
       
  2709 	$post = get_post( $post_id );
  2531 	$post = get_post( $post_id );
  2710 	$to_ping = get_to_ping($post_id);
  2532 	if ( ! $post ) {
  2711 	$pinged  = get_pung($post_id);
  2533 		return false;
  2712 	if ( empty($to_ping) ) {
  2534 	}
  2713 		$wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
  2535 
       
  2536 	$to_ping = get_to_ping( $post );
       
  2537 	$pinged  = get_pung( $post );
       
  2538 	if ( empty( $to_ping ) ) {
       
  2539 		$wpdb->update($wpdb->posts, array( 'to_ping' => '' ), array( 'ID' => $post->ID ) );
  2714 		return;
  2540 		return;
  2715 	}
  2541 	}
  2716 
  2542 
  2717 	if ( empty($post->post_excerpt) ) {
  2543 	if ( empty($post->post_excerpt) ) {
  2718 		/** This filter is documented in wp-includes/post-template.php */
  2544 		/** This filter is documented in wp-includes/post-template.php */
  2731 
  2557 
  2732 	if ( $to_ping ) {
  2558 	if ( $to_ping ) {
  2733 		foreach ( (array) $to_ping as $tb_ping ) {
  2559 		foreach ( (array) $to_ping as $tb_ping ) {
  2734 			$tb_ping = trim($tb_ping);
  2560 			$tb_ping = trim($tb_ping);
  2735 			if ( !in_array($tb_ping, $pinged) ) {
  2561 			if ( !in_array($tb_ping, $pinged) ) {
  2736 				trackback($tb_ping, $post_title, $excerpt, $post_id);
  2562 				trackback( $tb_ping, $post_title, $excerpt, $post->ID );
  2737 				$pinged[] = $tb_ping;
  2563 				$pinged[] = $tb_ping;
  2738 			} else {
  2564 			} else {
  2739 				$wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id) );
  2565 				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s,
       
  2566 					'')) WHERE ID = %d", $tb_ping, $post->ID ) );
  2740 			}
  2567 			}
  2741 		}
  2568 		}
  2742 	}
  2569 	}
  2743 }
  2570 }
  2744 
  2571 
  2765 
  2592 
  2766 /**
  2593 /**
  2767  * Pings back the links found in a post.
  2594  * Pings back the links found in a post.
  2768  *
  2595  *
  2769  * @since 0.71
  2596  * @since 0.71
  2770  * @uses $wp_version
  2597  * @since 4.7.0 $post_id can be a WP_Post object.
  2771  *
  2598  *
  2772  * @param string $content Post content to check for links.
  2599  * @param string $content Post content to check for links. If empty will retrieve from post.
  2773  * @param int $post_ID Post ID.
  2600  * @param int|WP_Post $post_id Post Object or ID.
  2774  */
  2601  */
  2775 function pingback($content, $post_ID) {
  2602 function pingback( $content, $post_id ) {
  2776 	global $wp_version;
  2603 	include_once( ABSPATH . WPINC . '/class-IXR.php' );
  2777 	include_once(ABSPATH . WPINC . '/class-IXR.php');
  2604 	include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );
  2778 	include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
       
  2779 
  2605 
  2780 	// original code by Mort (http://mort.mine.nu:8080)
  2606 	// original code by Mort (http://mort.mine.nu:8080)
  2781 	$post_links = array();
  2607 	$post_links = array();
  2782 
  2608 
  2783 	$pung = get_pung($post_ID);
  2609 	$post = get_post( $post_id );
       
  2610 	if ( ! $post ) {
       
  2611 		return;
       
  2612 	}
       
  2613 
       
  2614 	$pung = get_pung( $post );
       
  2615 
       
  2616 	if ( empty( $content ) ) {
       
  2617 		$content = $post->post_content;
       
  2618 	}
  2784 
  2619 
  2785 	// Step 1
  2620 	// Step 1
  2786 	// Parsing the post, external links (if any) are stored in the $post_links array
  2621 	// Parsing the post, external links (if any) are stored in the $post_links array
  2787 	$post_links_temp = wp_extract_urls( $content );
  2622 	$post_links_temp = wp_extract_urls( $content );
  2788 
  2623 
  2794 	// http://dummy-weblog.org/
  2629 	// http://dummy-weblog.org/
  2795 	// http://dummy-weblog.org/post.php
  2630 	// http://dummy-weblog.org/post.php
  2796 	// We don't wanna ping first and second types, even if they have a valid <link/>
  2631 	// We don't wanna ping first and second types, even if they have a valid <link/>
  2797 
  2632 
  2798 	foreach ( (array) $post_links_temp as $link_test ) :
  2633 	foreach ( (array) $post_links_temp as $link_test ) :
  2799 		if ( !in_array($link_test, $pung) && (url_to_postid($link_test) != $post_ID) // If we haven't pung it already and it isn't a link to itself
  2634 		if ( ! in_array( $link_test, $pung ) && ( url_to_postid( $link_test ) != $post->ID ) // If we haven't pung it already and it isn't a link to itself
  2800 				&& !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
  2635 				&& !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
  2801 			if ( $test = @parse_url($link_test) ) {
  2636 			if ( $test = @parse_url($link_test) ) {
  2802 				if ( isset($test['query']) )
  2637 				if ( isset($test['query']) )
  2803 					$post_links[] = $link_test;
  2638 					$post_links[] = $link_test;
  2804 				elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) )
  2639 				elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) )
  2811 	/**
  2646 	/**
  2812 	 * Fires just before pinging back links found in a post.
  2647 	 * Fires just before pinging back links found in a post.
  2813 	 *
  2648 	 *
  2814 	 * @since 2.0.0
  2649 	 * @since 2.0.0
  2815 	 *
  2650 	 *
  2816 	 * @param array &$post_links An array of post links to be checked, passed by reference.
  2651 	 * @param array $post_links An array of post links to be checked (passed by reference).
  2817 	 * @param array &$pung       Whether a link has already been pinged, passed by reference.
  2652 	 * @param array $pung       Whether a link has already been pinged (passed by reference).
  2818 	 * @param int   $post_ID     The post ID.
  2653 	 * @param int   $post_ID    The post ID.
  2819 	 */
  2654 	 */
  2820 	do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post_ID ) );
  2655 	do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post->ID ) );
  2821 
  2656 
  2822 	foreach ( (array) $post_links as $pagelinkedto ) {
  2657 	foreach ( (array) $post_links as $pagelinkedto ) {
  2823 		$pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
  2658 		$pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
  2824 
  2659 
  2825 		if ( $pingback_server_url ) {
  2660 		if ( $pingback_server_url ) {
  2826 			@ set_time_limit( 60 );
  2661 			@ set_time_limit( 60 );
  2827 			// Now, the RPC call
  2662 			// Now, the RPC call
  2828 			$pagelinkedfrom = get_permalink($post_ID);
  2663 			$pagelinkedfrom = get_permalink( $post );
  2829 
  2664 
  2830 			// using a timeout of 3 seconds should be enough to cover slow servers
  2665 			// using a timeout of 3 seconds should be enough to cover slow servers
  2831 			$client = new WP_HTTP_IXR_Client($pingback_server_url);
  2666 			$client = new WP_HTTP_IXR_Client($pingback_server_url);
  2832 			$client->timeout = 3;
  2667 			$client->timeout = 3;
  2833 			/**
  2668 			/**
  2834 			 * Filter the user agent sent when pinging-back a URL.
  2669 			 * Filters the user agent sent when pinging-back a URL.
  2835 			 *
  2670 			 *
  2836 			 * @since 2.9.0
  2671 			 * @since 2.9.0
  2837 			 *
  2672 			 *
  2838 			 * @param string $concat_useragent    The user agent concatenated with ' -- WordPress/'
  2673 			 * @param string $concat_useragent    The user agent concatenated with ' -- WordPress/'
  2839 			 *                                    and the WordPress version.
  2674 			 *                                    and the WordPress version.
  2840 			 * @param string $useragent           The useragent.
  2675 			 * @param string $useragent           The useragent.
  2841 			 * @param string $pingback_server_url The server URL being linked to.
  2676 			 * @param string $pingback_server_url The server URL being linked to.
  2842 			 * @param string $pagelinkedto        URL of page linked to.
  2677 			 * @param string $pagelinkedto        URL of page linked to.
  2843 			 * @param string $pagelinkedfrom      URL of page linked from.
  2678 			 * @param string $pagelinkedfrom      URL of page linked from.
  2844 			 */
  2679 			 */
  2845 			$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . $wp_version, $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
  2680 			$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . get_bloginfo( 'version' ), $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
  2846 			// when set to true, this outputs debug messages by itself
  2681 			// when set to true, this outputs debug messages by itself
  2847 			$client->debug = false;
  2682 			$client->debug = false;
  2848 
  2683 
  2849 			if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
  2684 			if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
  2850 				add_ping( $post_ID, $pagelinkedto );
  2685 				add_ping( $post, $pagelinkedto );
  2851 		}
  2686 		}
  2852 	}
  2687 	}
  2853 }
  2688 }
  2854 
  2689 
  2855 /**
  2690 /**
  2878  *
  2713  *
  2879  * @param string $trackback_url URL to send trackbacks.
  2714  * @param string $trackback_url URL to send trackbacks.
  2880  * @param string $title Title of post.
  2715  * @param string $title Title of post.
  2881  * @param string $excerpt Excerpt of post.
  2716  * @param string $excerpt Excerpt of post.
  2882  * @param int $ID Post ID.
  2717  * @param int $ID Post ID.
  2883  * @return mixed Database query from update.
  2718  * @return int|false|void Database query from update.
  2884  */
  2719  */
  2885 function trackback($trackback_url, $title, $excerpt, $ID) {
  2720 function trackback($trackback_url, $title, $excerpt, $ID) {
  2886 	global $wpdb;
  2721 	global $wpdb;
  2887 
  2722 
  2888 	if ( empty($trackback_url) )
  2723 	if ( empty($trackback_url) )
  2889 		return;
  2724 		return;
  2890 
  2725 
  2891 	$options = array();
  2726 	$options = array();
  2892 	$options['timeout'] = 4;
  2727 	$options['timeout'] = 10;
  2893 	$options['body'] = array(
  2728 	$options['body'] = array(
  2894 		'title' => $title,
  2729 		'title' => $title,
  2895 		'url' => get_permalink($ID),
  2730 		'url' => get_permalink($ID),
  2896 		'blog_name' => get_option('blogname'),
  2731 		'blog_name' => get_option('blogname'),
  2897 		'excerpt' => $excerpt
  2732 		'excerpt' => $excerpt
  2908 
  2743 
  2909 /**
  2744 /**
  2910  * Send a pingback.
  2745  * Send a pingback.
  2911  *
  2746  *
  2912  * @since 1.2.0
  2747  * @since 1.2.0
  2913  * @uses $wp_version
       
  2914  *
  2748  *
  2915  * @param string $server Host of blog to connect to.
  2749  * @param string $server Host of blog to connect to.
  2916  * @param string $path Path to send the ping.
  2750  * @param string $path Path to send the ping.
  2917  */
  2751  */
  2918 function weblog_ping($server = '', $path = '') {
  2752 function weblog_ping($server = '', $path = '') {
  2919 	global $wp_version;
  2753 	include_once( ABSPATH . WPINC . '/class-IXR.php' );
  2920 	include_once(ABSPATH . WPINC . '/class-IXR.php');
  2754 	include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );
  2921 	include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
       
  2922 
  2755 
  2923 	// using a timeout of 3 seconds should be enough to cover slow servers
  2756 	// using a timeout of 3 seconds should be enough to cover slow servers
  2924 	$client = new WP_HTTP_IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
  2757 	$client = new WP_HTTP_IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
  2925 	$client->timeout = 3;
  2758 	$client->timeout = 3;
  2926 	$client->useragent .= ' -- WordPress/'.$wp_version;
  2759 	$client->useragent .= ' -- WordPress/' . get_bloginfo( 'version' );
  2927 
  2760 
  2928 	// when set to true, this outputs debug messages by itself
  2761 	// when set to true, this outputs debug messages by itself
  2929 	$client->debug = false;
  2762 	$client->debug = false;
  2930 	$home = trailingslashit( home_url() );
  2763 	$home = trailingslashit( home_url() );
  2931 	if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
  2764 	if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
  2950  *
  2783  *
  2951  * Returns a generic pingback error code unless the error code is 48,
  2784  * Returns a generic pingback error code unless the error code is 48,
  2952  * which reports that the pingback is already registered.
  2785  * which reports that the pingback is already registered.
  2953  *
  2786  *
  2954  * @since 3.5.1
  2787  * @since 3.5.1
  2955  * @link http://www.hixie.ch/specs/pingback/pingback#TOC3
  2788  * @link https://www.hixie.ch/specs/pingback/pingback#TOC3
  2956  *
  2789  *
  2957  * @param IXR_Error $ixr_error
  2790  * @param IXR_Error $ixr_error
  2958  * @return IXR_Error
  2791  * @return IXR_Error
  2959  */
  2792  */
  2960 function xmlrpc_pingback_error( $ixr_error ) {
  2793 function xmlrpc_pingback_error( $ixr_error ) {
  2966 //
  2799 //
  2967 // Cache
  2800 // Cache
  2968 //
  2801 //
  2969 
  2802 
  2970 /**
  2803 /**
  2971  * Removes comment ID from the comment cache.
  2804  * Removes a comment from the object cache.
  2972  *
  2805  *
  2973  * @since 2.3.0
  2806  * @since 2.3.0
  2974  *
  2807  *
  2975  * @param int|array $ids Comment ID or array of comment IDs to remove from cache
  2808  * @param int|array $ids Comment ID or an array of comment IDs to remove from cache.
  2976  */
  2809  */
  2977 function clean_comment_cache($ids) {
  2810 function clean_comment_cache($ids) {
  2978 	foreach ( (array) $ids as $id )
  2811 	foreach ( (array) $ids as $id ) {
  2979 		wp_cache_delete($id, 'comment');
  2812 		wp_cache_delete( $id, 'comment' );
       
  2813 
       
  2814 		/**
       
  2815 		 * Fires immediately after a comment has been removed from the object cache.
       
  2816 		 *
       
  2817 		 * @since 4.5.0
       
  2818 		 *
       
  2819 		 * @param int $id Comment ID.
       
  2820 		 */
       
  2821 		do_action( 'clean_comment_cache', $id );
       
  2822 	}
  2980 
  2823 
  2981 	wp_cache_set( 'last_changed', microtime(), 'comment' );
  2824 	wp_cache_set( 'last_changed', microtime(), 'comment' );
  2982 }
  2825 }
  2983 
  2826 
  2984 /**
  2827 /**
  2987  * Will add the comments in $comments to the cache. If comment ID already exists
  2830  * Will add the comments in $comments to the cache. If comment ID already exists
  2988  * in the comment cache then it will not be updated. The comment is added to the
  2831  * in the comment cache then it will not be updated. The comment is added to the
  2989  * cache using the comment group with the key using the ID of the comments.
  2832  * cache using the comment group with the key using the ID of the comments.
  2990  *
  2833  *
  2991  * @since 2.3.0
  2834  * @since 2.3.0
  2992  *
  2835  * @since 4.4.0 Introduced the `$update_meta_cache` parameter.
  2993  * @param array $comments Array of comment row objects
  2836  *
  2994  */
  2837  * @param array $comments          Array of comment row objects
  2995 function update_comment_cache($comments) {
  2838  * @param bool  $update_meta_cache Whether to update commentmeta cache. Default true.
       
  2839  */
       
  2840 function update_comment_cache( $comments, $update_meta_cache = true ) {
  2996 	foreach ( (array) $comments as $comment )
  2841 	foreach ( (array) $comments as $comment )
  2997 		wp_cache_add($comment->comment_ID, $comment, 'comment');
  2842 		wp_cache_add($comment->comment_ID, $comment, 'comment');
       
  2843 
       
  2844 	if ( $update_meta_cache ) {
       
  2845 		// Avoid `wp_list_pluck()` in case `$comments` is passed by reference.
       
  2846 		$comment_ids = array();
       
  2847 		foreach ( $comments as $comment ) {
       
  2848 			$comment_ids[] = $comment->comment_ID;
       
  2849 		}
       
  2850 		update_meta_cache( 'comment', $comment_ids );
       
  2851 	}
       
  2852 }
       
  2853 
       
  2854 /**
       
  2855  * Adds any comments from the given IDs to the cache that do not already exist in cache.
       
  2856  *
       
  2857  * @since 4.4.0
       
  2858  * @access private
       
  2859  *
       
  2860  * @see update_comment_cache()
       
  2861  * @global wpdb $wpdb WordPress database abstraction object.
       
  2862  *
       
  2863  * @param array $comment_ids       Array of comment IDs.
       
  2864  * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
       
  2865  */
       
  2866 function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) {
       
  2867 	global $wpdb;
       
  2868 
       
  2869 	$non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' );
       
  2870 	if ( !empty( $non_cached_ids ) ) {
       
  2871 		$fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
       
  2872 
       
  2873 		update_comment_cache( $fresh_comments, $update_meta_cache );
       
  2874 	}
  2998 }
  2875 }
  2999 
  2876 
  3000 //
  2877 //
  3001 // Internal
  2878 // Internal
  3002 //
  2879 //
  3005  * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
  2882  * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
  3006  *
  2883  *
  3007  * @access private
  2884  * @access private
  3008  * @since 2.7.0
  2885  * @since 2.7.0
  3009  *
  2886  *
  3010  * @param object $posts Post data object.
  2887  * @param WP_Post  $posts Post data object.
  3011  * @param object $query Query object.
  2888  * @param WP_Query $query Query object.
  3012  * @return object
  2889  * @return array
  3013  */
  2890  */
  3014 function _close_comments_for_old_posts( $posts, $query ) {
  2891 function _close_comments_for_old_posts( $posts, $query ) {
  3015 	if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) )
  2892 	if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) )
  3016 		return $posts;
  2893 		return $posts;
  3017 
  2894 
  3018 	/**
  2895 	/**
  3019 	 * Filter the list of post types to automatically close comments for.
  2896 	 * Filters the list of post types to automatically close comments for.
  3020 	 *
  2897 	 *
  3021 	 * @since 3.2.0
  2898 	 * @since 3.2.0
  3022 	 *
  2899 	 *
  3023 	 * @param array $post_types An array of registered post types. Default array with 'post'.
  2900 	 * @param array $post_types An array of registered post types. Default array with 'post'.
  3024 	 */
  2901 	 */
  3064 	/** This filter is documented in wp-includes/comment.php */
  2941 	/** This filter is documented in wp-includes/comment.php */
  3065 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
  2942 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
  3066 	if ( ! in_array( $post->post_type, $post_types ) )
  2943 	if ( ! in_array( $post->post_type, $post_types ) )
  3067 		return $open;
  2944 		return $open;
  3068 
  2945 
       
  2946 	// Undated drafts should not show up as comments closed.
       
  2947 	if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
       
  2948 		return $open;
       
  2949 	}
       
  2950 
  3069 	if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
  2951 	if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
  3070 		return false;
  2952 		return false;
  3071 
  2953 
  3072 	return $open;
  2954 	return $open;
  3073 }
  2955 }
       
  2956 
       
  2957 /**
       
  2958  * Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form.
       
  2959  *
       
  2960  * This function expects unslashed data, as opposed to functions such as `wp_new_comment()` which
       
  2961  * expect slashed data.
       
  2962  *
       
  2963  * @since 4.4.0
       
  2964  *
       
  2965  * @param array $comment_data {
       
  2966  *     Comment data.
       
  2967  *
       
  2968  *     @type string|int $comment_post_ID             The ID of the post that relates to the comment.
       
  2969  *     @type string     $author                      The name of the comment author.
       
  2970  *     @type string     $email                       The comment author email address.
       
  2971  *     @type string     $url                         The comment author URL.
       
  2972  *     @type string     $comment                     The content of the comment.
       
  2973  *     @type string|int $comment_parent              The ID of this comment's parent, if any. Default 0.
       
  2974  *     @type string     $_wp_unfiltered_html_comment The nonce value for allowing unfiltered HTML.
       
  2975  * }
       
  2976  * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
       
  2977  */
       
  2978 function wp_handle_comment_submission( $comment_data ) {
       
  2979 
       
  2980 	$comment_post_ID = $comment_parent = 0;
       
  2981 	$comment_author = $comment_author_email = $comment_author_url = $comment_content = null;
       
  2982 
       
  2983 	if ( isset( $comment_data['comment_post_ID'] ) ) {
       
  2984 		$comment_post_ID = (int) $comment_data['comment_post_ID'];
       
  2985 	}
       
  2986 	if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
       
  2987 		$comment_author = trim( strip_tags( $comment_data['author'] ) );
       
  2988 	}
       
  2989 	if ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) ) {
       
  2990 		$comment_author_email = trim( $comment_data['email'] );
       
  2991 	}
       
  2992 	if ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) ) {
       
  2993 		$comment_author_url = trim( $comment_data['url'] );
       
  2994 	}
       
  2995 	if ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) ) {
       
  2996 		$comment_content = trim( $comment_data['comment'] );
       
  2997 	}
       
  2998 	if ( isset( $comment_data['comment_parent'] ) ) {
       
  2999 		$comment_parent = absint( $comment_data['comment_parent'] );
       
  3000 	}
       
  3001 
       
  3002 	$post = get_post( $comment_post_ID );
       
  3003 
       
  3004 	if ( empty( $post->comment_status ) ) {
       
  3005 
       
  3006 		/**
       
  3007 		 * Fires when a comment is attempted on a post that does not exist.
       
  3008 		 *
       
  3009 		 * @since 1.5.0
       
  3010 		 *
       
  3011 		 * @param int $comment_post_ID Post ID.
       
  3012 		 */
       
  3013 		do_action( 'comment_id_not_found', $comment_post_ID );
       
  3014 
       
  3015 		return new WP_Error( 'comment_id_not_found' );
       
  3016 
       
  3017 	}
       
  3018 
       
  3019 	// get_post_status() will get the parent status for attachments.
       
  3020 	$status = get_post_status( $post );
       
  3021 
       
  3022 	if ( ( 'private' == $status ) && ! current_user_can( 'read_post', $comment_post_ID ) ) {
       
  3023 		return new WP_Error( 'comment_id_not_found' );
       
  3024 	}
       
  3025 
       
  3026 	$status_obj = get_post_status_object( $status );
       
  3027 
       
  3028 	if ( ! comments_open( $comment_post_ID ) ) {
       
  3029 
       
  3030 		/**
       
  3031 		 * Fires when a comment is attempted on a post that has comments closed.
       
  3032 		 *
       
  3033 		 * @since 1.5.0
       
  3034 		 *
       
  3035 		 * @param int $comment_post_ID Post ID.
       
  3036 		 */
       
  3037 		do_action( 'comment_closed', $comment_post_ID );
       
  3038 
       
  3039 		return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
       
  3040 
       
  3041 	} elseif ( 'trash' == $status ) {
       
  3042 
       
  3043 		/**
       
  3044 		 * Fires when a comment is attempted on a trashed post.
       
  3045 		 *
       
  3046 		 * @since 2.9.0
       
  3047 		 *
       
  3048 		 * @param int $comment_post_ID Post ID.
       
  3049 		 */
       
  3050 		do_action( 'comment_on_trash', $comment_post_ID );
       
  3051 
       
  3052 		return new WP_Error( 'comment_on_trash' );
       
  3053 
       
  3054 	} elseif ( ! $status_obj->public && ! $status_obj->private ) {
       
  3055 
       
  3056 		/**
       
  3057 		 * Fires when a comment is attempted on a post in draft mode.
       
  3058 		 *
       
  3059 		 * @since 1.5.1
       
  3060 		 *
       
  3061 		 * @param int $comment_post_ID Post ID.
       
  3062 		 */
       
  3063 		do_action( 'comment_on_draft', $comment_post_ID );
       
  3064 		
       
  3065 		if ( current_user_can( 'read_post', $comment_post_ID ) ) {
       
  3066 			return new WP_Error( 'comment_on_draft', __( 'Sorry, comments are not allowed for this item.' ), 403 );
       
  3067 		} else {
       
  3068 			return new WP_Error( 'comment_on_draft' );
       
  3069 		}
       
  3070 
       
  3071 	} elseif ( post_password_required( $comment_post_ID ) ) {
       
  3072 
       
  3073 		/**
       
  3074 		 * Fires when a comment is attempted on a password-protected post.
       
  3075 		 *
       
  3076 		 * @since 2.9.0
       
  3077 		 *
       
  3078 		 * @param int $comment_post_ID Post ID.
       
  3079 		 */
       
  3080 		do_action( 'comment_on_password_protected', $comment_post_ID );
       
  3081 
       
  3082 		return new WP_Error( 'comment_on_password_protected' );
       
  3083 
       
  3084 	} else {
       
  3085 
       
  3086 		/**
       
  3087 		 * Fires before a comment is posted.
       
  3088 		 *
       
  3089 		 * @since 2.8.0
       
  3090 		 *
       
  3091 		 * @param int $comment_post_ID Post ID.
       
  3092 		 */
       
  3093 		do_action( 'pre_comment_on_post', $comment_post_ID );
       
  3094 
       
  3095 	}
       
  3096 
       
  3097 	// If the user is logged in
       
  3098 	$user = wp_get_current_user();
       
  3099 	if ( $user->exists() ) {
       
  3100 		if ( empty( $user->display_name ) ) {
       
  3101 			$user->display_name=$user->user_login;
       
  3102 		}
       
  3103 		$comment_author       = $user->display_name;
       
  3104 		$comment_author_email = $user->user_email;
       
  3105 		$comment_author_url   = $user->user_url;
       
  3106 		$user_ID              = $user->ID;
       
  3107 		if ( current_user_can( 'unfiltered_html' ) ) {
       
  3108 			if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
       
  3109 				|| ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
       
  3110 			) {
       
  3111 				kses_remove_filters(); // start with a clean slate
       
  3112 				kses_init_filters(); // set up the filters
       
  3113 			}
       
  3114 		}
       
  3115 	} else {
       
  3116 		if ( get_option( 'comment_registration' ) ) {
       
  3117 			return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to comment.' ), 403 );
       
  3118 		}
       
  3119 	}
       
  3120 
       
  3121 	$comment_type = '';
       
  3122 
       
  3123 	if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
       
  3124 		if ( '' == $comment_author_email || '' == $comment_author ) {
       
  3125 			return new WP_Error( 'require_name_email', __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
       
  3126 		} elseif ( ! is_email( $comment_author_email ) ) {
       
  3127 			return new WP_Error( 'require_valid_email', __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
       
  3128 		}
       
  3129 	}
       
  3130 
       
  3131 	if ( '' == $comment_content ) {
       
  3132 		return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
       
  3133 	}
       
  3134 
       
  3135 	$commentdata = compact(
       
  3136 		'comment_post_ID',
       
  3137 		'comment_author',
       
  3138 		'comment_author_email',
       
  3139 		'comment_author_url',
       
  3140 		'comment_content',
       
  3141 		'comment_type',
       
  3142 		'comment_parent',
       
  3143 		'user_ID'
       
  3144 	);
       
  3145 
       
  3146 	$check_max_lengths = wp_check_comment_data_max_lengths( $commentdata );
       
  3147 	if ( is_wp_error( $check_max_lengths ) ) {
       
  3148 		return $check_max_lengths;
       
  3149 	}
       
  3150 
       
  3151 	$comment_id = wp_new_comment( wp_slash( $commentdata ), true );
       
  3152 	if ( is_wp_error( $comment_id ) ) {
       
  3153 		return $comment_id;
       
  3154 	}
       
  3155 
       
  3156 	if ( ! $comment_id ) {
       
  3157 		return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
       
  3158 	}
       
  3159 
       
  3160 	return get_comment( $comment_id );
       
  3161 }
       
  3162 
       
  3163 /**
       
  3164  * Registers the personal data exporter for comments.
       
  3165  *
       
  3166  * @since 4.9.6
       
  3167  *
       
  3168  * @param array $exporters An array of personal data exporters.
       
  3169  * @return array $exporters An array of personal data exporters.
       
  3170  */
       
  3171 function wp_register_comment_personal_data_exporter( $exporters ) {
       
  3172 	$exporters['wordpress-comments'] = array(
       
  3173 		'exporter_friendly_name' => __( 'WordPress Comments' ),
       
  3174 		'callback'               => 'wp_comments_personal_data_exporter',
       
  3175 	);
       
  3176 
       
  3177 	return $exporters;
       
  3178 }
       
  3179 
       
  3180 /**
       
  3181  * Finds and exports personal data associated with an email address from the comments table.
       
  3182  *
       
  3183  * @since 4.9.6
       
  3184  *
       
  3185  * @param string $email_address The comment author email address.
       
  3186  * @param int    $page          Comment page.
       
  3187  * @return array $return An array of personal data.
       
  3188  */
       
  3189 function wp_comments_personal_data_exporter( $email_address, $page = 1 ) {
       
  3190 	// Limit us to 500 comments at a time to avoid timing out.
       
  3191 	$number = 500;
       
  3192 	$page   = (int) $page;
       
  3193 
       
  3194 	$data_to_export = array();
       
  3195 
       
  3196 	$comments = get_comments(
       
  3197 		array(
       
  3198 			'author_email'              => $email_address,
       
  3199 			'number'                    => $number,
       
  3200 			'paged'                     => $page,
       
  3201 			'order_by'                  => 'comment_ID',
       
  3202 			'order'                     => 'ASC',
       
  3203 			'update_comment_meta_cache' => false,
       
  3204 		)
       
  3205 	);
       
  3206 
       
  3207 	$comment_prop_to_export = array(
       
  3208 		'comment_author'       => __( 'Comment Author' ),
       
  3209 		'comment_author_email' => __( 'Comment Author Email' ),
       
  3210 		'comment_author_url'   => __( 'Comment Author URL' ),
       
  3211 		'comment_author_IP'    => __( 'Comment Author IP' ),
       
  3212 		'comment_agent'        => __( 'Comment Author User Agent' ),
       
  3213 		'comment_date'         => __( 'Comment Date' ),
       
  3214 		'comment_content'      => __( 'Comment Content' ),
       
  3215 		'comment_link'         => __( 'Comment URL' ),
       
  3216 	);
       
  3217 
       
  3218 	foreach ( (array) $comments as $comment ) {
       
  3219 		$comment_data_to_export = array();
       
  3220 
       
  3221 		foreach ( $comment_prop_to_export as $key => $name ) {
       
  3222 			$value = '';
       
  3223 
       
  3224 			switch ( $key ) {
       
  3225 				case 'comment_author':
       
  3226 				case 'comment_author_email':
       
  3227 				case 'comment_author_url':
       
  3228 				case 'comment_author_IP':
       
  3229 				case 'comment_agent':
       
  3230 				case 'comment_date':
       
  3231 					$value = $comment->{$key};
       
  3232 					break;
       
  3233 
       
  3234 				case 'comment_content':
       
  3235 					$value = get_comment_text( $comment->comment_ID );
       
  3236 					break;
       
  3237 
       
  3238 				case 'comment_link':
       
  3239 					$value = get_comment_link( $comment->comment_ID );
       
  3240 					$value = sprintf(
       
  3241 						'<a href="%s" target="_blank" rel="noreferrer noopener">%s</a>',
       
  3242 						esc_url( $value ),
       
  3243 						esc_html( $value )
       
  3244 					);
       
  3245 					break;
       
  3246 			}
       
  3247 
       
  3248 			if ( ! empty( $value ) ) {
       
  3249 				$comment_data_to_export[] = array(
       
  3250 					'name'  => $name,
       
  3251 					'value' => $value,
       
  3252 				);
       
  3253 			}
       
  3254 		}
       
  3255 
       
  3256 		$data_to_export[] = array(
       
  3257 			'group_id'    => 'comments',
       
  3258 			'group_label' => __( 'Comments' ),
       
  3259 			'item_id'     => "comment-{$comment->comment_ID}",
       
  3260 			'data'        => $comment_data_to_export,
       
  3261 		);
       
  3262 	}
       
  3263 
       
  3264 	$done = count( $comments ) < $number;
       
  3265 
       
  3266 	return array(
       
  3267 		'data' => $data_to_export,
       
  3268 		'done' => $done,
       
  3269 	);
       
  3270 }
       
  3271 
       
  3272 /**
       
  3273  * Registers the personal data eraser for comments.
       
  3274  *
       
  3275  * @since 4.9.6
       
  3276  *
       
  3277  * @param  array $erasers An array of personal data erasers.
       
  3278  * @return array $erasers An array of personal data erasers.
       
  3279  */
       
  3280 function wp_register_comment_personal_data_eraser( $erasers ) {
       
  3281 	$erasers['wordpress-comments'] = array(
       
  3282 		'eraser_friendly_name' => __( 'WordPress Comments' ),
       
  3283 		'callback'             => 'wp_comments_personal_data_eraser',
       
  3284 	);
       
  3285 
       
  3286 	return $erasers;
       
  3287 }
       
  3288 
       
  3289 /**
       
  3290  * Erases personal data associated with an email address from the comments table.
       
  3291  *
       
  3292  * @since 4.9.6
       
  3293  *
       
  3294  * @param  string $email_address The comment author email address.
       
  3295  * @param  int    $page          Comment page.
       
  3296  * @return array
       
  3297  */
       
  3298 function wp_comments_personal_data_eraser( $email_address, $page = 1 ) {
       
  3299 	global $wpdb;
       
  3300 
       
  3301 	if ( empty( $email_address ) ) {
       
  3302 		return array(
       
  3303 			'items_removed'  => false,
       
  3304 			'items_retained' => false,
       
  3305 			'messages'       => array(),
       
  3306 			'done'           => true,
       
  3307 		);
       
  3308 	}
       
  3309 
       
  3310 	// Limit us to 500 comments at a time to avoid timing out.
       
  3311 	$number         = 500;
       
  3312 	$page           = (int) $page;
       
  3313 	$items_removed  = false;
       
  3314 	$items_retained = false;
       
  3315 
       
  3316 	$comments = get_comments(
       
  3317 		array(
       
  3318 			'author_email'       => $email_address,
       
  3319 			'number'             => $number,
       
  3320 			'paged'              => $page,
       
  3321 			'order_by'           => 'comment_ID',
       
  3322 			'order'              => 'ASC',
       
  3323 			'include_unapproved' => true,
       
  3324 		)
       
  3325 	);
       
  3326 
       
  3327 	/* translators: Name of a comment's author after being anonymized. */
       
  3328 	$anon_author = __( 'Anonymous' );
       
  3329 	$messages    = array();
       
  3330 
       
  3331 	foreach ( (array) $comments as $comment ) {
       
  3332 		$anonymized_comment                         = array();
       
  3333 		$anonymized_comment['comment_agent']        = '';
       
  3334 		$anonymized_comment['comment_author']       = $anon_author;
       
  3335 		$anonymized_comment['comment_author_email'] = '';
       
  3336 		$anonymized_comment['comment_author_IP']    = wp_privacy_anonymize_data( 'ip', $comment->comment_author_IP );
       
  3337 		$anonymized_comment['comment_author_url']   = '';
       
  3338 		$anonymized_comment['user_id']              = 0;
       
  3339 
       
  3340 		$comment_id = (int) $comment->comment_ID;
       
  3341 
       
  3342 		/**
       
  3343 		 * Filters whether to anonymize the comment.
       
  3344 		 *
       
  3345 		 * @since 4.9.6
       
  3346 		 *
       
  3347 		 * @param bool|string                    Whether to apply the comment anonymization (bool).
       
  3348 		 *                                       Custom prevention message (string). Default true.
       
  3349 		 * @param WP_Comment $comment            WP_Comment object.
       
  3350 		 * @param array      $anonymized_comment Anonymized comment data.
       
  3351 		 */
       
  3352 		$anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
       
  3353 
       
  3354 		if ( true !== $anon_message ) {
       
  3355 			if ( $anon_message && is_string( $anon_message ) ) {
       
  3356 				$messages[] = esc_html( $anon_message );
       
  3357 			} else {
       
  3358 				/* translators: %d: Comment ID */
       
  3359 				$messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
       
  3360 			}
       
  3361 
       
  3362 			$items_retained = true;
       
  3363 
       
  3364 			continue;
       
  3365 		}
       
  3366 
       
  3367 		$args = array(
       
  3368 			'comment_ID' => $comment_id,
       
  3369 		);
       
  3370 
       
  3371 		$updated = $wpdb->update( $wpdb->comments, $anonymized_comment, $args );
       
  3372 
       
  3373 		if ( $updated ) {
       
  3374 			$items_removed = true;
       
  3375 			clean_comment_cache( $comment_id );
       
  3376 		} else {
       
  3377 			$items_retained = true;
       
  3378 		}
       
  3379 	}
       
  3380 
       
  3381 	$done = count( $comments ) < $number;
       
  3382 
       
  3383 	return array(
       
  3384 		'items_removed'  => $items_removed,
       
  3385 		'items_retained' => $items_retained,
       
  3386 		'messages'       => $messages,
       
  3387 		'done'           => $done,
       
  3388 	);
       
  3389 }