wp/wp-includes/comment.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     8 
     8 
     9 /**
     9 /**
    10  * Check whether a comment passes internal checks to be allowed to add.
    10  * Check whether a comment passes internal checks to be allowed to add.
    11  *
    11  *
    12  * If manual comment moderation is set in the administration, then all checks,
    12  * If manual comment moderation is set in the administration, then all checks,
    13  * regardless of their type and whitelist, will fail and the function will
    13  * regardless of their type and substance, will fail and the function will
    14  * return false.
    14  * return false.
    15  *
    15  *
    16  * If the number of links exceeds the amount in the administration, then the
    16  * If the number of links exceeds the amount in the administration, then the
    17  * check fails. If any of the parameter contents match the blacklist of words,
    17  * check fails. If any of the parameter contents contain any disallowed words,
    18  * then the check fails.
    18  * then the check fails.
    19  *
    19  *
    20  * If the comment author was approved before, then the comment is automatically
    20  * If the comment author was approved before, then the comment is automatically
    21  * whitelisted.
    21  * approved.
    22  *
    22  *
    23  * If all checks pass, the function will return true.
    23  * If all checks pass, the function will return true.
    24  *
    24  *
    25  * @since 1.2.0
    25  * @since 1.2.0
    26  *
    26  *
    46 
    46 
    47 	/** This filter is documented in wp-includes/comment-template.php */
    47 	/** This filter is documented in wp-includes/comment-template.php */
    48 	$comment = apply_filters( 'comment_text', $comment, null, array() );
    48 	$comment = apply_filters( 'comment_text', $comment, null, array() );
    49 
    49 
    50 	// Check for the number of external links if a max allowed number is set.
    50 	// Check for the number of external links if a max allowed number is set.
    51 	if ( $max_links = get_option( 'comment_max_links' ) ) {
    51 	$max_links = get_option( 'comment_max_links' );
       
    52 	if ( $max_links ) {
    52 		$num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
    53 		$num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
    53 
    54 
    54 		/**
    55 		/**
    55 		 * Filters the number of links found in a comment.
    56 		 * Filters the number of links found in a comment.
    56 		 *
    57 		 *
   123 	 *
   124 	 *
   124 	 * If it is enabled, check whether the comment author has a previously-approved comment,
   125 	 * If it is enabled, check whether the comment author has a previously-approved comment,
   125 	 * as well as whether there are any moderation keywords (if set) present in the author
   126 	 * as well as whether there are any moderation keywords (if set) present in the author
   126 	 * email address. If both checks pass, return true. Otherwise, return false.
   127 	 * email address. If both checks pass, return true. Otherwise, return false.
   127 	 */
   128 	 */
   128 	if ( 1 == get_option( 'comment_whitelist' ) ) {
   129 	if ( 1 == get_option( 'comment_previously_approved' ) ) {
   129 		if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
   130 		if ( 'trackback' !== $comment_type && 'pingback' !== $comment_type && '' !== $author && '' !== $email ) {
   130 			$comment_user = get_user_by( 'email', wp_unslash( $email ) );
   131 			$comment_user = get_user_by( 'email', wp_unslash( $email ) );
   131 			if ( ! empty( $comment_user->ID ) ) {
   132 			if ( ! empty( $comment_user->ID ) ) {
   132 				$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 ) );
   133 				$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 ) );
   133 			} else {
   134 			} else {
   134 				// expected_slashed ($author, $email)
   135 				// expected_slashed ($author, $email)
   151  * Retrieve the approved comments for post $post_id.
   152  * Retrieve the approved comments for post $post_id.
   152  *
   153  *
   153  * @since 2.0.0
   154  * @since 2.0.0
   154  * @since 4.1.0 Refactored to leverage WP_Comment_Query over a direct query.
   155  * @since 4.1.0 Refactored to leverage WP_Comment_Query over a direct query.
   155  *
   156  *
   156  * @param  int   $post_id The ID of the post.
   157  * @param int   $post_id The ID of the post.
   157  * @param  array $args    Optional. See WP_Comment_Query::__construct() for information on accepted arguments.
   158  * @param array $args    Optional. See WP_Comment_Query::__construct() for information on accepted arguments.
   158  * @return int|array $comments The approved comments, or number of comments if `$count`
   159  * @return int|array The approved comments, or number of comments if `$count`
   159  *                             argument is true.
   160  *                   argument is true.
   160  */
   161  */
   161 function get_approved_comments( $post_id, $args = array() ) {
   162 function get_approved_comments( $post_id, $args = array() ) {
   162 	if ( ! $post_id ) {
   163 	if ( ! $post_id ) {
   163 		return array();
   164 		return array();
   164 	}
   165 	}
   165 
   166 
   166 	$defaults = array(
   167 	$defaults    = array(
   167 		'status'  => 1,
   168 		'status'  => 1,
   168 		'post_id' => $post_id,
   169 		'post_id' => $post_id,
   169 		'order'   => 'ASC',
   170 		'order'   => 'ASC',
   170 	);
   171 	);
   171 	$r        = wp_parse_args( $args, $defaults );
   172 	$parsed_args = wp_parse_args( $args, $defaults );
   172 
   173 
   173 	$query = new WP_Comment_Query;
   174 	$query = new WP_Comment_Query;
   174 	return $query->query( $r );
   175 	return $query->query( $parsed_args );
   175 }
   176 }
   176 
   177 
   177 /**
   178 /**
   178  * Retrieves comment data given a comment ID or comment object.
   179  * Retrieves comment data given a comment ID or comment object.
   179  *
   180  *
   181  * after being passed through a filter. If the comment is empty, then the global
   182  * after being passed through a filter. If the comment is empty, then the global
   182  * comment variable will be used, if it is set.
   183  * comment variable will be used, if it is set.
   183  *
   184  *
   184  * @since 2.0.0
   185  * @since 2.0.0
   185  *
   186  *
   186  * @global WP_Comment $comment
   187  * @global WP_Comment $comment Global comment object.
   187  *
   188  *
   188  * @param WP_Comment|string|int $comment Comment to retrieve.
   189  * @param WP_Comment|string|int $comment Comment to retrieve.
   189  * @param string                $output  Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
   190  * @param string                $output  Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
   190  *                                       a WP_Comment object, an associative array, or a numeric array, respectively. Default OBJECT.
   191  *                                       correspond to a WP_Comment object, an associative array, or a numeric array,
       
   192  *                                       respectively. Default OBJECT.
   191  * @return WP_Comment|array|null Depends on $output value.
   193  * @return WP_Comment|array|null Depends on $output value.
   192  */
   194  */
   193 function get_comment( &$comment = null, $output = OBJECT ) {
   195 function get_comment( &$comment = null, $output = OBJECT ) {
   194 	if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
   196 	if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
   195 		$comment = $GLOBALS['comment'];
   197 		$comment = $GLOBALS['comment'];
   210 	/**
   212 	/**
   211 	 * Fires after a comment is retrieved.
   213 	 * Fires after a comment is retrieved.
   212 	 *
   214 	 *
   213 	 * @since 2.3.0
   215 	 * @since 2.3.0
   214 	 *
   216 	 *
   215 	 * @param mixed $_comment Comment data.
   217 	 * @param WP_Comment $_comment Comment data.
   216 	 */
   218 	 */
   217 	$_comment = apply_filters( 'get_comment', $_comment );
   219 	$_comment = apply_filters( 'get_comment', $_comment );
   218 
   220 
   219 	if ( $output == OBJECT ) {
   221 	if ( OBJECT == $output ) {
   220 		return $_comment;
   222 		return $_comment;
   221 	} elseif ( $output == ARRAY_A ) {
   223 	} elseif ( ARRAY_A == $output ) {
   222 		return $_comment->to_array();
   224 		return $_comment->to_array();
   223 	} elseif ( $output == ARRAY_N ) {
   225 	} elseif ( ARRAY_N == $output ) {
   224 		return array_values( $_comment->to_array() );
   226 		return array_values( $_comment->to_array() );
   225 	}
   227 	}
   226 	return $_comment;
   228 	return $_comment;
   227 }
   229 }
   228 
   230 
   248  * Comments have a limited set of valid status values, this provides the comment
   250  * Comments have a limited set of valid status values, this provides the comment
   249  * status values and descriptions.
   251  * status values and descriptions.
   250  *
   252  *
   251  * @since 2.7.0
   253  * @since 2.7.0
   252  *
   254  *
   253  * @return array List of comment statuses.
   255  * @return string[] List of comment status labels keyed by status.
   254  */
   256  */
   255 function get_comment_statuses() {
   257 function get_comment_statuses() {
   256 	$status = array(
   258 	$status = array(
   257 		'hold'    => __( 'Unapproved' ),
   259 		'hold'    => __( 'Unapproved' ),
   258 		'approve' => _x( 'Approved', 'comment status' ),
   260 		'approve' => _x( 'Approved', 'comment status' ),
   280 			$option   = 'ping';
   282 			$option   = 'ping';
   281 			break;
   283 			break;
   282 		default:
   284 		default:
   283 			$supports = 'comments';
   285 			$supports = 'comments';
   284 			$option   = 'comment';
   286 			$option   = 'comment';
       
   287 			break;
   285 	}
   288 	}
   286 
   289 
   287 	// Set the status.
   290 	// Set the status.
   288 	if ( 'page' === $post_type ) {
   291 	if ( 'page' === $post_type ) {
   289 		$status = 'closed';
   292 		$status = 'closed';
   335 			break;
   338 			break;
   336 		case 'blog':
   339 		case 'blog':
   337 			$comment_modified_date = $wpdb->get_var( "SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
   340 			$comment_modified_date = $wpdb->get_var( "SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
   338 			break;
   341 			break;
   339 		case 'server':
   342 		case 'server':
   340 			$add_seconds_server = date( 'Z' );
   343 			$add_seconds_server = gmdate( 'Z' );
   341 
   344 
   342 			$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 ) );
   345 			$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 ) );
   343 			break;
   346 			break;
   344 	}
   347 	}
   345 
   348 
   351 
   354 
   352 	return false;
   355 	return false;
   353 }
   356 }
   354 
   357 
   355 /**
   358 /**
   356  * The amount of comments in a post or total comments.
   359  * Retrieves the total comment counts for the whole site or a single post.
   357  *
   360  *
   358  * A lot like wp_count_comments(), in that they both return comment stats (albeit with different types).
   361  * Unlike wp_count_comments(), this function always returns the live comment counts without caching.
   359  * The wp_count_comments() actually caches, but this function does not.
       
   360  *
   362  *
   361  * @since 2.0.0
   363  * @since 2.0.0
   362  *
   364  *
   363  * @global wpdb $wpdb WordPress database abstraction object.
   365  * @global wpdb $wpdb WordPress database abstraction object.
   364  *
   366  *
   365  * @param int $post_id Optional. Comment amount in post if > 0, else total comments blog wide.
   367  * @param int $post_id Optional. Restrict the comment counts to the given post. Default 0, which indicates that
   366  * @return array The amount of spam, approved, awaiting moderation, and total comments.
   368  *                     comment counts for the whole site will be retrieved.
       
   369  * @return array() {
       
   370  *     The number of comments keyed by their status.
       
   371  *
       
   372  *     @type int $approved            The number of approved comments.
       
   373  *     @type int $awaiting_moderation The number of comments awaiting moderation (a.k.a. pending).
       
   374  *     @type int $spam                The number of spam comments.
       
   375  *     @type int $trash               The number of trashed comments.
       
   376  *     @type int $post-trashed        The number of comments for posts that are in the trash.
       
   377  *     @type int $total_comments      The total number of non-trashed comments, including spam.
       
   378  *     @type int $all                 The total number of pending or approved comments.
       
   379  * }
   367  */
   380  */
   368 function get_comment_count( $post_id = 0 ) {
   381 function get_comment_count( $post_id = 0 ) {
   369 	global $wpdb;
   382 	global $wpdb;
   370 
   383 
   371 	$post_id = (int) $post_id;
   384 	$post_id = (int) $post_id;
   420 			default:
   433 			default:
   421 				break;
   434 				break;
   422 		}
   435 		}
   423 	}
   436 	}
   424 
   437 
   425 	return $comment_count;
   438 	return array_map( 'intval', $comment_count );
   426 }
   439 }
   427 
   440 
   428 //
   441 //
   429 // Comment meta functions
   442 // Comment meta functions.
   430 //
   443 //
   431 
   444 
   432 /**
   445 /**
   433  * Add meta data field to a comment.
   446  * Add meta data field to a comment.
   434  *
   447  *
   435  * @since 2.9.0
   448  * @since 2.9.0
   436  * @link https://codex.wordpress.org/Function_Reference/add_comment_meta
   449  *
   437  *
   450  * @link https://developer.wordpress.org/reference/functions/add_comment_meta/
   438  * @param int $comment_id Comment ID.
   451  *
   439  * @param string $meta_key Metadata name.
   452  * @param int    $comment_id Comment ID.
   440  * @param mixed $meta_value Metadata value.
   453  * @param string $meta_key   Metadata name.
   441  * @param bool $unique Optional, default is false. Whether the same key should not be added.
   454  * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
       
   455  * @param bool   $unique     Optional. Whether the same key should not be added.
       
   456  *                           Default false.
   442  * @return int|bool Meta ID on success, false on failure.
   457  * @return int|bool Meta ID on success, false on failure.
   443  */
   458  */
   444 function add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false ) {
   459 function add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false ) {
   445 	return add_metadata( 'comment', $comment_id, $meta_key, $meta_value, $unique );
   460 	return add_metadata( 'comment', $comment_id, $meta_key, $meta_value, $unique );
   446 }
   461 }
   451  * You can match based on the key, or key and value. Removing based on key and
   466  * You can match based on the key, or key and value. Removing based on key and
   452  * value, will keep from removing duplicate metadata with the same key. It also
   467  * value, will keep from removing duplicate metadata with the same key. It also
   453  * allows removing all metadata matching key, if needed.
   468  * allows removing all metadata matching key, if needed.
   454  *
   469  *
   455  * @since 2.9.0
   470  * @since 2.9.0
   456  * @link https://codex.wordpress.org/Function_Reference/delete_comment_meta
   471  *
   457  *
   472  * @link https://developer.wordpress.org/reference/functions/delete_comment_meta/
   458  * @param int $comment_id comment ID
   473  *
   459  * @param string $meta_key Metadata name.
   474  * @param int    $comment_id Comment ID.
   460  * @param mixed $meta_value Optional. Metadata value.
   475  * @param string $meta_key   Metadata name.
       
   476  * @param mixed  $meta_value Optional. Metadata value. If provided,
       
   477  *                           rows will only be removed that match the value.
       
   478  *                           Must be serializable if non-scalar. Default empty.
   461  * @return bool True on success, false on failure.
   479  * @return bool True on success, false on failure.
   462  */
   480  */
   463 function delete_comment_meta( $comment_id, $meta_key, $meta_value = '' ) {
   481 function delete_comment_meta( $comment_id, $meta_key, $meta_value = '' ) {
   464 	return delete_metadata( 'comment', $comment_id, $meta_key, $meta_value );
   482 	return delete_metadata( 'comment', $comment_id, $meta_key, $meta_value );
   465 }
   483 }
   466 
   484 
   467 /**
   485 /**
   468  * Retrieve comment meta field for a comment.
   486  * Retrieve comment meta field for a comment.
   469  *
   487  *
   470  * @since 2.9.0
   488  * @since 2.9.0
   471  * @link https://codex.wordpress.org/Function_Reference/get_comment_meta
   489  *
   472  *
   490  * @link https://developer.wordpress.org/reference/functions/get_comment_meta/
   473  * @param int $comment_id Comment ID.
   491  *
   474  * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
   492  * @param int    $comment_id Comment ID.
   475  * @param bool $single Whether to return a single value.
   493  * @param string $key        Optional. The meta key to retrieve. By default,
   476  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
   494  *                           returns data for all keys.
   477  *  is true.
   495  * @param bool   $single     Optional. Whether to return a single value.
       
   496  *                           This parameter has no effect if $key is not specified.
       
   497  *                           Default false.
       
   498  * @return mixed An array if $single is false. The value of meta data field
       
   499  *               if $single is true. False for an invalid $comment_id.
   478  */
   500  */
   479 function get_comment_meta( $comment_id, $key = '', $single = false ) {
   501 function get_comment_meta( $comment_id, $key = '', $single = false ) {
   480 	return get_metadata( 'comment', $comment_id, $key, $single );
   502 	return get_metadata( 'comment', $comment_id, $key, $single );
   481 }
   503 }
   482 
   504 
   487  * same key and comment ID.
   509  * same key and comment ID.
   488  *
   510  *
   489  * If the meta field for the comment does not exist, it will be added.
   511  * If the meta field for the comment does not exist, it will be added.
   490  *
   512  *
   491  * @since 2.9.0
   513  * @since 2.9.0
   492  * @link https://codex.wordpress.org/Function_Reference/update_comment_meta
   514  *
   493  *
   515  * @link https://developer.wordpress.org/reference/functions/update_comment_meta/
   494  * @param int $comment_id Comment ID.
   516  *
   495  * @param string $meta_key Metadata key.
   517  * @param int    $comment_id Comment ID.
   496  * @param mixed $meta_value Metadata value.
   518  * @param string $meta_key   Metadata key.
   497  * @param mixed $prev_value Optional. Previous value to check before removing.
   519  * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
   498  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
   520  * @param mixed  $prev_value Optional. Previous value to check before updating.
       
   521  *                           If specified, only update existing metadata entries with
       
   522  *                           this value. Otherwise, update all entries. Default empty.
       
   523  * @return int|bool Meta ID if the key didn't exist, true on successful update,
       
   524  *                  false on failure or if the value passed to the function
       
   525  *                  is the same as the one that is already in the database.
   499  */
   526  */
   500 function update_comment_meta( $comment_id, $meta_key, $meta_value, $prev_value = '' ) {
   527 function update_comment_meta( $comment_id, $meta_key, $meta_value, $prev_value = '' ) {
   501 	return update_metadata( 'comment', $comment_id, $meta_key, $meta_value, $prev_value );
   528 	return update_metadata( 'comment', $comment_id, $meta_key, $meta_value, $prev_value );
   502 }
   529 }
   503 
   530 
   532  * @since 3.4.0
   559  * @since 3.4.0
   533  * @since 4.9.6 The `$cookies_consent` parameter was added.
   560  * @since 4.9.6 The `$cookies_consent` parameter was added.
   534  *
   561  *
   535  * @param WP_Comment $comment         Comment object.
   562  * @param WP_Comment $comment         Comment object.
   536  * @param WP_User    $user            Comment author's user object. The user may not exist.
   563  * @param WP_User    $user            Comment author's user object. The user may not exist.
   537  * @param boolean    $cookies_consent Optional. Comment author's consent to store cookies. Default true.
   564  * @param bool       $cookies_consent Optional. Comment author's consent to store cookies. Default true.
   538  */
   565  */
   539 function wp_set_comment_cookies( $comment, $user, $cookies_consent = true ) {
   566 function wp_set_comment_cookies( $comment, $user, $cookies_consent = true ) {
   540 	// If the user already exists, or the user opted out of cookies, don't set cookies.
   567 	// If the user already exists, or the user opted out of cookies, don't set cookies.
   541 	if ( $user->exists() ) {
   568 	if ( $user->exists() ) {
   542 		return;
   569 		return;
   558 	 * @since 2.8.0
   585 	 * @since 2.8.0
   559 	 *
   586 	 *
   560 	 * @param int $seconds Comment cookie lifetime. Default 30000000.
   587 	 * @param int $seconds Comment cookie lifetime. Default 30000000.
   561 	 */
   588 	 */
   562 	$comment_cookie_lifetime = time() + apply_filters( 'comment_cookie_lifetime', 30000000 );
   589 	$comment_cookie_lifetime = time() + apply_filters( 'comment_cookie_lifetime', 30000000 );
   563 	$secure                  = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
   590 
       
   591 	$secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
       
   592 
   564 	setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   593 	setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   565 	setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   594 	setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   566 	setcookie( 'comment_author_url_' . COOKIEHASH, esc_url( $comment->comment_author_url ), $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   595 	setcookie( 'comment_author_url_' . COOKIEHASH, esc_url( $comment->comment_author_url ), $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
   567 }
   596 }
   568 
   597 
   628 
   657 
   629 /**
   658 /**
   630  * Validates whether this comment is allowed to be made.
   659  * Validates whether this comment is allowed to be made.
   631  *
   660  *
   632  * @since 2.0.0
   661  * @since 2.0.0
   633  * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function to
   662  * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function
   634  *              return a WP_Error object instead of dying.
   663  *              to return a WP_Error object instead of dying.
       
   664  * @since 5.5.0 The `$avoid_die` parameter was renamed to `$wp_error`.
   635  *
   665  *
   636  * @global wpdb $wpdb WordPress database abstraction object.
   666  * @global wpdb $wpdb WordPress database abstraction object.
   637  *
   667  *
   638  * @param array $commentdata Contains information on the comment.
   668  * @param array $commentdata Contains information on the comment.
   639  * @param bool  $avoid_die   When true, a disallowed comment will result in the function
   669  * @param bool  $wp_error    When true, a disallowed comment will result in the function
   640  *                           returning a WP_Error object, rather than executing wp_die().
   670  *                           returning a WP_Error object, rather than executing wp_die().
   641  *                           Default false.
   671  *                           Default false.
   642  * @return int|string|WP_Error Allowed comments return the approval status (0|1|'spam').
   672  * @return int|string|WP_Error Allowed comments return the approval status (0|1|'spam'|'trash').
   643  *                             If `$avoid_die` is true, disallowed comments return a WP_Error.
   673  *                             If `$wp_error` is true, disallowed comments return a WP_Error.
   644  */
   674  */
   645 function wp_allow_comment( $commentdata, $avoid_die = false ) {
   675 function wp_allow_comment( $commentdata, $wp_error = false ) {
   646 	global $wpdb;
   676 	global $wpdb;
   647 
   677 
   648 	// Simple duplicate check
   678 	// Simple duplicate check.
   649 	// expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
   679 	// expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
   650 	$dupe = $wpdb->prepare(
   680 	$dupe = $wpdb->prepare(
   651 		"SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = %s AND comment_approved != 'trash' AND ( comment_author = %s ",
   681 		"SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = %s AND comment_approved != 'trash' AND ( comment_author = %s ",
   652 		wp_unslash( $commentdata['comment_post_ID'] ),
   682 		wp_unslash( $commentdata['comment_post_ID'] ),
   653 		wp_unslash( $commentdata['comment_parent'] ),
   683 		wp_unslash( $commentdata['comment_parent'] ),
   695 		 *
   725 		 *
   696 		 * @param string $comment_duplicate_message Duplicate comment error message.
   726 		 * @param string $comment_duplicate_message Duplicate comment error message.
   697 		 */
   727 		 */
   698 		$comment_duplicate_message = apply_filters( 'comment_duplicate_message', __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ) );
   728 		$comment_duplicate_message = apply_filters( 'comment_duplicate_message', __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ) );
   699 
   729 
   700 		if ( true === $avoid_die ) {
   730 		if ( $wp_error ) {
   701 			return new WP_Error( 'comment_duplicate', $comment_duplicate_message, 409 );
   731 			return new WP_Error( 'comment_duplicate', $comment_duplicate_message, 409 );
   702 		} else {
   732 		} else {
   703 			if ( wp_doing_ajax() ) {
   733 			if ( wp_doing_ajax() ) {
   704 				die( $comment_duplicate_message );
   734 				die( $comment_duplicate_message );
   705 			}
   735 			}
   713 	 *
   743 	 *
   714 	 * Allows checking for comment flooding.
   744 	 * Allows checking for comment flooding.
   715 	 *
   745 	 *
   716 	 * @since 2.3.0
   746 	 * @since 2.3.0
   717 	 * @since 4.7.0 The `$avoid_die` parameter was added.
   747 	 * @since 4.7.0 The `$avoid_die` parameter was added.
       
   748 	 * @since 5.5.0 The `$avoid_die` parameter was renamed to `$wp_error`.
   718 	 *
   749 	 *
   719 	 * @param string $comment_author_IP    Comment author's IP address.
   750 	 * @param string $comment_author_IP    Comment author's IP address.
   720 	 * @param string $comment_author_email Comment author's email.
   751 	 * @param string $comment_author_email Comment author's email.
   721 	 * @param string $comment_date_gmt     GMT date the comment was posted.
   752 	 * @param string $comment_date_gmt     GMT date the comment was posted.
   722 	 * @param bool   $avoid_die            Whether to prevent executing wp_die()
   753 	 * @param bool   $wp_error             Whether to return a WP_Error object instead of executing
   723 	 *                                     or die() if a comment flood is occurring.
   754 	 *                                     wp_die() or die() if a comment flood is occurring.
   724 	 */
   755 	 */
   725 	do_action(
   756 	do_action(
   726 		'check_comment_flood',
   757 		'check_comment_flood',
   727 		$commentdata['comment_author_IP'],
   758 		$commentdata['comment_author_IP'],
   728 		$commentdata['comment_author_email'],
   759 		$commentdata['comment_author_email'],
   729 		$commentdata['comment_date_gmt'],
   760 		$commentdata['comment_date_gmt'],
   730 		$avoid_die
   761 		$wp_error
   731 	);
   762 	);
   732 
   763 
   733 	/**
   764 	/**
   734 	 * Filters whether a comment is part of a comment flood.
   765 	 * Filters whether a comment is part of a comment flood.
   735 	 *
   766 	 *
   736 	 * The default check is wp_check_comment_flood(). See check_comment_flood_db().
   767 	 * The default check is wp_check_comment_flood(). See check_comment_flood_db().
   737 	 *
   768 	 *
   738 	 * @since 4.7.0
   769 	 * @since 4.7.0
       
   770 	 * @since 5.5.0 The `$avoid_die` parameter was renamed to `$wp_error`.
   739 	 *
   771 	 *
   740 	 * @param bool   $is_flood             Is a comment flooding occurring? Default false.
   772 	 * @param bool   $is_flood             Is a comment flooding occurring? Default false.
   741 	 * @param string $comment_author_IP    Comment author's IP address.
   773 	 * @param string $comment_author_IP    Comment author's IP address.
   742 	 * @param string $comment_author_email Comment author's email.
   774 	 * @param string $comment_author_email Comment author's email.
   743 	 * @param string $comment_date_gmt     GMT date the comment was posted.
   775 	 * @param string $comment_date_gmt     GMT date the comment was posted.
   744 	 * @param bool   $avoid_die            Whether to prevent executing wp_die()
   776 	 * @param bool   $wp_error             Whether to return a WP_Error object instead of executing
   745 	 *                                     or die() if a comment flood is occurring.
   777 	 *                                     wp_die() or die() if a comment flood is occurring.
   746 	 */
   778 	 */
   747 	$is_flood = apply_filters(
   779 	$is_flood = apply_filters(
   748 		'wp_is_comment_flood',
   780 		'wp_is_comment_flood',
   749 		false,
   781 		false,
   750 		$commentdata['comment_author_IP'],
   782 		$commentdata['comment_author_IP'],
   751 		$commentdata['comment_author_email'],
   783 		$commentdata['comment_author_email'],
   752 		$commentdata['comment_date_gmt'],
   784 		$commentdata['comment_date_gmt'],
   753 		$avoid_die
   785 		$wp_error
   754 	);
   786 	);
   755 
   787 
   756 	if ( $is_flood ) {
   788 	if ( $is_flood ) {
   757 		/** This filter is documented in wp-includes/comment-template.php */
   789 		/** This filter is documented in wp-includes/comment-template.php */
   758 		$comment_flood_message = apply_filters( 'comment_flood_message', __( 'You are posting comments too quickly. Slow down.' ) );
   790 		$comment_flood_message = apply_filters( 'comment_flood_message', __( 'You are posting comments too quickly. Slow down.' ) );
   787 			$approved = 1;
   819 			$approved = 1;
   788 		} else {
   820 		} else {
   789 			$approved = 0;
   821 			$approved = 0;
   790 		}
   822 		}
   791 
   823 
   792 		if ( wp_blacklist_check(
   824 		if ( wp_check_comment_disallowed_list(
   793 			$commentdata['comment_author'],
   825 			$commentdata['comment_author'],
   794 			$commentdata['comment_author_email'],
   826 			$commentdata['comment_author_email'],
   795 			$commentdata['comment_author_url'],
   827 			$commentdata['comment_author_url'],
   796 			$commentdata['comment_content'],
   828 			$commentdata['comment_content'],
   797 			$commentdata['comment_author_IP'],
   829 			$commentdata['comment_author_IP'],
   803 
   835 
   804 	/**
   836 	/**
   805 	 * Filters a comment's approval status before it is set.
   837 	 * Filters a comment's approval status before it is set.
   806 	 *
   838 	 *
   807 	 * @since 2.1.0
   839 	 * @since 2.1.0
   808 	 * @since 4.9.0 Returning a WP_Error value from the filter will shortcircuit comment insertion and
   840 	 * @since 4.9.0 Returning a WP_Error value from the filter will short-circuit comment insertion
   809 	 *              allow skipping further processing.
   841 	 *              and allow skipping further processing.
   810 	 *
   842 	 *
   811 	 * @param bool|string|WP_Error $approved    The approval status. Accepts 1, 0, 'spam' or WP_Error.
   843 	 * @param int|string|WP_Error $approved    The approval status. Accepts 1, 0, 'spam', 'trash',
   812 	 * @param array                $commentdata Comment data.
   844 	 *                                         or WP_Error.
   813 	 */
   845 	 * @param array               $commentdata Comment data.
   814 	$approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
   846 	 */
   815 	return $approved;
   847 	return apply_filters( 'pre_comment_approved', $approved, $commentdata );
   816 }
   848 }
   817 
   849 
   818 /**
   850 /**
   819  * Hooks WP's native database-based comment-flood check.
   851  * Hooks WP's native database-based comment-flood check.
   820  *
   852  *
   842  * @param bool   $is_flood  Is a comment flooding occurring?
   874  * @param bool   $is_flood  Is a comment flooding occurring?
   843  * @param string $ip        Comment author's IP address.
   875  * @param string $ip        Comment author's IP address.
   844  * @param string $email     Comment author's email address.
   876  * @param string $email     Comment author's email address.
   845  * @param string $date      MySQL time string.
   877  * @param string $date      MySQL time string.
   846  * @param bool   $avoid_die When true, a disallowed comment will result in the function
   878  * @param bool   $avoid_die When true, a disallowed comment will result in the function
   847  *                          returning a WP_Error object, rather than executing wp_die().
   879  *                          returning without executing wp_die() or die(). Default false.
   848  *                          Default false.
       
   849  * @return bool Whether comment flooding is occurring.
   880  * @return bool Whether comment flooding is occurring.
   850  */
   881  */
   851 function wp_check_comment_flood( $is_flood, $ip, $email, $date, $avoid_die = false ) {
   882 function wp_check_comment_flood( $is_flood, $ip, $email, $date, $avoid_die = false ) {
   852 
   883 
   853 	global $wpdb;
   884 	global $wpdb;
   855 	// Another callback has declared a flood. Trust it.
   886 	// Another callback has declared a flood. Trust it.
   856 	if ( true === $is_flood ) {
   887 	if ( true === $is_flood ) {
   857 		return $is_flood;
   888 		return $is_flood;
   858 	}
   889 	}
   859 
   890 
   860 	// don't throttle admins or moderators
   891 	// Don't throttle admins or moderators.
   861 	if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
   892 	if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
   862 		return false;
   893 		return false;
   863 	}
   894 	}
       
   895 
   864 	$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
   896 	$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
   865 
   897 
   866 	if ( is_user_logged_in() ) {
   898 	if ( is_user_logged_in() ) {
   867 		$user         = get_current_user_id();
   899 		$user         = get_current_user_id();
   868 		$check_column = '`user_id`';
   900 		$check_column = '`user_id`';
   869 	} else {
   901 	} else {
   870 		$user         = $ip;
   902 		$user         = $ip;
   871 		$check_column = '`comment_author_IP`';
   903 		$check_column = '`comment_author_IP`';
   872 	}
   904 	}
   873 
   905 
   874 	$sql      = $wpdb->prepare(
   906 	$sql = $wpdb->prepare(
   875 		"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",
   907 		"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",
   876 		$hour_ago,
   908 		$hour_ago,
   877 		$user,
   909 		$user,
   878 		$email
   910 		$email
   879 	);
   911 	);
       
   912 
   880 	$lasttime = $wpdb->get_var( $sql );
   913 	$lasttime = $wpdb->get_var( $sql );
       
   914 
   881 	if ( $lasttime ) {
   915 	if ( $lasttime ) {
   882 		$time_lastcomment = mysql2date( 'U', $lasttime, false );
   916 		$time_lastcomment = mysql2date( 'U', $lasttime, false );
   883 		$time_newcomment  = mysql2date( 'U', $date, false );
   917 		$time_newcomment  = mysql2date( 'U', $date, false );
       
   918 
   884 		/**
   919 		/**
   885 		 * Filters the comment flood status.
   920 		 * Filters the comment flood status.
   886 		 *
   921 		 *
   887 		 * @since 2.1.0
   922 		 * @since 2.1.0
   888 		 *
   923 		 *
   889 		 * @param bool $bool             Whether a comment flood is occurring. Default false.
   924 		 * @param bool $bool             Whether a comment flood is occurring. Default false.
   890 		 * @param int  $time_lastcomment Timestamp of when the last comment was posted.
   925 		 * @param int  $time_lastcomment Timestamp of when the last comment was posted.
   891 		 * @param int  $time_newcomment  Timestamp of when the new comment was posted.
   926 		 * @param int  $time_newcomment  Timestamp of when the new comment was posted.
   892 		 */
   927 		 */
   893 		$flood_die = apply_filters( 'comment_flood_filter', false, $time_lastcomment, $time_newcomment );
   928 		$flood_die = apply_filters( 'comment_flood_filter', false, $time_lastcomment, $time_newcomment );
       
   929 
   894 		if ( $flood_die ) {
   930 		if ( $flood_die ) {
   895 			/**
   931 			/**
   896 			 * Fires before the comment flood message is triggered.
   932 			 * Fires before the comment flood message is triggered.
   897 			 *
   933 			 *
   898 			 * @since 1.5.0
   934 			 * @since 1.5.0
   900 			 * @param int $time_lastcomment Timestamp of when the last comment was posted.
   936 			 * @param int $time_lastcomment Timestamp of when the last comment was posted.
   901 			 * @param int $time_newcomment  Timestamp of when the new comment was posted.
   937 			 * @param int $time_newcomment  Timestamp of when the new comment was posted.
   902 			 */
   938 			 */
   903 			do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
   939 			do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
   904 
   940 
   905 			if ( true === $avoid_die ) {
   941 			if ( $avoid_die ) {
   906 				return true;
   942 				return true;
   907 			} else {
   943 			} else {
   908 				/**
   944 				/**
   909 				 * Filters the comment flood error message.
   945 				 * Filters the comment flood error message.
   910 				 *
   946 				 *
   939 		'comment'   => array(),
   975 		'comment'   => array(),
   940 		'trackback' => array(),
   976 		'trackback' => array(),
   941 		'pingback'  => array(),
   977 		'pingback'  => array(),
   942 		'pings'     => array(),
   978 		'pings'     => array(),
   943 	);
   979 	);
   944 	$count            = count( $comments );
   980 
       
   981 	$count = count( $comments );
       
   982 
   945 	for ( $i = 0; $i < $count; $i++ ) {
   983 	for ( $i = 0; $i < $count; $i++ ) {
   946 		$type = $comments[ $i ]->comment_type;
   984 		$type = $comments[ $i ]->comment_type;
       
   985 
   947 		if ( empty( $type ) ) {
   986 		if ( empty( $type ) ) {
   948 			$type = 'comment';
   987 			$type = 'comment';
   949 		}
   988 		}
       
   989 
   950 		$comments_by_type[ $type ][] = &$comments[ $i ];
   990 		$comments_by_type[ $type ][] = &$comments[ $i ];
   951 		if ( 'trackback' == $type || 'pingback' == $type ) {
   991 
       
   992 		if ( 'trackback' === $type || 'pingback' === $type ) {
   952 			$comments_by_type['pings'][] = &$comments[ $i ];
   993 			$comments_by_type['pings'][] = &$comments[ $i ];
   953 		}
   994 		}
   954 	}
   995 	}
   955 
   996 
   956 	return $comments_by_type;
   997 	return $comments_by_type;
   961  *
  1002  *
   962  * @since 2.7.0
  1003  * @since 2.7.0
   963  *
  1004  *
   964  * @uses Walker_Comment
  1005  * @uses Walker_Comment
   965  *
  1006  *
   966  * @global WP_Query $wp_query
  1007  * @global WP_Query $wp_query WordPress Query object.
   967  *
  1008  *
   968  * @param WP_Comment[] $comments Optional. Array of WP_Comment objects. Defaults to $wp_query->comments.
  1009  * @param WP_Comment[] $comments Optional. Array of WP_Comment objects. Defaults to `$wp_query->comments`.
   969  * @param int          $per_page Optional. Comments per page.
  1010  * @param int          $per_page Optional. Comments per page.
   970  * @param bool         $threaded Optional. Control over flat or threaded comments.
  1011  * @param bool         $threaded Optional. Control over flat or threaded comments.
   971  * @return int Number of comment pages.
  1012  * @return int Number of comment pages.
   972  */
  1013  */
   973 function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
  1014 function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
  1020  *
  1061  *
  1021  * @global wpdb $wpdb WordPress database abstraction object.
  1062  * @global wpdb $wpdb WordPress database abstraction object.
  1022  *
  1063  *
  1023  * @param int   $comment_ID Comment ID.
  1064  * @param int   $comment_ID Comment ID.
  1024  * @param array $args {
  1065  * @param array $args {
  1025  *      Array of optional arguments.
  1066  *     Array of optional arguments.
  1026  *      @type string     $type      Limit paginated comments to those matching a given type. Accepts 'comment',
  1067  *
  1027  *                                  'trackback', 'pingback', 'pings' (trackbacks and pingbacks), or 'all'.
  1068  *     @type string     $type      Limit paginated comments to those matching a given type.
  1028  *                                  Default is 'all'.
  1069  *                                 Accepts 'comment', 'trackback', 'pingback', 'pings'
  1029  *      @type int        $per_page  Per-page count to use when calculating pagination. Defaults to the value of the
  1070  *                                 (trackbacks and pingbacks), or 'all'. Default 'all'.
  1030  *                                  'comments_per_page' option.
  1071  *     @type int        $per_page  Per-page count to use when calculating pagination.
  1031  *      @type int|string $max_depth If greater than 1, comment page will be determined for the top-level parent of
  1072  *                                 Defaults to the value of the 'comments_per_page' option.
  1032  *                                  `$comment_ID`. Defaults to the value of the 'thread_comments_depth' option.
  1073  *     @type int|string $max_depth If greater than 1, comment page will be determined
       
  1074  *                                 for the top-level parent `$comment_ID`.
       
  1075  *                                 Defaults to the value of the 'thread_comments_depth' option.
  1033  * } *
  1076  * } *
  1034  * @return int|null Comment page number or null on error.
  1077  * @return int|null Comment page number or null on error.
  1035  */
  1078  */
  1036 function get_page_of_comment( $comment_ID, $args = array() ) {
  1079 function get_page_of_comment( $comment_ID, $args = array() ) {
  1037 	global $wpdb;
  1080 	global $wpdb;
  1038 
  1081 
  1039 	$page = null;
  1082 	$page = null;
  1040 
  1083 
  1041 	if ( ! $comment = get_comment( $comment_ID ) ) {
  1084 	$comment = get_comment( $comment_ID );
       
  1085 	if ( ! $comment ) {
  1042 		return;
  1086 		return;
  1043 	}
  1087 	}
  1044 
  1088 
  1045 	$defaults      = array(
  1089 	$defaults      = array(
  1046 		'type'      => 'all',
  1090 		'type'      => 'all',
  1078 			} else {
  1122 			} else {
  1079 				$args['max_depth'] = -1;
  1123 				$args['max_depth'] = -1;
  1080 			}
  1124 			}
  1081 		}
  1125 		}
  1082 
  1126 
  1083 		// Find this comment's top level parent if threading is enabled
  1127 		// Find this comment's top-level parent if threading is enabled.
  1084 		if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent ) {
  1128 		if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent ) {
  1085 			return get_page_of_comment( $comment->comment_parent, $args );
  1129 			return get_page_of_comment( $comment->comment_parent, $args );
  1086 		}
  1130 		}
  1087 
  1131 
  1088 		$comment_args = array(
  1132 		$comment_args = array(
  1098 					'before' => $comment->comment_date_gmt,
  1142 					'before' => $comment->comment_date_gmt,
  1099 				),
  1143 				),
  1100 			),
  1144 			),
  1101 		);
  1145 		);
  1102 
  1146 
       
  1147 		if ( is_user_logged_in() ) {
       
  1148 			$comment_args['include_unapproved'] = array( get_current_user_id() );
       
  1149 		} else {
       
  1150 			$unapproved_email = wp_get_unapproved_comment_author_email();
       
  1151 
       
  1152 			if ( $unapproved_email ) {
       
  1153 				$comment_args['include_unapproved'] = array( $unapproved_email );
       
  1154 			}
       
  1155 		}
       
  1156 
       
  1157 		/**
       
  1158 		 * Filters the arguments used to query comments in get_page_of_comment().
       
  1159 		 *
       
  1160 		 * @since 5.5.0
       
  1161 		 *
       
  1162 		 * @see WP_Comment_Query::__construct()
       
  1163 		 *
       
  1164 		 * @param array $comment_args {
       
  1165 		 *     Array of WP_Comment_Query arguments.
       
  1166 		 *
       
  1167 		 *     @type string $type               Limit paginated comments to those matching a given type.
       
  1168 		 *                                      Accepts 'comment', 'trackback', 'pingback', 'pings'
       
  1169 		 *                                      (trackbacks and pingbacks), or 'all'. Default 'all'.
       
  1170 		 *     @type int    $post_id            ID of the post.
       
  1171 		 *     @type string $fields             Comment fields to return.
       
  1172 		 *     @type bool   $count              Whether to return a comment count (true) or array
       
  1173 		 *                                      of comment objects (false).
       
  1174 		 *     @type string $status             Comment status.
       
  1175 		 *     @type int    $parent             Parent ID of comment to retrieve children of.
       
  1176 		 *     @type array  $date_query         Date query clauses to limit comments by. See WP_Date_Query.
       
  1177 		 *     @type array  $include_unapproved Array of IDs or email addresses whose unapproved comments
       
  1178 		 *                                      will be included in paginated comments.
       
  1179 		 * }
       
  1180 		 */
       
  1181 		$comment_args = apply_filters( 'get_page_of_comment_query_args', $comment_args );
       
  1182 
  1103 		$comment_query       = new WP_Comment_Query();
  1183 		$comment_query       = new WP_Comment_Query();
  1104 		$older_comment_count = $comment_query->query( $comment_args );
  1184 		$older_comment_count = $comment_query->query( $comment_args );
  1105 
  1185 
  1106 		// No older comments? Then it's page #1.
  1186 		// No older comments? Then it's page #1.
  1107 		if ( 0 == $older_comment_count ) {
  1187 		if ( 0 == $older_comment_count ) {
  1108 			$page = 1;
  1188 			$page = 1;
  1109 
  1189 
  1110 			// Divide comments older than this one by comments per page to get this comment's page number
  1190 			// Divide comments older than this one by comments per page to get this comment's page number.
  1111 		} else {
  1191 		} else {
  1112 			$page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
  1192 			$page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
  1113 		}
  1193 		}
  1114 	}
  1194 	}
  1115 
  1195 
  1148  *
  1228  *
  1149  * @since 4.5.0
  1229  * @since 4.5.0
  1150  *
  1230  *
  1151  * @global wpdb $wpdb WordPress database abstraction object.
  1231  * @global wpdb $wpdb WordPress database abstraction object.
  1152  *
  1232  *
  1153  * @return array Maximum character length for the comment form fields.
  1233  * @return int[] Array of maximum lengths keyed by field name.
  1154  */
  1234  */
  1155 function wp_get_comment_fields_max_lengths() {
  1235 function wp_get_comment_fields_max_lengths() {
  1156 	global $wpdb;
  1236 	global $wpdb;
  1157 
  1237 
  1158 	$lengths = array(
  1238 	$lengths = array(
  1165 	if ( $wpdb->is_mysql ) {
  1245 	if ( $wpdb->is_mysql ) {
  1166 		foreach ( $lengths as $column => $length ) {
  1246 		foreach ( $lengths as $column => $length ) {
  1167 			$col_length = $wpdb->get_col_length( $wpdb->comments, $column );
  1247 			$col_length = $wpdb->get_col_length( $wpdb->comments, $column );
  1168 			$max_length = 0;
  1248 			$max_length = 0;
  1169 
  1249 
  1170 			// No point if we can't get the DB column lengths
  1250 			// No point if we can't get the DB column lengths.
  1171 			if ( is_wp_error( $col_length ) ) {
  1251 			if ( is_wp_error( $col_length ) ) {
  1172 				break;
  1252 				break;
  1173 			}
  1253 			}
  1174 
  1254 
  1175 			if ( ! is_array( $col_length ) && (int) $col_length > 0 ) {
  1255 			if ( ! is_array( $col_length ) && (int) $col_length > 0 ) {
  1191 	/**
  1271 	/**
  1192 	 * Filters the lengths for the comment form fields.
  1272 	 * Filters the lengths for the comment form fields.
  1193 	 *
  1273 	 *
  1194 	 * @since 4.5.0
  1274 	 * @since 4.5.0
  1195 	 *
  1275 	 *
  1196 	 * @param array $lengths Associative array `'field_name' => 'maximum length'`.
  1276 	 * @param int[] $lengths Array of maximum lengths keyed by field name.
  1197 	 */
  1277 	 */
  1198 	return apply_filters( 'wp_get_comment_fields_max_lengths', $lengths );
  1278 	return apply_filters( 'wp_get_comment_fields_max_lengths', $lengths );
  1199 }
  1279 }
  1200 
  1280 
  1201 /**
  1281 /**
  1209  */
  1289  */
  1210 function wp_check_comment_data_max_lengths( $comment_data ) {
  1290 function wp_check_comment_data_max_lengths( $comment_data ) {
  1211 	$max_lengths = wp_get_comment_fields_max_lengths();
  1291 	$max_lengths = wp_get_comment_fields_max_lengths();
  1212 
  1292 
  1213 	if ( isset( $comment_data['comment_author'] ) && mb_strlen( $comment_data['comment_author'], '8bit' ) > $max_lengths['comment_author'] ) {
  1293 	if ( isset( $comment_data['comment_author'] ) && mb_strlen( $comment_data['comment_author'], '8bit' ) > $max_lengths['comment_author'] ) {
  1214 		return new WP_Error( 'comment_author_column_length', __( '<strong>ERROR</strong>: your name is too long.' ), 200 );
  1294 		return new WP_Error( 'comment_author_column_length', __( '<strong>Error</strong>: Your name is too long.' ), 200 );
  1215 	}
  1295 	}
  1216 
  1296 
  1217 	if ( isset( $comment_data['comment_author_email'] ) && strlen( $comment_data['comment_author_email'] ) > $max_lengths['comment_author_email'] ) {
  1297 	if ( isset( $comment_data['comment_author_email'] ) && strlen( $comment_data['comment_author_email'] ) > $max_lengths['comment_author_email'] ) {
  1218 		return new WP_Error( 'comment_author_email_column_length', __( '<strong>ERROR</strong>: your email address is too long.' ), 200 );
  1298 		return new WP_Error( 'comment_author_email_column_length', __( '<strong>Error</strong>: Your email address is too long.' ), 200 );
  1219 	}
  1299 	}
  1220 
  1300 
  1221 	if ( isset( $comment_data['comment_author_url'] ) && strlen( $comment_data['comment_author_url'] ) > $max_lengths['comment_author_url'] ) {
  1301 	if ( isset( $comment_data['comment_author_url'] ) && strlen( $comment_data['comment_author_url'] ) > $max_lengths['comment_author_url'] ) {
  1222 		return new WP_Error( 'comment_author_url_column_length', __( '<strong>ERROR</strong>: your url is too long.' ), 200 );
  1302 		return new WP_Error( 'comment_author_url_column_length', __( '<strong>Error</strong>: Your URL is too long.' ), 200 );
  1223 	}
  1303 	}
  1224 
  1304 
  1225 	if ( isset( $comment_data['comment_content'] ) && mb_strlen( $comment_data['comment_content'], '8bit' ) > $max_lengths['comment_content'] ) {
  1305 	if ( isset( $comment_data['comment_content'] ) && mb_strlen( $comment_data['comment_content'], '8bit' ) > $max_lengths['comment_content'] ) {
  1226 		return new WP_Error( 'comment_content_column_length', __( '<strong>ERROR</strong>: your comment is too long.' ), 200 );
  1306 		return new WP_Error( 'comment_content_column_length', __( '<strong>Error</strong>: Your comment is too long.' ), 200 );
  1227 	}
  1307 	}
  1228 
  1308 
  1229 	return true;
  1309 	return true;
  1230 }
  1310 }
  1231 
  1311 
  1232 /**
  1312 /**
  1233  * Does comment contain blacklisted characters or words.
  1313  * Checks if a comment contains disallowed characters or words.
  1234  *
  1314  *
  1235  * @since 1.5.0
  1315  * @since 5.5.0
  1236  *
  1316  *
  1237  * @param string $author The author of the comment
  1317  * @param string $author The author of the comment
  1238  * @param string $email The email of the comment
  1318  * @param string $email The email of the comment
  1239  * @param string $url The url used in the comment
  1319  * @param string $url The url used in the comment
  1240  * @param string $comment The comment content
  1320  * @param string $comment The comment content
  1241  * @param string $user_ip The comment author's IP address
  1321  * @param string $user_ip The comment author's IP address
  1242  * @param string $user_agent The author's browser user agent
  1322  * @param string $user_agent The author's browser user agent
  1243  * @return bool True if comment contains blacklisted content, false if comment does not
  1323  * @return bool True if comment contains disallowed content, false if comment does not
  1244  */
  1324  */
  1245 function wp_blacklist_check( $author, $email, $url, $comment, $user_ip, $user_agent ) {
  1325 function wp_check_comment_disallowed_list( $author, $email, $url, $comment, $user_ip, $user_agent ) {
  1246 	/**
  1326 	/**
  1247 	 * Fires before the comment is tested for blacklisted characters or words.
  1327 	 * Fires before the comment is tested for disallowed characters or words.
  1248 	 *
  1328 	 *
  1249 	 * @since 1.5.0
  1329 	 * @since 1.5.0
       
  1330 	 * @deprecated 5.5.0 Use {@see 'wp_check_comment_disallowed_list'} instead.
  1250 	 *
  1331 	 *
  1251 	 * @param string $author     Comment author.
  1332 	 * @param string $author     Comment author.
  1252 	 * @param string $email      Comment author's email.
  1333 	 * @param string $email      Comment author's email.
  1253 	 * @param string $url        Comment author's URL.
  1334 	 * @param string $url        Comment author's URL.
  1254 	 * @param string $comment    Comment content.
  1335 	 * @param string $comment    Comment content.
  1255 	 * @param string $user_ip    Comment author's IP address.
  1336 	 * @param string $user_ip    Comment author's IP address.
  1256 	 * @param string $user_agent Comment author's browser user agent.
  1337 	 * @param string $user_agent Comment author's browser user agent.
  1257 	 */
  1338 	 */
  1258 	do_action( 'wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent );
  1339 	do_action_deprecated(
  1259 
  1340 		'wp_blacklist_check',
  1260 	$mod_keys = trim( get_option( 'blacklist_keys' ) );
  1341 		array( $author, $email, $url, $comment, $user_ip, $user_agent ),
  1261 	if ( '' == $mod_keys ) {
  1342 		'5.5.0',
  1262 		return false; // If moderation keys are empty
  1343 		'wp_check_comment_disallowed_list',
  1263 	}
  1344 		__( 'Please consider writing more inclusive code.' )
  1264 
  1345 	);
  1265 	// Ensure HTML tags are not being used to bypass the blacklist.
  1346 
       
  1347 	/**
       
  1348 	 * Fires before the comment is tested for disallowed characters or words.
       
  1349 	 *
       
  1350 	 * @since 5.5.0
       
  1351 	 *
       
  1352 	 * @param string $author     Comment author.
       
  1353 	 * @param string $email      Comment author's email.
       
  1354 	 * @param string $url        Comment author's URL.
       
  1355 	 * @param string $comment    Comment content.
       
  1356 	 * @param string $user_ip    Comment author's IP address.
       
  1357 	 * @param string $user_agent Comment author's browser user agent.
       
  1358 	 */
       
  1359 	do_action( 'wp_check_comment_disallowed_list', $author, $email, $url, $comment, $user_ip, $user_agent );
       
  1360 
       
  1361 	$mod_keys = trim( get_option( 'disallowed_keys' ) );
       
  1362 	if ( '' === $mod_keys ) {
       
  1363 		return false; // If moderation keys are empty.
       
  1364 	}
       
  1365 
       
  1366 	// Ensure HTML tags are not being used to bypass the list of disallowed characters and words.
  1266 	$comment_without_html = wp_strip_all_tags( $comment );
  1367 	$comment_without_html = wp_strip_all_tags( $comment );
  1267 
  1368 
  1268 	$words = explode( "\n", $mod_keys );
  1369 	$words = explode( "\n", $mod_keys );
  1269 
  1370 
  1270 	foreach ( (array) $words as $word ) {
  1371 	foreach ( (array) $words as $word ) {
  1271 		$word = trim( $word );
  1372 		$word = trim( $word );
  1272 
  1373 
  1273 		// Skip empty lines
  1374 		// Skip empty lines.
  1274 		if ( empty( $word ) ) {
  1375 		if ( empty( $word ) ) {
  1275 			continue; }
  1376 			continue; }
  1276 
  1377 
  1277 		// Do some escaping magic so that '#' chars in the
  1378 		// Do some escaping magic so that '#' chars
  1278 		// spam words don't break things:
  1379 		// in the spam words don't break things:
  1279 		$word = preg_quote( $word, '#' );
  1380 		$word = preg_quote( $word, '#' );
  1280 
  1381 
  1281 		$pattern = "#$word#i";
  1382 		$pattern = "#$word#i";
  1282 		if ( preg_match( $pattern, $author )
  1383 		if ( preg_match( $pattern, $author )
  1283 			|| preg_match( $pattern, $email )
  1384 			|| preg_match( $pattern, $email )
  1292 	}
  1393 	}
  1293 	return false;
  1394 	return false;
  1294 }
  1395 }
  1295 
  1396 
  1296 /**
  1397 /**
  1297  * Retrieve total comments for blog or single post.
  1398  * Retrieves the total comment counts for the whole site or a single post.
  1298  *
       
  1299  * The properties of the returned object contain the 'moderated', 'approved',
       
  1300  * and spam comments for either the entire blog or single post. Those properties
       
  1301  * contain the amount of comments that match the status. The 'total_comments'
       
  1302  * property contains the integer of total comments.
       
  1303  *
  1399  *
  1304  * The comment stats are cached and then retrieved, if they already exist in the
  1400  * The comment stats are cached and then retrieved, if they already exist in the
  1305  * cache.
  1401  * cache.
  1306  *
  1402  *
       
  1403  * @see get_comment_count() Which handles fetching the live comment counts.
       
  1404  *
  1307  * @since 2.5.0
  1405  * @since 2.5.0
  1308  *
  1406  *
  1309  * @param int $post_id Optional. Post ID.
  1407  * @param int $post_id Optional. Restrict the comment counts to the given post. Default 0, which indicates that
  1310  * @return object|array Comment stats.
  1408  *                     comment counts for the whole site will be retrieved.
       
  1409  * @return stdClass {
       
  1410  *     The number of comments keyed by their status.
       
  1411  *
       
  1412  *     @type int $approved       The number of approved comments.
       
  1413  *     @type int $moderated      The number of comments awaiting moderation (a.k.a. pending).
       
  1414  *     @type int $spam           The number of spam comments.
       
  1415  *     @type int $trash          The number of trashed comments.
       
  1416  *     @type int $post-trashed   The number of comments for posts that are in the trash.
       
  1417  *     @type int $total_comments The total number of non-trashed comments, including spam.
       
  1418  *     @type int $all            The total number of pending or approved comments.
       
  1419  * }
  1311  */
  1420  */
  1312 function wp_count_comments( $post_id = 0 ) {
  1421 function wp_count_comments( $post_id = 0 ) {
  1313 	$post_id = (int) $post_id;
  1422 	$post_id = (int) $post_id;
  1314 
  1423 
  1315 	/**
  1424 	/**
  1316 	 * Filters the comments count for a given post.
  1425 	 * Filters the comments count for a given post or the whole site.
  1317 	 *
  1426 	 *
  1318 	 * @since 2.7.0
  1427 	 * @since 2.7.0
  1319 	 *
  1428 	 *
  1320 	 * @param array $count   An empty array.
  1429 	 * @param array|stdClass $count   An empty array or an object containing comment counts.
  1321 	 * @param int   $post_id The post ID.
  1430 	 * @param int            $post_id The post ID. Can be 0 to represent the whole site.
  1322 	 */
  1431 	 */
  1323 	$filtered = apply_filters( 'wp_count_comments', array(), $post_id );
  1432 	$filtered = apply_filters( 'wp_count_comments', array(), $post_id );
  1324 	if ( ! empty( $filtered ) ) {
  1433 	if ( ! empty( $filtered ) ) {
  1325 		return $filtered;
  1434 		return $filtered;
  1326 	}
  1435 	}
  1341 }
  1450 }
  1342 
  1451 
  1343 /**
  1452 /**
  1344  * Trashes or deletes a comment.
  1453  * Trashes or deletes a comment.
  1345  *
  1454  *
  1346  * The comment is moved to trash instead of permanently deleted unless trash is
  1455  * The comment is moved to Trash instead of permanently deleted unless Trash is
  1347  * disabled, item is already in the trash, or $force_delete is true.
  1456  * disabled, item is already in the Trash, or $force_delete is true.
  1348  *
  1457  *
  1349  * The post comment count will be updated if the comment was approved and has a
  1458  * The post comment count will be updated if the comment was approved and has a
  1350  * post ID available.
  1459  * post ID available.
  1351  *
  1460  *
  1352  * @since 2.0.0
  1461  * @since 2.0.0
  1353  *
  1462  *
  1354  * @global wpdb $wpdb WordPress database abstraction object.
  1463  * @global wpdb $wpdb WordPress database abstraction object.
  1355  *
  1464  *
  1356  * @param int|WP_Comment $comment_id   Comment ID or WP_Comment object.
  1465  * @param int|WP_Comment $comment_id   Comment ID or WP_Comment object.
  1357  * @param bool           $force_delete Whether to bypass trash and force deletion. Default is false.
  1466  * @param bool           $force_delete Whether to bypass Trash and force deletion. Default false.
  1358  * @return bool True on success, false on failure.
  1467  * @return bool True on success, false on failure.
  1359  */
  1468  */
  1360 function wp_delete_comment( $comment_id, $force_delete = false ) {
  1469 function wp_delete_comment( $comment_id, $force_delete = false ) {
  1361 	global $wpdb;
  1470 	global $wpdb;
  1362 	if ( ! $comment = get_comment( $comment_id ) ) {
  1471 	$comment = get_comment( $comment_id );
       
  1472 	if ( ! $comment ) {
  1363 		return false;
  1473 		return false;
  1364 	}
  1474 	}
  1365 
  1475 
  1366 	if ( ! $force_delete && EMPTY_TRASH_DAYS && ! in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ) ) ) {
  1476 	if ( ! $force_delete && EMPTY_TRASH_DAYS && ! in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ), true ) ) {
  1367 		return wp_trash_comment( $comment_id );
  1477 		return wp_trash_comment( $comment_id );
  1368 	}
  1478 	}
  1369 
  1479 
  1370 	/**
  1480 	/**
  1371 	 * Fires immediately before a comment is deleted from the database.
  1481 	 * Fires immediately before a comment is deleted from the database.
  1383 	if ( ! empty( $children ) ) {
  1493 	if ( ! empty( $children ) ) {
  1384 		$wpdb->update( $wpdb->comments, array( 'comment_parent' => $comment->comment_parent ), array( 'comment_parent' => $comment->comment_ID ) );
  1494 		$wpdb->update( $wpdb->comments, array( 'comment_parent' => $comment->comment_parent ), array( 'comment_parent' => $comment->comment_ID ) );
  1385 		clean_comment_cache( $children );
  1495 		clean_comment_cache( $children );
  1386 	}
  1496 	}
  1387 
  1497 
  1388 	// Delete metadata
  1498 	// Delete metadata.
  1389 	$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
  1499 	$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
  1390 	foreach ( $meta_ids as $mid ) {
  1500 	foreach ( $meta_ids as $mid ) {
  1391 		delete_metadata_by_mid( 'comment', $mid );
  1501 		delete_metadata_by_mid( 'comment', $mid );
  1392 	}
  1502 	}
  1393 
  1503 
  1405 	 * @param WP_Comment $comment    The deleted comment.
  1515 	 * @param WP_Comment $comment    The deleted comment.
  1406 	 */
  1516 	 */
  1407 	do_action( 'deleted_comment', $comment->comment_ID, $comment );
  1517 	do_action( 'deleted_comment', $comment->comment_ID, $comment );
  1408 
  1518 
  1409 	$post_id = $comment->comment_post_ID;
  1519 	$post_id = $comment->comment_post_ID;
  1410 	if ( $post_id && $comment->comment_approved == 1 ) {
  1520 	if ( $post_id && 1 == $comment->comment_approved ) {
  1411 		wp_update_comment_count( $post_id );
  1521 		wp_update_comment_count( $post_id );
  1412 	}
  1522 	}
  1413 
  1523 
  1414 	clean_comment_cache( $comment->comment_ID );
  1524 	clean_comment_cache( $comment->comment_ID );
  1415 
  1525 
  1416 	/** This action is documented in wp-includes/comment.php */
  1526 	/** This action is documented in wp-includes/comment.php */
  1417 	do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
  1527 	do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
  1418 
  1528 
  1419 	wp_transition_comment_status( 'delete', $comment->comment_approved, $comment );
  1529 	wp_transition_comment_status( 'delete', $comment->comment_approved, $comment );
       
  1530 
  1420 	return true;
  1531 	return true;
  1421 }
  1532 }
  1422 
  1533 
  1423 /**
  1534 /**
  1424  * Moves a comment to the Trash
  1535  * Moves a comment to the Trash
  1425  *
  1536  *
  1426  * If trash is disabled, comment is permanently deleted.
  1537  * If Trash is disabled, comment is permanently deleted.
  1427  *
  1538  *
  1428  * @since 2.9.0
  1539  * @since 2.9.0
  1429  *
  1540  *
  1430  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1541  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1431  * @return bool True on success, false on failure.
  1542  * @return bool True on success, false on failure.
  1433 function wp_trash_comment( $comment_id ) {
  1544 function wp_trash_comment( $comment_id ) {
  1434 	if ( ! EMPTY_TRASH_DAYS ) {
  1545 	if ( ! EMPTY_TRASH_DAYS ) {
  1435 		return wp_delete_comment( $comment_id, true );
  1546 		return wp_delete_comment( $comment_id, true );
  1436 	}
  1547 	}
  1437 
  1548 
  1438 	if ( ! $comment = get_comment( $comment_id ) ) {
  1549 	$comment = get_comment( $comment_id );
       
  1550 	if ( ! $comment ) {
  1439 		return false;
  1551 		return false;
  1440 	}
  1552 	}
  1441 
  1553 
  1442 	/**
  1554 	/**
  1443 	 * Fires immediately before a comment is sent to the Trash.
  1555 	 * Fires immediately before a comment is sent to the Trash.
  1464 		 *
  1576 		 *
  1465 		 * @param int        $comment_id The comment ID.
  1577 		 * @param int        $comment_id The comment ID.
  1466 		 * @param WP_Comment $comment    The trashed comment.
  1578 		 * @param WP_Comment $comment    The trashed comment.
  1467 		 */
  1579 		 */
  1468 		do_action( 'trashed_comment', $comment->comment_ID, $comment );
  1580 		do_action( 'trashed_comment', $comment->comment_ID, $comment );
       
  1581 
  1469 		return true;
  1582 		return true;
  1470 	}
  1583 	}
  1471 
  1584 
  1472 	return false;
  1585 	return false;
  1473 }
  1586 }
  1503 	}
  1616 	}
  1504 
  1617 
  1505 	if ( wp_set_comment_status( $comment, $status ) ) {
  1618 	if ( wp_set_comment_status( $comment, $status ) ) {
  1506 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1619 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1507 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
  1620 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
       
  1621 
  1508 		/**
  1622 		/**
  1509 		 * Fires immediately after a comment is restored from the Trash.
  1623 		 * Fires immediately after a comment is restored from the Trash.
  1510 		 *
  1624 		 *
  1511 		 * @since 2.9.0
  1625 		 * @since 2.9.0
  1512 		 * @since 4.9.0 Added the `$comment` parameter.
  1626 		 * @since 4.9.0 Added the `$comment` parameter.
  1513 		 *
  1627 		 *
  1514 		 * @param int        $comment_id The comment ID.
  1628 		 * @param int        $comment_id The comment ID.
  1515 		 * @param WP_Comment $comment    The untrashed comment.
  1629 		 * @param WP_Comment $comment    The untrashed comment.
  1516 		 */
  1630 		 */
  1517 		do_action( 'untrashed_comment', $comment->comment_ID, $comment );
  1631 		do_action( 'untrashed_comment', $comment->comment_ID, $comment );
       
  1632 
  1518 		return true;
  1633 		return true;
  1519 	}
  1634 	}
  1520 
  1635 
  1521 	return false;
  1636 	return false;
  1522 }
  1637 }
  1549 	if ( wp_set_comment_status( $comment, 'spam' ) ) {
  1664 	if ( wp_set_comment_status( $comment, 'spam' ) ) {
  1550 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
  1665 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
  1551 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1666 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1552 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
  1667 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
  1553 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
  1668 		add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
       
  1669 
  1554 		/**
  1670 		/**
  1555 		 * Fires immediately after a comment is marked as Spam.
  1671 		 * Fires immediately after a comment is marked as Spam.
  1556 		 *
  1672 		 *
  1557 		 * @since 2.9.0
  1673 		 * @since 2.9.0
  1558 		 * @since 4.9.0 Added the `$comment` parameter.
  1674 		 * @since 4.9.0 Added the `$comment` parameter.
  1559 		 *
  1675 		 *
  1560 		 * @param int        $comment_id The comment ID.
  1676 		 * @param int        $comment_id The comment ID.
  1561 		 * @param WP_Comment $comment    The comment marked as spam.
  1677 		 * @param WP_Comment $comment    The comment marked as spam.
  1562 		 */
  1678 		 */
  1563 		do_action( 'spammed_comment', $comment->comment_ID, $comment );
  1679 		do_action( 'spammed_comment', $comment->comment_ID, $comment );
       
  1680 
  1564 		return true;
  1681 		return true;
  1565 	}
  1682 	}
  1566 
  1683 
  1567 	return false;
  1684 	return false;
  1568 }
  1685 }
  1598 	}
  1715 	}
  1599 
  1716 
  1600 	if ( wp_set_comment_status( $comment, $status ) ) {
  1717 	if ( wp_set_comment_status( $comment, $status ) ) {
  1601 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
  1718 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
  1602 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
  1719 		delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
       
  1720 
  1603 		/**
  1721 		/**
  1604 		 * Fires immediately after a comment is unmarked as Spam.
  1722 		 * Fires immediately after a comment is unmarked as Spam.
  1605 		 *
  1723 		 *
  1606 		 * @since 2.9.0
  1724 		 * @since 2.9.0
  1607 		 * @since 4.9.0 Added the `$comment` parameter.
  1725 		 * @since 4.9.0 Added the `$comment` parameter.
  1608 		 *
  1726 		 *
  1609 		 * @param int        $comment_id The comment ID.
  1727 		 * @param int        $comment_id The comment ID.
  1610 		 * @param WP_Comment $comment    The comment unmarked as spam.
  1728 		 * @param WP_Comment $comment    The comment unmarked as spam.
  1611 		 */
  1729 		 */
  1612 		do_action( 'unspammed_comment', $comment->comment_ID, $comment );
  1730 		do_action( 'unspammed_comment', $comment->comment_ID, $comment );
       
  1731 
  1613 		return true;
  1732 		return true;
  1614 	}
  1733 	}
  1615 
  1734 
  1616 	return false;
  1735 	return false;
  1617 }
  1736 }
  1620  * The status of a comment by ID.
  1739  * The status of a comment by ID.
  1621  *
  1740  *
  1622  * @since 1.0.0
  1741  * @since 1.0.0
  1623  *
  1742  *
  1624  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object
  1743  * @param int|WP_Comment $comment_id Comment ID or WP_Comment object
  1625  * @return false|string Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
  1744  * @return string|false Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
  1626  */
  1745  */
  1627 function wp_get_comment_status( $comment_id ) {
  1746 function wp_get_comment_status( $comment_id ) {
  1628 	$comment = get_comment( $comment_id );
  1747 	$comment = get_comment( $comment_id );
  1629 	if ( ! $comment ) {
  1748 	if ( ! $comment ) {
  1630 		return false;
  1749 		return false;
  1631 	}
  1750 	}
  1632 
  1751 
  1633 	$approved = $comment->comment_approved;
  1752 	$approved = $comment->comment_approved;
  1634 
  1753 
  1635 	if ( $approved == null ) {
  1754 	if ( null == $approved ) {
  1636 		return false;
  1755 		return false;
  1637 	} elseif ( $approved == '1' ) {
  1756 	} elseif ( '1' == $approved ) {
  1638 		return 'approved';
  1757 		return 'approved';
  1639 	} elseif ( $approved == '0' ) {
  1758 	} elseif ( '0' == $approved ) {
  1640 		return 'unapproved';
  1759 		return 'unapproved';
  1641 	} elseif ( $approved == 'spam' ) {
  1760 	} elseif ( 'spam' === $approved ) {
  1642 		return 'spam';
  1761 		return 'spam';
  1643 	} elseif ( $approved == 'trash' ) {
  1762 	} elseif ( 'trash' === $approved ) {
  1644 		return 'trash';
  1763 		return 'trash';
  1645 	} else {
  1764 	} else {
  1646 		return false;
  1765 		return false;
  1647 	}
  1766 	}
  1648 }
  1767 }
  1650 /**
  1769 /**
  1651  * Call hooks for when a comment status transition occurs.
  1770  * Call hooks for when a comment status transition occurs.
  1652  *
  1771  *
  1653  * Calls hooks for comment status transitions. If the new comment status is not the same
  1772  * Calls hooks for comment status transitions. If the new comment status is not the same
  1654  * as the previous comment status, then two hooks will be ran, the first is
  1773  * as the previous comment status, then two hooks will be ran, the first is
  1655  * {@see 'transition_comment_status'} with new status, old status, and comment data. The
  1774  * {@see 'transition_comment_status'} with new status, old status, and comment data.
  1656  * next action called is {@see comment_$old_status_to_$new_status'}. It has the
  1775  * The next action called is {@see 'comment_$old_status_to_$new_status'}. It has
  1657  * comment data.
  1776  * the comment data.
  1658  *
  1777  *
  1659  * The final action will run whether or not the comment statuses are the same. The
  1778  * The final action will run whether or not the comment statuses are the same.
  1660  * action is named {@see 'comment_$new_status_$comment->comment_type'}.
  1779  * The action is named {@see 'comment_$new_status_$comment->comment_type'}.
  1661  *
  1780  *
  1662  * @since 2.7.0
  1781  * @since 2.7.0
  1663  *
  1782  *
  1664  * @param string $new_status New comment status.
  1783  * @param string     $new_status New comment status.
  1665  * @param string $old_status Previous comment status.
  1784  * @param string     $old_status Previous comment status.
  1666  * @param object $comment Comment data.
  1785  * @param WP_Comment $comment    Comment object.
  1667  */
  1786  */
  1668 function wp_transition_comment_status( $new_status, $old_status, $comment ) {
  1787 function wp_transition_comment_status( $new_status, $old_status, $comment ) {
  1669 	/*
  1788 	/*
  1670 	 * Translate raw statuses to human readable formats for the hooks.
  1789 	 * Translate raw statuses to human-readable formats for the hooks.
  1671 	 * This is not a complete list of comment status, it's only the ones
  1790 	 * This is not a complete list of comment status, it's only the ones
  1672 	 * that need to be renamed
  1791 	 * that need to be renamed.
  1673 	 */
  1792 	 */
  1674 	$comment_statuses = array(
  1793 	$comment_statuses = array(
  1675 		0         => 'unapproved',
  1794 		0         => 'unapproved',
  1676 		'hold'    => 'unapproved', // wp_set_comment_status() uses "hold"
  1795 		'hold'    => 'unapproved', // wp_set_comment_status() uses "hold".
  1677 		1         => 'approved',
  1796 		1         => 'approved',
  1678 		'approve' => 'approved', // wp_set_comment_status() uses "approve"
  1797 		'approve' => 'approved',   // wp_set_comment_status() uses "approve".
  1679 	);
  1798 	);
  1680 	if ( isset( $comment_statuses[ $new_status ] ) ) {
  1799 	if ( isset( $comment_statuses[ $new_status ] ) ) {
  1681 		$new_status = $comment_statuses[ $new_status ];
  1800 		$new_status = $comment_statuses[ $new_status ];
  1682 	}
  1801 	}
  1683 	if ( isset( $comment_statuses[ $old_status ] ) ) {
  1802 	if ( isset( $comment_statuses[ $old_status ] ) ) {
  1684 		$old_status = $comment_statuses[ $old_status ];
  1803 		$old_status = $comment_statuses[ $old_status ];
  1685 	}
  1804 	}
  1686 
  1805 
  1687 	// Call the hooks
  1806 	// Call the hooks.
  1688 	if ( $new_status != $old_status ) {
  1807 	if ( $new_status != $old_status ) {
  1689 		/**
  1808 		/**
  1690 		 * Fires when the comment status is in transition.
  1809 		 * Fires when the comment status is in transition.
  1691 		 *
  1810 		 *
  1692 		 * @since 2.7.0
  1811 		 * @since 2.7.0
  1693 		 *
  1812 		 *
  1694 		 * @param int|string $new_status The new comment status.
  1813 		 * @param int|string $new_status The new comment status.
  1695 		 * @param int|string $old_status The old comment status.
  1814 		 * @param int|string $old_status The old comment status.
  1696 		 * @param object     $comment    The comment data.
  1815 		 * @param WP_Comment $comment    Comment object.
  1697 		 */
  1816 		 */
  1698 		do_action( 'transition_comment_status', $new_status, $old_status, $comment );
  1817 		do_action( 'transition_comment_status', $new_status, $old_status, $comment );
  1699 		/**
  1818 		/**
  1700 		 * Fires when the comment status is in transition from one specific status to another.
  1819 		 * Fires when the comment status is in transition from one specific status to another.
  1701 		 *
  1820 		 *
  1753  *
  1872  *
  1754  * @see sanitize_comment_cookies() Use to sanitize cookies
  1873  * @see sanitize_comment_cookies() Use to sanitize cookies
  1755  *
  1874  *
  1756  * @since 2.0.4
  1875  * @since 2.0.4
  1757  *
  1876  *
  1758  * @return array Comment author, email, url respectively.
  1877  * @return array {
       
  1878  *     An array of current commenter variables.
       
  1879  *
       
  1880  *     @type string $comment_author       The name of the current commenter, or an empty string.
       
  1881  *     @type string $comment_author_email The email address of the current commenter, or an empty string.
       
  1882  *     @type string $comment_author_url   The URL address of the current commenter, or an empty string.
       
  1883  * }
  1759  */
  1884  */
  1760 function wp_get_current_commenter() {
  1885 function wp_get_current_commenter() {
  1761 	// Cookies should already be sanitized.
  1886 	// Cookies should already be sanitized.
  1762 
  1887 
  1763 	$comment_author = '';
  1888 	$comment_author = '';
  1781 	 * @since 3.1.0
  1906 	 * @since 3.1.0
  1782 	 *
  1907 	 *
  1783 	 * @param array $comment_author_data {
  1908 	 * @param array $comment_author_data {
  1784 	 *     An array of current commenter variables.
  1909 	 *     An array of current commenter variables.
  1785 	 *
  1910 	 *
  1786 	 *     @type string $comment_author       The name of the author of the comment. Default empty.
  1911 	 *     @type string $comment_author       The name of the current commenter, or an empty string.
  1787 	 *     @type string $comment_author_email The email address of the `$comment_author`. Default empty.
  1912 	 *     @type string $comment_author_email The email address of the current commenter, or an empty string.
  1788 	 *     @type string $comment_author_url   The URL address of the `$comment_author`. Default empty.
  1913 	 *     @type string $comment_author_url   The URL address of the current commenter, or an empty string.
  1789 	 * }
  1914 	 * }
  1790 	 */
  1915 	 */
  1791 	return apply_filters( 'wp_get_current_commenter', compact( 'comment_author', 'comment_author_email', 'comment_author_url' ) );
  1916 	return apply_filters( 'wp_get_current_commenter', compact( 'comment_author', 'comment_author_email', 'comment_author_url' ) );
  1792 }
  1917 }
  1793 
  1918 
  1806 	if ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) {
  1931 	if ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) {
  1807 		$comment_id = (int) $_GET['unapproved'];
  1932 		$comment_id = (int) $_GET['unapproved'];
  1808 		$comment    = get_comment( $comment_id );
  1933 		$comment    = get_comment( $comment_id );
  1809 
  1934 
  1810 		if ( $comment && hash_equals( $_GET['moderation-hash'], wp_hash( $comment->comment_date_gmt ) ) ) {
  1935 		if ( $comment && hash_equals( $_GET['moderation-hash'], wp_hash( $comment->comment_date_gmt ) ) ) {
  1811 			$commenter_email = $comment->comment_author_email;
  1936 			// The comment will only be viewable by the comment author for 1 minute.
       
  1937 			$comment_preview_expires = strtotime( $comment->comment_date_gmt . '+1 minute' );
       
  1938 
       
  1939 			if ( time() < $comment_preview_expires ) {
       
  1940 				$commenter_email = $comment->comment_author_email;
       
  1941 			}
  1812 		}
  1942 		}
  1813 	}
  1943 	}
  1814 
  1944 
  1815 	if ( ! $commenter_email ) {
  1945 	if ( ! $commenter_email ) {
  1816 		$commenter       = wp_get_current_commenter();
  1946 		$commenter       = wp_get_current_commenter();
  1822 
  1952 
  1823 /**
  1953 /**
  1824  * Inserts a comment into the database.
  1954  * Inserts a comment into the database.
  1825  *
  1955  *
  1826  * @since 2.0.0
  1956  * @since 2.0.0
  1827  * @since 4.4.0 Introduced `$comment_meta` argument.
  1957  * @since 4.4.0 Introduced the `$comment_meta` argument.
       
  1958  * @since 5.5.0 Default value for `$comment_type` argument changed to `comment`.
  1828  *
  1959  *
  1829  * @global wpdb $wpdb WordPress database abstraction object.
  1960  * @global wpdb $wpdb WordPress database abstraction object.
  1830  *
  1961  *
  1831  * @param array $commentdata {
  1962  * @param array $commentdata {
  1832  *     Array of arguments for inserting a new comment.
  1963  *     Array of arguments for inserting a new comment.
  1846  *                                            Default is `$comment_date` in the site's GMT timezone.
  1977  *                                            Default is `$comment_date` in the site's GMT timezone.
  1847  *     @type int        $comment_karma        The karma of the comment. Default 0.
  1978  *     @type int        $comment_karma        The karma of the comment. Default 0.
  1848  *     @type int        $comment_parent       ID of this comment's parent, if any. Default 0.
  1979  *     @type int        $comment_parent       ID of this comment's parent, if any. Default 0.
  1849  *     @type int        $comment_post_ID      ID of the post that relates to the comment, if any.
  1980  *     @type int        $comment_post_ID      ID of the post that relates to the comment, if any.
  1850  *                                            Default 0.
  1981  *                                            Default 0.
  1851  *     @type string     $comment_type         Comment type. Default empty.
  1982  *     @type string     $comment_type         Comment type. Default 'comment'.
  1852  *     @type array      $comment_meta         Optional. Array of key/value pairs to be stored in commentmeta for the
  1983  *     @type array      $comment_meta         Optional. Array of key/value pairs to be stored in commentmeta for the
  1853  *                                            new comment.
  1984  *                                            new comment.
  1854  *     @type int        $user_id              ID of the user who submitted the comment. Default 0.
  1985  *     @type int        $user_id              ID of the user who submitted the comment. Default 0.
  1855  * }
  1986  * }
  1856  * @return int|false The new comment's ID on success, false on failure.
  1987  * @return int|false The new comment's ID on success, false on failure.
  1870 	$comment_post_ID  = ! isset( $data['comment_post_ID'] ) ? 0 : $data['comment_post_ID'];
  2001 	$comment_post_ID  = ! isset( $data['comment_post_ID'] ) ? 0 : $data['comment_post_ID'];
  1871 	$comment_content  = ! isset( $data['comment_content'] ) ? '' : $data['comment_content'];
  2002 	$comment_content  = ! isset( $data['comment_content'] ) ? '' : $data['comment_content'];
  1872 	$comment_karma    = ! isset( $data['comment_karma'] ) ? 0 : $data['comment_karma'];
  2003 	$comment_karma    = ! isset( $data['comment_karma'] ) ? 0 : $data['comment_karma'];
  1873 	$comment_approved = ! isset( $data['comment_approved'] ) ? 1 : $data['comment_approved'];
  2004 	$comment_approved = ! isset( $data['comment_approved'] ) ? 1 : $data['comment_approved'];
  1874 	$comment_agent    = ! isset( $data['comment_agent'] ) ? '' : $data['comment_agent'];
  2005 	$comment_agent    = ! isset( $data['comment_agent'] ) ? '' : $data['comment_agent'];
  1875 	$comment_type     = ! isset( $data['comment_type'] ) ? '' : $data['comment_type'];
  2006 	$comment_type     = empty( $data['comment_type'] ) ? 'comment' : $data['comment_type'];
  1876 	$comment_parent   = ! isset( $data['comment_parent'] ) ? 0 : $data['comment_parent'];
  2007 	$comment_parent   = ! isset( $data['comment_parent'] ) ? 0 : $data['comment_parent'];
  1877 
  2008 
  1878 	$user_id = ! isset( $data['user_id'] ) ? 0 : $data['user_id'];
  2009 	$user_id = ! isset( $data['user_id'] ) ? 0 : $data['user_id'];
  1879 
  2010 
  1880 	$compacted = compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id' );
  2011 	$compacted = compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id' );
  1882 		return false;
  2013 		return false;
  1883 	}
  2014 	}
  1884 
  2015 
  1885 	$id = (int) $wpdb->insert_id;
  2016 	$id = (int) $wpdb->insert_id;
  1886 
  2017 
  1887 	if ( $comment_approved == 1 ) {
  2018 	if ( 1 == $comment_approved ) {
  1888 		wp_update_comment_count( $comment_post_ID );
  2019 		wp_update_comment_count( $comment_post_ID );
  1889 
  2020 
  1890 		foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
  2021 		foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
  1891 			wp_cache_delete( "lastcommentmodified:$timezone", 'timeinfo' );
  2022 			wp_cache_delete( "lastcommentmodified:$timezone", 'timeinfo' );
  1892 		}
  2023 		}
  1929  * @return array Parsed comment information.
  2060  * @return array Parsed comment information.
  1930  */
  2061  */
  1931 function wp_filter_comment( $commentdata ) {
  2062 function wp_filter_comment( $commentdata ) {
  1932 	if ( isset( $commentdata['user_ID'] ) ) {
  2063 	if ( isset( $commentdata['user_ID'] ) ) {
  1933 		/**
  2064 		/**
  1934 		 * Filters the comment author's user id before it is set.
  2065 		 * Filters the comment author's user ID before it is set.
  1935 		 *
  2066 		 *
  1936 		 * The first time this filter is evaluated, 'user_ID' is checked
  2067 		 * The first time this filter is evaluated, 'user_ID' is checked
  1937 		 * (for back-compat), followed by the standard 'user_id' value.
  2068 		 * (for back-compat), followed by the standard 'user_id' value.
  1938 		 *
  2069 		 *
  1939 		 * @since 1.5.0
  2070 		 * @since 1.5.0
  1983 /**
  2114 /**
  1984  * Whether a comment should be blocked because of comment flood.
  2115  * Whether a comment should be blocked because of comment flood.
  1985  *
  2116  *
  1986  * @since 2.1.0
  2117  * @since 2.1.0
  1987  *
  2118  *
  1988  * @param bool $block Whether plugin has already blocked comment.
  2119  * @param bool $block            Whether plugin has already blocked comment.
  1989  * @param int $time_lastcomment Timestamp for last comment.
  2120  * @param int  $time_lastcomment Timestamp for last comment.
  1990  * @param int $time_newcomment Timestamp for new comment.
  2121  * @param int  $time_newcomment  Timestamp for new comment.
  1991  * @return bool Whether comment should be blocked.
  2122  * @return bool Whether comment should be blocked.
  1992  */
  2123  */
  1993 function wp_throttle_comment_flood( $block, $time_lastcomment, $time_newcomment ) {
  2124 function wp_throttle_comment_flood( $block, $time_lastcomment, $time_newcomment ) {
  1994 	if ( $block ) { // a plugin has already blocked... we'll let that decision stand
  2125 	if ( $block ) { // A plugin has already blocked... we'll let that decision stand.
  1995 		return $block;
  2126 		return $block;
  1996 	}
  2127 	}
  1997 	if ( ( $time_newcomment - $time_lastcomment ) < 15 ) {
  2128 	if ( ( $time_newcomment - $time_lastcomment ) < 15 ) {
  1998 		return true;
  2129 		return true;
  1999 	}
  2130 	}
  2012  * that it is properly set, such as in wp-config.php, for your environment.
  2143  * that it is properly set, such as in wp-config.php, for your environment.
  2013  *
  2144  *
  2014  * See {@link https://core.trac.wordpress.org/ticket/9235}
  2145  * See {@link https://core.trac.wordpress.org/ticket/9235}
  2015  *
  2146  *
  2016  * @since 1.5.0
  2147  * @since 1.5.0
  2017  * @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
  2148  * @since 4.3.0 Introduced the `comment_agent` and `comment_author_IP` arguments.
  2018  * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function to
  2149  * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function
  2019  *              return a WP_Error object instead of dying.
  2150  *              to return a WP_Error object instead of dying.
       
  2151  * @since 5.5.0 The `$avoid_die` parameter was renamed to `$wp_error`.
       
  2152  * @since 5.5.0 Introduced the `comment_type` argument.
  2020  *
  2153  *
  2021  * @see wp_insert_comment()
  2154  * @see wp_insert_comment()
  2022  * @global wpdb $wpdb WordPress database abstraction object.
  2155  * @global wpdb $wpdb WordPress database abstraction object.
  2023  *
  2156  *
  2024  * @param array $commentdata {
  2157  * @param array $commentdata {
  2029  *     @type string $comment_author_url   The comment author URL.
  2162  *     @type string $comment_author_url   The comment author URL.
  2030  *     @type string $comment_content      The content of the comment.
  2163  *     @type string $comment_content      The content of the comment.
  2031  *     @type string $comment_date         The date the comment was submitted. Default is the current time.
  2164  *     @type string $comment_date         The date the comment was submitted. Default is the current time.
  2032  *     @type string $comment_date_gmt     The date the comment was submitted in the GMT timezone.
  2165  *     @type string $comment_date_gmt     The date the comment was submitted in the GMT timezone.
  2033  *                                        Default is `$comment_date` in the GMT timezone.
  2166  *                                        Default is `$comment_date` in the GMT timezone.
       
  2167  *     @type string $comment_type         Comment type. Default 'comment'.
  2034  *     @type int    $comment_parent       The ID of this comment's parent, if any. Default 0.
  2168  *     @type int    $comment_parent       The ID of this comment's parent, if any. Default 0.
  2035  *     @type int    $comment_post_ID      The ID of the post that relates to the comment.
  2169  *     @type int    $comment_post_ID      The ID of the post that relates to the comment.
  2036  *     @type int    $user_id              The ID of the user who submitted the comment. Default 0.
  2170  *     @type int    $user_id              The ID of the user who submitted the comment. Default 0.
  2037  *     @type int    $user_ID              Kept for backward-compatibility. Use `$user_id` instead.
  2171  *     @type int    $user_ID              Kept for backward-compatibility. Use `$user_id` instead.
  2038  *     @type string $comment_agent        Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
  2172  *     @type string $comment_agent        Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
  2039  *                                        in the `$_SERVER` superglobal sent in the original request.
  2173  *                                        in the `$_SERVER` superglobal sent in the original request.
  2040  *     @type string $comment_author_IP    Comment author IP address in IPv4 format. Default is the value of
  2174  *     @type string $comment_author_IP    Comment author IP address in IPv4 format. Default is the value of
  2041  *                                        'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
  2175  *                                        'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
  2042  * }
  2176  * }
  2043  * @param bool $avoid_die Should errors be returned as WP_Error objects instead of
  2177  * @param bool  $wp_error Should errors be returned as WP_Error objects instead of
  2044  *                        executing wp_die()? Default false.
  2178  *                        executing wp_die()? Default false.
  2045  * @return int|false|WP_Error The ID of the comment on success, false or WP_Error on failure.
  2179  * @return int|false|WP_Error The ID of the comment on success, false or WP_Error on failure.
  2046  */
  2180  */
  2047 function wp_new_comment( $commentdata, $avoid_die = false ) {
  2181 function wp_new_comment( $commentdata, $wp_error = false ) {
  2048 	global $wpdb;
  2182 	global $wpdb;
  2049 
  2183 
  2050 	if ( isset( $commentdata['user_ID'] ) ) {
  2184 	if ( isset( $commentdata['user_ID'] ) ) {
  2051 		$commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
  2185 		$commentdata['user_ID'] = (int) $commentdata['user_ID'];
       
  2186 		$commentdata['user_id'] = $commentdata['user_ID'];
  2052 	}
  2187 	}
  2053 
  2188 
  2054 	$prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
  2189 	$prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
  2055 
  2190 
  2056 	/**
  2191 	/**
  2062 	 */
  2197 	 */
  2063 	$commentdata = apply_filters( 'preprocess_comment', $commentdata );
  2198 	$commentdata = apply_filters( 'preprocess_comment', $commentdata );
  2064 
  2199 
  2065 	$commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
  2200 	$commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
  2066 	if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
  2201 	if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
  2067 		$commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
  2202 		$commentdata['user_ID'] = (int) $commentdata['user_ID'];
       
  2203 		$commentdata['user_id'] = $commentdata['user_ID'];
  2068 	} elseif ( isset( $commentdata['user_id'] ) ) {
  2204 	} elseif ( isset( $commentdata['user_id'] ) ) {
  2069 		$commentdata['user_id'] = (int) $commentdata['user_id'];
  2205 		$commentdata['user_id'] = (int) $commentdata['user_id'];
  2070 	}
  2206 	}
  2071 
  2207 
  2072 	$commentdata['comment_parent'] = isset( $commentdata['comment_parent'] ) ? absint( $commentdata['comment_parent'] ) : 0;
  2208 	$commentdata['comment_parent'] = isset( $commentdata['comment_parent'] ) ? absint( $commentdata['comment_parent'] ) : 0;
  2073 	$parent_status                 = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status( $commentdata['comment_parent'] ) : '';
  2209 
  2074 	$commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
  2210 	$parent_status = ( $commentdata['comment_parent'] > 0 ) ? wp_get_comment_status( $commentdata['comment_parent'] ) : '';
       
  2211 
       
  2212 	$commentdata['comment_parent'] = ( 'approved' === $parent_status || 'unapproved' === $parent_status ) ? $commentdata['comment_parent'] : 0;
  2075 
  2213 
  2076 	if ( ! isset( $commentdata['comment_author_IP'] ) ) {
  2214 	if ( ! isset( $commentdata['comment_author_IP'] ) ) {
  2077 		$commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
  2215 		$commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
  2078 	}
  2216 	}
  2079 	$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
  2217 	$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
  2089 
  2227 
  2090 	if ( empty( $commentdata['comment_date_gmt'] ) ) {
  2228 	if ( empty( $commentdata['comment_date_gmt'] ) ) {
  2091 		$commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
  2229 		$commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
  2092 	}
  2230 	}
  2093 
  2231 
       
  2232 	if ( empty( $commentdata['comment_type'] ) ) {
       
  2233 		$commentdata['comment_type'] = 'comment';
       
  2234 	}
       
  2235 
  2094 	$commentdata = wp_filter_comment( $commentdata );
  2236 	$commentdata = wp_filter_comment( $commentdata );
  2095 
  2237 
  2096 	$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
  2238 	$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $wp_error );
  2097 	if ( is_wp_error( $commentdata['comment_approved'] ) ) {
  2239 	if ( is_wp_error( $commentdata['comment_approved'] ) ) {
  2098 		return $commentdata['comment_approved'];
  2240 		return $commentdata['comment_approved'];
  2099 	}
  2241 	}
  2100 
  2242 
  2101 	$comment_ID = wp_insert_comment( $commentdata );
  2243 	$comment_ID = wp_insert_comment( $commentdata );
  2108 			}
  2250 			}
  2109 		}
  2251 		}
  2110 
  2252 
  2111 		$commentdata = wp_filter_comment( $commentdata );
  2253 		$commentdata = wp_filter_comment( $commentdata );
  2112 
  2254 
  2113 		$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );
  2255 		$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $wp_error );
  2114 		if ( is_wp_error( $commentdata['comment_approved'] ) ) {
  2256 		if ( is_wp_error( $commentdata['comment_approved'] ) ) {
  2115 			return $commentdata['comment_approved'];
  2257 			return $commentdata['comment_approved'];
  2116 		}
  2258 		}
  2117 
  2259 
  2118 		$comment_ID = wp_insert_comment( $commentdata );
  2260 		$comment_ID = wp_insert_comment( $commentdata );
  2213  *
  2355  *
  2214  * @global wpdb $wpdb WordPress database abstraction object.
  2356  * @global wpdb $wpdb WordPress database abstraction object.
  2215  *
  2357  *
  2216  * @param int|WP_Comment $comment_id     Comment ID or WP_Comment object.
  2358  * @param int|WP_Comment $comment_id     Comment ID or WP_Comment object.
  2217  * @param string         $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
  2359  * @param string         $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
  2218  * @param bool           $wp_error       Whether to return a WP_Error object if there is a failure. Default is false.
  2360  * @param bool           $wp_error       Whether to return a WP_Error object if there is a failure. Default false.
  2219  * @return bool|WP_Error True on success, false or WP_Error on failure.
  2361  * @return bool|WP_Error True on success, false or WP_Error on failure.
  2220  */
  2362  */
  2221 function wp_set_comment_status( $comment_id, $comment_status, $wp_error = false ) {
  2363 function wp_set_comment_status( $comment_id, $comment_status, $wp_error = false ) {
  2222 	global $wpdb;
  2364 	global $wpdb;
  2223 
  2365 
  2243 
  2385 
  2244 	$comment_old = clone get_comment( $comment_id );
  2386 	$comment_old = clone get_comment( $comment_id );
  2245 
  2387 
  2246 	if ( ! $wpdb->update( $wpdb->comments, array( 'comment_approved' => $status ), array( 'comment_ID' => $comment_old->comment_ID ) ) ) {
  2388 	if ( ! $wpdb->update( $wpdb->comments, array( 'comment_approved' => $status ), array( 'comment_ID' => $comment_old->comment_ID ) ) ) {
  2247 		if ( $wp_error ) {
  2389 		if ( $wp_error ) {
  2248 			return new WP_Error( 'db_update_error', __( 'Could not update comment status' ), $wpdb->last_error );
  2390 			return new WP_Error( 'db_update_error', __( 'Could not update comment status.' ), $wpdb->last_error );
  2249 		} else {
  2391 		} else {
  2250 			return false;
  2392 			return false;
  2251 		}
  2393 		}
  2252 	}
  2394 	}
  2253 
  2395 
  2279  *
  2421  *
  2280  * Filters the comment and makes sure certain fields are valid before updating.
  2422  * Filters the comment and makes sure certain fields are valid before updating.
  2281  *
  2423  *
  2282  * @since 2.0.0
  2424  * @since 2.0.0
  2283  * @since 4.9.0 Add updating comment meta during comment update.
  2425  * @since 4.9.0 Add updating comment meta during comment update.
       
  2426  * @since 5.5.0 The `$wp_error` parameter was added.
       
  2427  * @since 5.5.0 The return values for an invalid comment or post ID
       
  2428  *              were changed to false instead of 0.
  2284  *
  2429  *
  2285  * @global wpdb $wpdb WordPress database abstraction object.
  2430  * @global wpdb $wpdb WordPress database abstraction object.
  2286  *
  2431  *
  2287  * @param array $commentarr Contains information on the comment.
  2432  * @param array $commentarr Contains information on the comment.
  2288  * @return int Comment was updated if value is 1, or was not updated if value is 0.
  2433  * @param bool  $wp_error   Optional. Whether to return a WP_Error on failure. Default false.
  2289  */
  2434  * @return int|false|WP_Error The value 1 if the comment was updated, 0 if not updated.
  2290 function wp_update_comment( $commentarr ) {
  2435  *                            False or a WP_Error object on failure.
       
  2436  */
       
  2437 function wp_update_comment( $commentarr, $wp_error = false ) {
  2291 	global $wpdb;
  2438 	global $wpdb;
  2292 
  2439 
  2293 	// First, get all of the original fields
  2440 	// First, get all of the original fields.
  2294 	$comment = get_comment( $commentarr['comment_ID'], ARRAY_A );
  2441 	$comment = get_comment( $commentarr['comment_ID'], ARRAY_A );
  2295 	if ( empty( $comment ) ) {
  2442 	if ( empty( $comment ) ) {
  2296 		return 0;
  2443 		if ( $wp_error ) {
       
  2444 			return new WP_Error( 'invalid_comment_id', __( 'Invalid comment ID.' ) );
       
  2445 		} else {
       
  2446 			return false;
       
  2447 		}
  2297 	}
  2448 	}
  2298 
  2449 
  2299 	// Make sure that the comment post ID is valid (if specified).
  2450 	// Make sure that the comment post ID is valid (if specified).
  2300 	if ( ! empty( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
  2451 	if ( ! empty( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
  2301 		return 0;
  2452 		if ( $wp_error ) {
       
  2453 			return new WP_Error( 'invalid_post_id', __( 'Invalid post ID.' ) );
       
  2454 		} else {
       
  2455 			return false;
       
  2456 		}
  2302 	}
  2457 	}
  2303 
  2458 
  2304 	// Escape data pulled from DB.
  2459 	// Escape data pulled from DB.
  2305 	$comment = wp_slash( $comment );
  2460 	$comment = wp_slash( $comment );
  2306 
  2461 
  2325 
  2480 
  2326 	$data['comment_date_gmt'] = get_gmt_from_date( $data['comment_date'] );
  2481 	$data['comment_date_gmt'] = get_gmt_from_date( $data['comment_date'] );
  2327 
  2482 
  2328 	if ( ! isset( $data['comment_approved'] ) ) {
  2483 	if ( ! isset( $data['comment_approved'] ) ) {
  2329 		$data['comment_approved'] = 1;
  2484 		$data['comment_approved'] = 1;
  2330 	} elseif ( 'hold' == $data['comment_approved'] ) {
  2485 	} elseif ( 'hold' === $data['comment_approved'] ) {
  2331 		$data['comment_approved'] = 0;
  2486 		$data['comment_approved'] = 0;
  2332 	} elseif ( 'approve' == $data['comment_approved'] ) {
  2487 	} elseif ( 'approve' === $data['comment_approved'] ) {
  2333 		$data['comment_approved'] = 1;
  2488 		$data['comment_approved'] = 1;
  2334 	}
  2489 	}
  2335 
  2490 
  2336 	$comment_ID      = $data['comment_ID'];
  2491 	$comment_ID      = $data['comment_ID'];
  2337 	$comment_post_ID = $data['comment_post_ID'];
  2492 	$comment_post_ID = $data['comment_post_ID'];
  2340 	 * Filters the comment data immediately before it is updated in the database.
  2495 	 * Filters the comment data immediately before it is updated in the database.
  2341 	 *
  2496 	 *
  2342 	 * Note: data being passed to the filter is already unslashed.
  2497 	 * Note: data being passed to the filter is already unslashed.
  2343 	 *
  2498 	 *
  2344 	 * @since 4.7.0
  2499 	 * @since 4.7.0
  2345 	 *
  2500 	 * @since 5.5.0 Returning a WP_Error value from the filter will short-circuit comment update
  2346 	 * @param array $data       The new, processed comment data.
  2501 	 *              and allow skipping further processing.
  2347 	 * @param array $comment    The old, unslashed comment data.
  2502 	 *
  2348 	 * @param array $commentarr The new, raw comment data.
  2503 	 * @param array|WP_Error $data       The new, processed comment data, or WP_Error.
       
  2504 	 * @param array          $comment    The old, unslashed comment data.
       
  2505 	 * @param array          $commentarr The new, raw comment data.
  2349 	 */
  2506 	 */
  2350 	$data = apply_filters( 'wp_update_comment_data', $data, $comment, $commentarr );
  2507 	$data = apply_filters( 'wp_update_comment_data', $data, $comment, $commentarr );
       
  2508 
       
  2509 	// Do not carry on on failure.
       
  2510 	if ( is_wp_error( $data ) ) {
       
  2511 		if ( $wp_error ) {
       
  2512 			return $data;
       
  2513 		} else {
       
  2514 			return false;
       
  2515 		}
       
  2516 	}
  2351 
  2517 
  2352 	$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' );
  2518 	$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' );
  2353 	$data = wp_array_slice_assoc( $data, $keys );
  2519 	$data = wp_array_slice_assoc( $data, $keys );
  2354 
  2520 
  2355 	$rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
  2521 	$rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
       
  2522 
       
  2523 	if ( false === $rval ) {
       
  2524 		if ( $wp_error ) {
       
  2525 			return new WP_Error( 'db_update_error', __( 'Could not update comment in the database.' ), $wpdb->last_error );
       
  2526 		} else {
       
  2527 			return false;
       
  2528 		}
       
  2529 	}
  2356 
  2530 
  2357 	// If metadata is provided, store it.
  2531 	// If metadata is provided, store it.
  2358 	if ( isset( $commentarr['comment_meta'] ) && is_array( $commentarr['comment_meta'] ) ) {
  2532 	if ( isset( $commentarr['comment_meta'] ) && is_array( $commentarr['comment_meta'] ) ) {
  2359 		foreach ( $commentarr['comment_meta'] as $meta_key => $meta_value ) {
  2533 		foreach ( $commentarr['comment_meta'] as $meta_key => $meta_value ) {
  2360 			update_comment_meta( $comment_ID, $meta_key, $meta_value );
  2534 			update_comment_meta( $comment_ID, $meta_key, $meta_value );
  2361 		}
  2535 		}
  2362 	}
  2536 	}
  2363 
  2537 
  2364 	clean_comment_cache( $comment_ID );
  2538 	clean_comment_cache( $comment_ID );
  2365 	wp_update_comment_count( $comment_post_ID );
  2539 	wp_update_comment_count( $comment_post_ID );
       
  2540 
  2366 	/**
  2541 	/**
  2367 	 * Fires immediately after a comment is updated in the database.
  2542 	 * Fires immediately after a comment is updated in the database.
  2368 	 *
  2543 	 *
  2369 	 * The hook also fires immediately before comment status transition hooks are fired.
  2544 	 * The hook also fires immediately before comment status transition hooks are fired.
  2370 	 *
  2545 	 *
  2373 	 *
  2548 	 *
  2374 	 * @param int   $comment_ID The comment ID.
  2549 	 * @param int   $comment_ID The comment ID.
  2375 	 * @param array $data       Comment data.
  2550 	 * @param array $data       Comment data.
  2376 	 */
  2551 	 */
  2377 	do_action( 'edit_comment', $comment_ID, $data );
  2552 	do_action( 'edit_comment', $comment_ID, $data );
       
  2553 
  2378 	$comment = get_comment( $comment_ID );
  2554 	$comment = get_comment( $comment_ID );
       
  2555 
  2379 	wp_transition_comment_status( $comment->comment_approved, $old_status, $comment );
  2556 	wp_transition_comment_status( $comment->comment_approved, $old_status, $comment );
       
  2557 
  2380 	return $rval;
  2558 	return $rval;
  2381 }
  2559 }
  2382 
  2560 
  2383 /**
  2561 /**
  2384  * Whether to defer comment counting.
  2562  * Whether to defer comment counting.
  2387  * until $defer is set to false. When $defer is set to false, then all
  2565  * until $defer is set to false. When $defer is set to false, then all
  2388  * previously deferred updated post comment counts will then be automatically
  2566  * previously deferred updated post comment counts will then be automatically
  2389  * updated without having to call wp_update_comment_count() after.
  2567  * updated without having to call wp_update_comment_count() after.
  2390  *
  2568  *
  2391  * @since 2.5.0
  2569  * @since 2.5.0
  2392  * @staticvar bool $_defer
       
  2393  *
  2570  *
  2394  * @param bool $defer
  2571  * @param bool $defer
  2395  * @return bool
  2572  * @return bool
  2396  */
  2573  */
  2397 function wp_defer_comment_counting( $defer = null ) {
  2574 function wp_defer_comment_counting( $defer = null ) {
  2398 	static $_defer = false;
  2575 	static $_defer = false;
  2399 
  2576 
  2400 	if ( is_bool( $defer ) ) {
  2577 	if ( is_bool( $defer ) ) {
  2401 		$_defer = $defer;
  2578 		$_defer = $defer;
  2402 		// flush any deferred counts
  2579 		// Flush any deferred counts.
  2403 		if ( ! $defer ) {
  2580 		if ( ! $defer ) {
  2404 			wp_update_comment_count( null, true );
  2581 			wp_update_comment_count( null, true );
  2405 		}
  2582 		}
  2406 	}
  2583 	}
  2407 
  2584 
  2418  * If the comments have not be set up to be deferred, then the post will be
  2595  * If the comments have not be set up to be deferred, then the post will be
  2419  * updated. When $do_deferred is set to true, then all previous deferred post
  2596  * updated. When $do_deferred is set to true, then all previous deferred post
  2420  * IDs will be updated along with the current $post_id.
  2597  * IDs will be updated along with the current $post_id.
  2421  *
  2598  *
  2422  * @since 2.1.0
  2599  * @since 2.1.0
       
  2600  *
  2423  * @see wp_update_comment_count_now() For what could cause a false return value
  2601  * @see wp_update_comment_count_now() For what could cause a false return value
  2424  *
       
  2425  * @staticvar array $_deferred
       
  2426  *
  2602  *
  2427  * @param int|null $post_id     Post ID.
  2603  * @param int|null $post_id     Post ID.
  2428  * @param bool     $do_deferred Optional. Whether to process previously deferred
  2604  * @param bool     $do_deferred Optional. Whether to process previously deferred
  2429  *                              post comment counts. Default false.
  2605  *                              post comment counts. Default false.
  2430  * @return bool|void True on success, false on failure or if post with ID does
  2606  * @return bool|void True on success, false on failure or if post with ID does
  2461  * @since 2.5.0
  2637  * @since 2.5.0
  2462  *
  2638  *
  2463  * @global wpdb $wpdb WordPress database abstraction object.
  2639  * @global wpdb $wpdb WordPress database abstraction object.
  2464  *
  2640  *
  2465  * @param int $post_id Post ID
  2641  * @param int $post_id Post ID
  2466  * @return bool True on success, false on '0' $post_id or if post with ID does not exist.
  2642  * @return bool True on success, false if the post does not exist.
  2467  */
  2643  */
  2468 function wp_update_comment_count_now( $post_id ) {
  2644 function wp_update_comment_count_now( $post_id ) {
  2469 	global $wpdb;
  2645 	global $wpdb;
  2470 	$post_id = (int) $post_id;
  2646 	$post_id = (int) $post_id;
  2471 	if ( ! $post_id ) {
  2647 	if ( ! $post_id ) {
  2473 	}
  2649 	}
  2474 
  2650 
  2475 	wp_cache_delete( 'comments-0', 'counts' );
  2651 	wp_cache_delete( 'comments-0', 'counts' );
  2476 	wp_cache_delete( "comments-{$post_id}", 'counts' );
  2652 	wp_cache_delete( "comments-{$post_id}", 'counts' );
  2477 
  2653 
  2478 	if ( ! $post = get_post( $post_id ) ) {
  2654 	$post = get_post( $post_id );
       
  2655 	if ( ! $post ) {
  2479 		return false;
  2656 		return false;
  2480 	}
  2657 	}
  2481 
  2658 
  2482 	$old = (int) $post->comment_count;
  2659 	$old = (int) $post->comment_count;
  2483 
  2660 
  2484 	/**
  2661 	/**
  2485 	 * Filters a post's comment count before it is updated in the database.
  2662 	 * Filters a post's comment count before it is updated in the database.
  2486 	 *
  2663 	 *
  2487 	 * @since 4.5.0
  2664 	 * @since 4.5.0
  2488 	 *
  2665 	 *
  2489 	 * @param int $new     The new comment count. Default null.
  2666 	 * @param int|null $new     The new comment count. Default null.
  2490 	 * @param int $old     The old comment count.
  2667 	 * @param int      $old     The old comment count.
  2491 	 * @param int $post_id Post ID.
  2668 	 * @param int      $post_id Post ID.
  2492 	 */
  2669 	 */
  2493 	$new = apply_filters( 'pre_wp_update_comment_count_now', null, $old, $post_id );
  2670 	$new = apply_filters( 'pre_wp_update_comment_count_now', null, $old, $post_id );
  2494 
  2671 
  2495 	if ( is_null( $new ) ) {
  2672 	if ( is_null( $new ) ) {
  2496 		$new = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id ) );
  2673 		$new = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id ) );
  2533  * a check for the x-pingback headers first and returns that, if available. The
  2710  * a check for the x-pingback headers first and returns that, if available. The
  2534  * check for the rel="pingback" has more overhead than just the header.
  2711  * check for the rel="pingback" has more overhead than just the header.
  2535  *
  2712  *
  2536  * @since 1.5.0
  2713  * @since 1.5.0
  2537  *
  2714  *
  2538  * @param string $url URL to ping.
  2715  * @param string $url        URL to ping.
  2539  * @param int $deprecated Not Used.
  2716  * @param int    $deprecated Not Used.
  2540  * @return false|string False on failure, string containing URI on success.
  2717  * @return string|false String containing URI on success, false on failure.
  2541  */
  2718  */
  2542 function discover_pingback_server_uri( $url, $deprecated = '' ) {
  2719 function discover_pingback_server_uri( $url, $deprecated = '' ) {
  2543 	if ( ! empty( $deprecated ) ) {
  2720 	if ( ! empty( $deprecated ) ) {
  2544 		_deprecated_argument( __FUNCTION__, '2.7.0' );
  2721 		_deprecated_argument( __FUNCTION__, '2.7.0' );
  2545 	}
  2722 	}
  2552 
  2729 
  2553 	if ( ! isset( $parsed_url['host'] ) ) { // Not a URL. This should never happen.
  2730 	if ( ! isset( $parsed_url['host'] ) ) { // Not a URL. This should never happen.
  2554 		return false;
  2731 		return false;
  2555 	}
  2732 	}
  2556 
  2733 
  2557 	//Do not search for a pingback server on our own uploads
  2734 	// Do not search for a pingback server on our own uploads.
  2558 	$uploads_dir = wp_get_upload_dir();
  2735 	$uploads_dir = wp_get_upload_dir();
  2559 	if ( 0 === strpos( $url, $uploads_dir['baseurl'] ) ) {
  2736 	if ( 0 === strpos( $url, $uploads_dir['baseurl'] ) ) {
  2560 		return false;
  2737 		return false;
  2561 	}
  2738 	}
  2562 
  2739 
  2579 	// Not an (x)html, sgml, or xml page, no use going further.
  2756 	// Not an (x)html, sgml, or xml page, no use going further.
  2580 	if ( preg_match( '#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'content-type' ) ) ) {
  2757 	if ( preg_match( '#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'content-type' ) ) ) {
  2581 		return false;
  2758 		return false;
  2582 	}
  2759 	}
  2583 
  2760 
  2584 	// Now do a GET since we're going to look in the html headers (and we're sure it's not a binary file)
  2761 	// Now do a GET since we're going to look in the HTML headers (and we're sure it's not a binary file).
  2585 	$response = wp_safe_remote_get(
  2762 	$response = wp_safe_remote_get(
  2586 		$url,
  2763 		$url,
  2587 		array(
  2764 		array(
  2588 			'timeout'     => 2,
  2765 			'timeout'     => 2,
  2589 			'httpversion' => '1.0',
  2766 			'httpversion' => '1.0',
  2598 
  2775 
  2599 	$pingback_link_offset_dquote = strpos( $contents, $pingback_str_dquote );
  2776 	$pingback_link_offset_dquote = strpos( $contents, $pingback_str_dquote );
  2600 	$pingback_link_offset_squote = strpos( $contents, $pingback_str_squote );
  2777 	$pingback_link_offset_squote = strpos( $contents, $pingback_str_squote );
  2601 	if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
  2778 	if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
  2602 		$quote                   = ( $pingback_link_offset_dquote ) ? '"' : '\'';
  2779 		$quote                   = ( $pingback_link_offset_dquote ) ? '"' : '\'';
  2603 		$pingback_link_offset    = ( $quote == '"' ) ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
  2780 		$pingback_link_offset    = ( '"' === $quote ) ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
  2604 		$pingback_href_pos       = @strpos( $contents, 'href=', $pingback_link_offset );
  2781 		$pingback_href_pos       = strpos( $contents, 'href=', $pingback_link_offset );
  2605 		$pingback_href_start     = $pingback_href_pos + 6;
  2782 		$pingback_href_start     = $pingback_href_pos + 6;
  2606 		$pingback_href_end       = @strpos( $contents, $quote, $pingback_href_start );
  2783 		$pingback_href_end       = strpos( $contents, $quote, $pingback_href_start );
  2607 		$pingback_server_url_len = $pingback_href_end - $pingback_href_start;
  2784 		$pingback_server_url_len = $pingback_href_end - $pingback_href_start;
  2608 		$pingback_server_url     = substr( $contents, $pingback_href_start, $pingback_server_url_len );
  2785 		$pingback_server_url     = substr( $contents, $pingback_href_start, $pingback_server_url_len );
  2609 
  2786 
  2610 		// We may find rel="pingback" but an incomplete pingback URL
  2787 		// We may find rel="pingback" but an incomplete pingback URL.
  2611 		if ( $pingback_server_url_len > 0 ) { // We got it!
  2788 		if ( $pingback_server_url_len > 0 ) { // We got it!
  2612 			return $pingback_server_url;
  2789 			return $pingback_server_url;
  2613 		}
  2790 		}
  2614 	}
  2791 	}
  2615 
  2792 
  2624  * @global wpdb $wpdb WordPress database abstraction object.
  2801  * @global wpdb $wpdb WordPress database abstraction object.
  2625  */
  2802  */
  2626 function do_all_pings() {
  2803 function do_all_pings() {
  2627 	global $wpdb;
  2804 	global $wpdb;
  2628 
  2805 
  2629 	// Do pingbacks
  2806 	// Do pingbacks.
  2630 	while ( $ping = $wpdb->get_row( "SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_pingme' LIMIT 1" ) ) {
  2807 	$pings = get_posts(
  2631 		delete_metadata_by_mid( 'post', $ping->meta_id );
  2808 		array(
  2632 		pingback( $ping->post_content, $ping->ID );
  2809 			'post_type'        => get_post_types(),
  2633 	}
  2810 			'suppress_filters' => false,
  2634 
  2811 			'nopaging'         => true,
  2635 	// Do Enclosures
  2812 			'meta_key'         => '_pingme',
  2636 	while ( $enclosure = $wpdb->get_row( "SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1" ) ) {
  2813 			'fields'           => 'ids',
  2637 		delete_metadata_by_mid( 'post', $enclosure->meta_id );
  2814 		)
  2638 		do_enclose( $enclosure->post_content, $enclosure->ID );
  2815 	);
  2639 	}
  2816 
  2640 
  2817 	foreach ( $pings as $ping ) {
  2641 	// Do Trackbacks
  2818 		delete_post_meta( $ping, '_pingme' );
  2642 	$trackbacks = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE to_ping <> '' AND post_status = 'publish'" );
  2819 		pingback( null, $ping );
  2643 	if ( is_array( $trackbacks ) ) {
  2820 	}
  2644 		foreach ( $trackbacks as $trackback ) {
  2821 
  2645 			do_trackbacks( $trackback );
  2822 	// Do enclosures.
  2646 		}
  2823 	$enclosures = get_posts(
  2647 	}
  2824 		array(
  2648 
  2825 			'post_type'        => get_post_types(),
  2649 	//Do Update Services/Generic Pings
  2826 			'suppress_filters' => false,
       
  2827 			'nopaging'         => true,
       
  2828 			'meta_key'         => '_encloseme',
       
  2829 			'fields'           => 'ids',
       
  2830 		)
       
  2831 	);
       
  2832 
       
  2833 	foreach ( $enclosures as $enclosure ) {
       
  2834 		delete_post_meta( $enclosure, '_encloseme' );
       
  2835 		do_enclose( null, $enclosure );
       
  2836 	}
       
  2837 
       
  2838 	// Do trackbacks.
       
  2839 	$trackbacks = get_posts(
       
  2840 		array(
       
  2841 			'post_type'        => get_post_types(),
       
  2842 			'suppress_filters' => false,
       
  2843 			'nopaging'         => true,
       
  2844 			'meta_key'         => '_trackbackme',
       
  2845 			'fields'           => 'ids',
       
  2846 		)
       
  2847 	);
       
  2848 
       
  2849 	foreach ( $trackbacks as $trackback ) {
       
  2850 		delete_post_meta( $trackback, '_trackbackme' );
       
  2851 		do_trackbacks( $trackback );
       
  2852 	}
       
  2853 
       
  2854 	// Do Update Services/Generic Pings.
  2650 	generic_ping();
  2855 	generic_ping();
  2651 }
  2856 }
  2652 
  2857 
  2653 /**
  2858 /**
  2654  * Perform trackbacks.
  2859  * Perform trackbacks.
  2690 	$post_title = strip_tags( $post_title );
  2895 	$post_title = strip_tags( $post_title );
  2691 
  2896 
  2692 	if ( $to_ping ) {
  2897 	if ( $to_ping ) {
  2693 		foreach ( (array) $to_ping as $tb_ping ) {
  2898 		foreach ( (array) $to_ping as $tb_ping ) {
  2694 			$tb_ping = trim( $tb_ping );
  2899 			$tb_ping = trim( $tb_ping );
  2695 			if ( ! in_array( $tb_ping, $pinged ) ) {
  2900 			if ( ! in_array( $tb_ping, $pinged, true ) ) {
  2696 				trackback( $tb_ping, $post_title, $excerpt, $post->ID );
  2901 				trackback( $tb_ping, $post_title, $excerpt, $post->ID );
  2697 				$pinged[] = $tb_ping;
  2902 				$pinged[] = $tb_ping;
  2698 			} else {
  2903 			} else {
  2699 				$wpdb->query(
  2904 				$wpdb->query(
  2700 					$wpdb->prepare(
  2905 					$wpdb->prepare(
  2721 	$services = get_option( 'ping_sites' );
  2926 	$services = get_option( 'ping_sites' );
  2722 
  2927 
  2723 	$services = explode( "\n", $services );
  2928 	$services = explode( "\n", $services );
  2724 	foreach ( (array) $services as $service ) {
  2929 	foreach ( (array) $services as $service ) {
  2725 		$service = trim( $service );
  2930 		$service = trim( $service );
  2726 		if ( '' != $service ) {
  2931 		if ( '' !== $service ) {
  2727 			weblog_ping( $service );
  2932 			weblog_ping( $service );
  2728 		}
  2933 		}
  2729 	}
  2934 	}
  2730 
  2935 
  2731 	return $post_id;
  2936 	return $post_id;
  2735  * Pings back the links found in a post.
  2940  * Pings back the links found in a post.
  2736  *
  2941  *
  2737  * @since 0.71
  2942  * @since 0.71
  2738  * @since 4.7.0 `$post_id` can be a WP_Post object.
  2943  * @since 4.7.0 `$post_id` can be a WP_Post object.
  2739  *
  2944  *
  2740  * @param string $content Post content to check for links. If empty will retrieve from post.
  2945  * @param string      $content Post content to check for links. If empty will retrieve from post.
  2741  * @param int|WP_Post $post_id Post Object or ID.
  2946  * @param int|WP_Post $post_id Post Object or ID.
  2742  */
  2947  */
  2743 function pingback( $content, $post_id ) {
  2948 function pingback( $content, $post_id ) {
  2744 	include_once( ABSPATH . WPINC . '/class-IXR.php' );
  2949 	include_once ABSPATH . WPINC . '/class-IXR.php';
  2745 	include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );
  2950 	include_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
  2746 
  2951 
  2747 	// original code by Mort (http://mort.mine.nu:8080)
  2952 	// Original code by Mort (http://mort.mine.nu:8080).
  2748 	$post_links = array();
  2953 	$post_links = array();
  2749 
  2954 
  2750 	$post = get_post( $post_id );
  2955 	$post = get_post( $post_id );
  2751 	if ( ! $post ) {
  2956 	if ( ! $post ) {
  2752 		return;
  2957 		return;
  2756 
  2961 
  2757 	if ( empty( $content ) ) {
  2962 	if ( empty( $content ) ) {
  2758 		$content = $post->post_content;
  2963 		$content = $post->post_content;
  2759 	}
  2964 	}
  2760 
  2965 
  2761 	// Step 1
  2966 	/*
  2762 	// Parsing the post, external links (if any) are stored in the $post_links array
  2967 	 * Step 1.
       
  2968 	 * Parsing the post, external links (if any) are stored in the $post_links array.
       
  2969 	 */
  2763 	$post_links_temp = wp_extract_urls( $content );
  2970 	$post_links_temp = wp_extract_urls( $content );
  2764 
  2971 
  2765 	// Step 2.
  2972 	/*
  2766 	// Walking thru the links array
  2973 	 * Step 2.
  2767 	// first we get rid of links pointing to sites, not to specific files
  2974 	 * Walking through the links array.
  2768 	// Example:
  2975 	 * First we get rid of links pointing to sites, not to specific files.
  2769 	// http://dummy-weblog.org
  2976 	 * Example:
  2770 	// http://dummy-weblog.org/
  2977 	 * http://dummy-weblog.org
  2771 	// http://dummy-weblog.org/post.php
  2978 	 * http://dummy-weblog.org/
  2772 	// We don't wanna ping first and second types, even if they have a valid <link/>
  2979 	 * http://dummy-weblog.org/post.php
  2773 
  2980 	 * We don't wanna ping first and second types, even if they have a valid <link/>.
  2774 	foreach ( (array) $post_links_temp as $link_test ) :
  2981 	 */
  2775 		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
  2982 	foreach ( (array) $post_links_temp as $link_test ) {
  2776 				&& ! is_local_attachment( $link_test ) ) : // Also, let's never ping local attachments.
  2983 		// If we haven't pung it already and it isn't a link to itself.
  2777 			if ( $test = @parse_url( $link_test ) ) {
  2984 		if ( ! in_array( $link_test, $pung, true ) && ( url_to_postid( $link_test ) != $post->ID )
       
  2985 			// Also, let's never ping local attachments.
       
  2986 			&& ! is_local_attachment( $link_test )
       
  2987 		) {
       
  2988 			$test = parse_url( $link_test );
       
  2989 			if ( $test ) {
  2778 				if ( isset( $test['query'] ) ) {
  2990 				if ( isset( $test['query'] ) ) {
  2779 					$post_links[] = $link_test;
  2991 					$post_links[] = $link_test;
  2780 				} elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) ) {
  2992 				} elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) {
  2781 					$post_links[] = $link_test;
  2993 					$post_links[] = $link_test;
  2782 				}
  2994 				}
  2783 			}
  2995 			}
  2784 		endif;
  2996 		}
  2785 	endforeach;
  2997 	}
  2786 
  2998 
  2787 	$post_links = array_unique( $post_links );
  2999 	$post_links = array_unique( $post_links );
       
  3000 
  2788 	/**
  3001 	/**
  2789 	 * Fires just before pinging back links found in a post.
  3002 	 * Fires just before pinging back links found in a post.
  2790 	 *
  3003 	 *
  2791 	 * @since 2.0.0
  3004 	 * @since 2.0.0
  2792 	 *
  3005 	 *
  2798 
  3011 
  2799 	foreach ( (array) $post_links as $pagelinkedto ) {
  3012 	foreach ( (array) $post_links as $pagelinkedto ) {
  2800 		$pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
  3013 		$pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
  2801 
  3014 
  2802 		if ( $pingback_server_url ) {
  3015 		if ( $pingback_server_url ) {
  2803 			@ set_time_limit( 60 );
  3016 			set_time_limit( 60 );
  2804 			// Now, the RPC call
  3017 			// Now, the RPC call.
  2805 			$pagelinkedfrom = get_permalink( $post );
  3018 			$pagelinkedfrom = get_permalink( $post );
  2806 
  3019 
  2807 			// using a timeout of 3 seconds should be enough to cover slow servers
  3020 			// Using a timeout of 3 seconds should be enough to cover slow servers.
  2808 			$client          = new WP_HTTP_IXR_Client( $pingback_server_url );
  3021 			$client          = new WP_HTTP_IXR_Client( $pingback_server_url );
  2809 			$client->timeout = 3;
  3022 			$client->timeout = 3;
  2810 			/**
  3023 			/**
  2811 			 * Filters the user agent sent when pinging-back a URL.
  3024 			 * Filters the user agent sent when pinging-back a URL.
  2812 			 *
  3025 			 *
  2818 			 * @param string $pingback_server_url The server URL being linked to.
  3031 			 * @param string $pingback_server_url The server URL being linked to.
  2819 			 * @param string $pagelinkedto        URL of page linked to.
  3032 			 * @param string $pagelinkedto        URL of page linked to.
  2820 			 * @param string $pagelinkedfrom      URL of page linked from.
  3033 			 * @param string $pagelinkedfrom      URL of page linked from.
  2821 			 */
  3034 			 */
  2822 			$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . get_bloginfo( 'version' ), $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
  3035 			$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . get_bloginfo( 'version' ), $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
  2823 			// when set to true, this outputs debug messages by itself
  3036 			// When set to true, this outputs debug messages by itself.
  2824 			$client->debug = false;
  3037 			$client->debug = false;
  2825 
  3038 
  2826 			if ( $client->query( 'pingback.ping', $pagelinkedfrom, $pagelinkedto ) || ( isset( $client->error->code ) && 48 == $client->error->code ) ) { // Already registered
  3039 			if ( $client->query( 'pingback.ping', $pagelinkedfrom, $pagelinkedto ) || ( isset( $client->error->code ) && 48 == $client->error->code ) ) { // Already registered.
  2827 				add_ping( $post, $pagelinkedto );
  3040 				add_ping( $post, $pagelinkedto );
  2828 			}
  3041 			}
  2829 		}
  3042 		}
  2830 	}
  3043 	}
  2831 }
  3044 }
  2854  * @since 0.71
  3067  * @since 0.71
  2855  *
  3068  *
  2856  * @global wpdb $wpdb WordPress database abstraction object.
  3069  * @global wpdb $wpdb WordPress database abstraction object.
  2857  *
  3070  *
  2858  * @param string $trackback_url URL to send trackbacks.
  3071  * @param string $trackback_url URL to send trackbacks.
  2859  * @param string $title Title of post.
  3072  * @param string $title         Title of post.
  2860  * @param string $excerpt Excerpt of post.
  3073  * @param string $excerpt       Excerpt of post.
  2861  * @param int $ID Post ID.
  3074  * @param int    $ID            Post ID.
  2862  * @return int|false|void Database query from update.
  3075  * @return int|false|void Database query from update.
  2863  */
  3076  */
  2864 function trackback( $trackback_url, $title, $excerpt, $ID ) {
  3077 function trackback( $trackback_url, $title, $excerpt, $ID ) {
  2865 	global $wpdb;
  3078 	global $wpdb;
  2866 
  3079 
  2894  *
  3107  *
  2895  * @param string $server Host of blog to connect to.
  3108  * @param string $server Host of blog to connect to.
  2896  * @param string $path Path to send the ping.
  3109  * @param string $path Path to send the ping.
  2897  */
  3110  */
  2898 function weblog_ping( $server = '', $path = '' ) {
  3111 function weblog_ping( $server = '', $path = '' ) {
  2899 	include_once( ABSPATH . WPINC . '/class-IXR.php' );
  3112 	include_once ABSPATH . WPINC . '/class-IXR.php';
  2900 	include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );
  3113 	include_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
  2901 
  3114 
  2902 	// using a timeout of 3 seconds should be enough to cover slow servers
  3115 	// Using a timeout of 3 seconds should be enough to cover slow servers.
  2903 	$client             = new WP_HTTP_IXR_Client( $server, ( ( ! strlen( trim( $path ) ) || ( '/' == $path ) ) ? false : $path ) );
  3116 	$client             = new WP_HTTP_IXR_Client( $server, ( ( ! strlen( trim( $path ) ) || ( '/' === $path ) ) ? false : $path ) );
  2904 	$client->timeout    = 3;
  3117 	$client->timeout    = 3;
  2905 	$client->useragent .= ' -- WordPress/' . get_bloginfo( 'version' );
  3118 	$client->useragent .= ' -- WordPress/' . get_bloginfo( 'version' );
  2906 
  3119 
  2907 	// when set to true, this outputs debug messages by itself
  3120 	// When set to true, this outputs debug messages by itself.
  2908 	$client->debug = false;
  3121 	$client->debug = false;
  2909 	$home          = trailingslashit( home_url() );
  3122 	$home          = trailingslashit( home_url() );
  2910 	if ( ! $client->query( 'weblogUpdates.extendedPing', get_option( 'blogname' ), $home, get_bloginfo( 'rss2_url' ) ) ) { // then try a normal ping
  3123 	if ( ! $client->query( 'weblogUpdates.extendedPing', get_option( 'blogname' ), $home, get_bloginfo( 'rss2_url' ) ) ) { // Then try a normal ping.
  2911 		$client->query( 'weblogUpdates.ping', get_option( 'blogname' ), $home );
  3124 		$client->query( 'weblogUpdates.ping', get_option( 'blogname' ), $home );
  2912 	}
  3125 	}
  2913 }
  3126 }
  2914 
  3127 
  2915 /**
  3128 /**
  2916  * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI
  3129  * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI
  2917  *
  3130  *
  2918  * @since 3.5.1
  3131  * @since 3.5.1
       
  3132  *
  2919  * @see wp_http_validate_url()
  3133  * @see wp_http_validate_url()
  2920  *
  3134  *
  2921  * @param string $source_uri
  3135  * @param string $source_uri
  2922  * @return string
  3136  * @return string
  2923  */
  3137  */
  2930  *
  3144  *
  2931  * Returns a generic pingback error code unless the error code is 48,
  3145  * Returns a generic pingback error code unless the error code is 48,
  2932  * which reports that the pingback is already registered.
  3146  * which reports that the pingback is already registered.
  2933  *
  3147  *
  2934  * @since 3.5.1
  3148  * @since 3.5.1
       
  3149  *
  2935  * @link https://www.hixie.ch/specs/pingback/pingback#TOC3
  3150  * @link https://www.hixie.ch/specs/pingback/pingback#TOC3
  2936  *
  3151  *
  2937  * @param IXR_Error $ixr_error
  3152  * @param IXR_Error $ixr_error
  2938  * @return IXR_Error
  3153  * @return IXR_Error
  2939  */
  3154  */
  2940 function xmlrpc_pingback_error( $ixr_error ) {
  3155 function xmlrpc_pingback_error( $ixr_error ) {
  2941 	if ( $ixr_error->code === 48 ) {
  3156 	if ( 48 === $ixr_error->code ) {
  2942 		return $ixr_error;
  3157 		return $ixr_error;
  2943 	}
  3158 	}
  2944 	return new IXR_Error( 0, '' );
  3159 	return new IXR_Error( 0, '' );
  2945 }
  3160 }
  2946 
  3161 
  2947 //
  3162 //
  2948 // Cache
  3163 // Cache.
  2949 //
  3164 //
  2950 
  3165 
  2951 /**
  3166 /**
  2952  * Removes a comment from the object cache.
  3167  * Removes a comment from the object cache.
  2953  *
  3168  *
  3022 		update_comment_cache( $fresh_comments, $update_meta_cache );
  3237 		update_comment_cache( $fresh_comments, $update_meta_cache );
  3023 	}
  3238 	}
  3024 }
  3239 }
  3025 
  3240 
  3026 //
  3241 //
  3027 // Internal
  3242 // Internal.
  3028 //
  3243 //
  3029 
  3244 
  3030 /**
  3245 /**
  3031  * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
  3246  * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
  3032  *
  3247  *
       
  3248  * @since 2.7.0
  3033  * @access private
  3249  * @access private
  3034  * @since 2.7.0
       
  3035  *
  3250  *
  3036  * @param WP_Post  $posts Post data object.
  3251  * @param WP_Post  $posts Post data object.
  3037  * @param WP_Query $query Query object.
  3252  * @param WP_Query $query Query object.
  3038  * @return array
  3253  * @return array
  3039  */
  3254  */
  3048 	 * @since 3.2.0
  3263 	 * @since 3.2.0
  3049 	 *
  3264 	 *
  3050 	 * @param string[] $post_types An array of post type names.
  3265 	 * @param string[] $post_types An array of post type names.
  3051 	 */
  3266 	 */
  3052 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
  3267 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
  3053 	if ( ! in_array( $posts[0]->post_type, $post_types ) ) {
  3268 	if ( ! in_array( $posts[0]->post_type, $post_types, true ) ) {
  3054 		return $posts;
  3269 		return $posts;
  3055 	}
  3270 	}
  3056 
  3271 
  3057 	$days_old = (int) get_option( 'close_comments_days_old' );
  3272 	$days_old = (int) get_option( 'close_comments_days_old' );
  3058 	if ( ! $days_old ) {
  3273 	if ( ! $days_old ) {
  3068 }
  3283 }
  3069 
  3284 
  3070 /**
  3285 /**
  3071  * Close comments on an old post. Hooked to comments_open and pings_open.
  3286  * Close comments on an old post. Hooked to comments_open and pings_open.
  3072  *
  3287  *
       
  3288  * @since 2.7.0
  3073  * @access private
  3289  * @access private
  3074  * @since 2.7.0
  3290  *
  3075  *
  3291  * @param bool $open    Comments open or closed.
  3076  * @param bool $open Comments open or closed
  3292  * @param int  $post_id Post ID.
  3077  * @param int $post_id Post ID
       
  3078  * @return bool $open
  3293  * @return bool $open
  3079  */
  3294  */
  3080 function _close_comments_for_old_post( $open, $post_id ) {
  3295 function _close_comments_for_old_post( $open, $post_id ) {
  3081 	if ( ! $open ) {
  3296 	if ( ! $open ) {
  3082 		return $open;
  3297 		return $open;
  3093 
  3308 
  3094 	$post = get_post( $post_id );
  3309 	$post = get_post( $post_id );
  3095 
  3310 
  3096 	/** This filter is documented in wp-includes/comment.php */
  3311 	/** This filter is documented in wp-includes/comment.php */
  3097 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
  3312 	$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
  3098 	if ( ! in_array( $post->post_type, $post_types ) ) {
  3313 	if ( ! in_array( $post->post_type, $post_types, true ) ) {
  3099 		return $open;
  3314 		return $open;
  3100 	}
  3315 	}
  3101 
  3316 
  3102 	// Undated drafts should not show up as comments closed.
  3317 	// Undated drafts should not show up as comments closed.
  3103 	if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
  3318 	if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
  3132  * }
  3347  * }
  3133  * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
  3348  * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
  3134  */
  3349  */
  3135 function wp_handle_comment_submission( $comment_data ) {
  3350 function wp_handle_comment_submission( $comment_data ) {
  3136 
  3351 
  3137 	$comment_post_ID = $comment_parent = $user_ID = 0;
  3352 	$comment_post_ID      = 0;
  3138 	$comment_author  = $comment_author_email = $comment_author_url = $comment_content = null;
  3353 	$comment_parent       = 0;
       
  3354 	$user_ID              = 0;
       
  3355 	$comment_author       = null;
       
  3356 	$comment_author_email = null;
       
  3357 	$comment_author_url   = null;
       
  3358 	$comment_content      = null;
  3139 
  3359 
  3140 	if ( isset( $comment_data['comment_post_ID'] ) ) {
  3360 	if ( isset( $comment_data['comment_post_ID'] ) ) {
  3141 		$comment_post_ID = (int) $comment_data['comment_post_ID'];
  3361 		$comment_post_ID = (int) $comment_data['comment_post_ID'];
  3142 	}
  3362 	}
  3143 	if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
  3363 	if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
  3174 	}
  3394 	}
  3175 
  3395 
  3176 	// get_post_status() will get the parent status for attachments.
  3396 	// get_post_status() will get the parent status for attachments.
  3177 	$status = get_post_status( $post );
  3397 	$status = get_post_status( $post );
  3178 
  3398 
  3179 	if ( ( 'private' == $status ) && ! current_user_can( 'read_post', $comment_post_ID ) ) {
  3399 	if ( ( 'private' === $status ) && ! current_user_can( 'read_post', $comment_post_ID ) ) {
  3180 		return new WP_Error( 'comment_id_not_found' );
  3400 		return new WP_Error( 'comment_id_not_found' );
  3181 	}
  3401 	}
  3182 
  3402 
  3183 	$status_obj = get_post_status_object( $status );
  3403 	$status_obj = get_post_status_object( $status );
  3184 
  3404 
  3193 		 */
  3413 		 */
  3194 		do_action( 'comment_closed', $comment_post_ID );
  3414 		do_action( 'comment_closed', $comment_post_ID );
  3195 
  3415 
  3196 		return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
  3416 		return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
  3197 
  3417 
  3198 	} elseif ( 'trash' == $status ) {
  3418 	} elseif ( 'trash' === $status ) {
  3199 
  3419 
  3200 		/**
  3420 		/**
  3201 		 * Fires when a comment is attempted on a trashed post.
  3421 		 * Fires when a comment is attempted on a trashed post.
  3202 		 *
  3422 		 *
  3203 		 * @since 2.9.0
  3423 		 * @since 2.9.0
  3248 		 */
  3468 		 */
  3249 		do_action( 'pre_comment_on_post', $comment_post_ID );
  3469 		do_action( 'pre_comment_on_post', $comment_post_ID );
  3250 
  3470 
  3251 	}
  3471 	}
  3252 
  3472 
  3253 	// If the user is logged in
  3473 	// If the user is logged in.
  3254 	$user = wp_get_current_user();
  3474 	$user = wp_get_current_user();
  3255 	if ( $user->exists() ) {
  3475 	if ( $user->exists() ) {
  3256 		if ( empty( $user->display_name ) ) {
  3476 		if ( empty( $user->display_name ) ) {
  3257 			$user->display_name = $user->user_login;
  3477 			$user->display_name = $user->user_login;
  3258 		}
  3478 		}
  3262 		$user_ID              = $user->ID;
  3482 		$user_ID              = $user->ID;
  3263 		if ( current_user_can( 'unfiltered_html' ) ) {
  3483 		if ( current_user_can( 'unfiltered_html' ) ) {
  3264 			if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
  3484 			if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
  3265 				|| ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
  3485 				|| ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
  3266 			) {
  3486 			) {
  3267 				kses_remove_filters(); // start with a clean slate
  3487 				kses_remove_filters(); // Start with a clean slate.
  3268 				kses_init_filters(); // set up the filters
  3488 				kses_init_filters();   // Set up the filters.
  3269 				remove_filter( 'pre_comment_content', 'wp_filter_post_kses' );
  3489 				remove_filter( 'pre_comment_content', 'wp_filter_post_kses' );
  3270 				add_filter( 'pre_comment_content', 'wp_filter_kses' );
  3490 				add_filter( 'pre_comment_content', 'wp_filter_kses' );
  3271 			}
  3491 			}
  3272 		}
  3492 		}
  3273 	} else {
  3493 	} else {
  3274 		if ( get_option( 'comment_registration' ) ) {
  3494 		if ( get_option( 'comment_registration' ) ) {
  3275 			return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to comment.' ), 403 );
  3495 			return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to comment.' ), 403 );
  3276 		}
  3496 		}
  3277 	}
  3497 	}
  3278 
  3498 
  3279 	$comment_type = '';
  3499 	$comment_type = 'comment';
  3280 
  3500 
  3281 	if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
  3501 	if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
  3282 		if ( '' == $comment_author_email || '' == $comment_author ) {
  3502 		if ( '' == $comment_author_email || '' == $comment_author ) {
  3283 			return new WP_Error( 'require_name_email', __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
  3503 			return new WP_Error( 'require_name_email', __( '<strong>Error</strong>: Please fill the required fields (name, email).' ), 200 );
  3284 		} elseif ( ! is_email( $comment_author_email ) ) {
  3504 		} elseif ( ! is_email( $comment_author_email ) ) {
  3285 			return new WP_Error( 'require_valid_email', __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
  3505 			return new WP_Error( 'require_valid_email', __( '<strong>Error</strong>: Please enter a valid email address.' ), 200 );
  3286 		}
  3506 		}
  3287 	}
  3507 	}
  3288 
  3508 
  3289 	$commentdata = compact(
  3509 	$commentdata = compact(
  3290 		'comment_post_ID',
  3510 		'comment_post_ID',
  3305 	 * @param bool  $allow_empty_comment Whether to allow empty comments. Default false.
  3525 	 * @param bool  $allow_empty_comment Whether to allow empty comments. Default false.
  3306 	 * @param array $commentdata         Array of comment data to be sent to wp_insert_comment().
  3526 	 * @param array $commentdata         Array of comment data to be sent to wp_insert_comment().
  3307 	 */
  3527 	 */
  3308 	$allow_empty_comment = apply_filters( 'allow_empty_comment', false, $commentdata );
  3528 	$allow_empty_comment = apply_filters( 'allow_empty_comment', false, $commentdata );
  3309 	if ( '' === $comment_content && ! $allow_empty_comment ) {
  3529 	if ( '' === $comment_content && ! $allow_empty_comment ) {
  3310 		return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
  3530 		return new WP_Error( 'require_valid_comment', __( '<strong>Error</strong>: Please type your comment text.' ), 200 );
  3311 	}
  3531 	}
  3312 
  3532 
  3313 	$check_max_lengths = wp_check_comment_data_max_lengths( $commentdata );
  3533 	$check_max_lengths = wp_check_comment_data_max_lengths( $commentdata );
  3314 	if ( is_wp_error( $check_max_lengths ) ) {
  3534 	if ( is_wp_error( $check_max_lengths ) ) {
  3315 		return $check_max_lengths;
  3535 		return $check_max_lengths;
  3319 	if ( is_wp_error( $comment_id ) ) {
  3539 	if ( is_wp_error( $comment_id ) ) {
  3320 		return $comment_id;
  3540 		return $comment_id;
  3321 	}
  3541 	}
  3322 
  3542 
  3323 	if ( ! $comment_id ) {
  3543 	if ( ! $comment_id ) {
  3324 		return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
  3544 		return new WP_Error( 'comment_save_error', __( '<strong>Error</strong>: The comment could not be saved. Please try again later.' ), 500 );
  3325 	}
  3545 	}
  3326 
  3546 
  3327 	return get_comment( $comment_id );
  3547 	return get_comment( $comment_id );
  3328 }
  3548 }
  3329 
  3549 
  3331  * Registers the personal data exporter for comments.
  3551  * Registers the personal data exporter for comments.
  3332  *
  3552  *
  3333  * @since 4.9.6
  3553  * @since 4.9.6
  3334  *
  3554  *
  3335  * @param array $exporters An array of personal data exporters.
  3555  * @param array $exporters An array of personal data exporters.
  3336  * @return array $exporters An array of personal data exporters.
  3556  * @return array An array of personal data exporters.
  3337  */
  3557  */
  3338 function wp_register_comment_personal_data_exporter( $exporters ) {
  3558 function wp_register_comment_personal_data_exporter( $exporters ) {
  3339 	$exporters['wordpress-comments'] = array(
  3559 	$exporters['wordpress-comments'] = array(
  3340 		'exporter_friendly_name' => __( 'WordPress Comments' ),
  3560 		'exporter_friendly_name' => __( 'WordPress Comments' ),
  3341 		'callback'               => 'wp_comments_personal_data_exporter',
  3561 		'callback'               => 'wp_comments_personal_data_exporter',
  3349  *
  3569  *
  3350  * @since 4.9.6
  3570  * @since 4.9.6
  3351  *
  3571  *
  3352  * @param string $email_address The comment author email address.
  3572  * @param string $email_address The comment author email address.
  3353  * @param int    $page          Comment page.
  3573  * @param int    $page          Comment page.
  3354  * @return array $return An array of personal data.
  3574  * @return array An array of personal data.
  3355  */
  3575  */
  3356 function wp_comments_personal_data_exporter( $email_address, $page = 1 ) {
  3576 function wp_comments_personal_data_exporter( $email_address, $page = 1 ) {
  3357 	// Limit us to 500 comments at a time to avoid timing out.
  3577 	// Limit us to 500 comments at a time to avoid timing out.
  3358 	$number = 500;
  3578 	$number = 500;
  3359 	$page   = (int) $page;
  3579 	$page   = (int) $page;
  3419 				);
  3639 				);
  3420 			}
  3640 			}
  3421 		}
  3641 		}
  3422 
  3642 
  3423 		$data_to_export[] = array(
  3643 		$data_to_export[] = array(
  3424 			'group_id'    => 'comments',
  3644 			'group_id'          => 'comments',
  3425 			'group_label' => __( 'Comments' ),
  3645 			'group_label'       => __( 'Comments' ),
  3426 			'item_id'     => "comment-{$comment->comment_ID}",
  3646 			'group_description' => __( 'User&#8217;s comment data.' ),
  3427 			'data'        => $comment_data_to_export,
  3647 			'item_id'           => "comment-{$comment->comment_ID}",
       
  3648 			'data'              => $comment_data_to_export,
  3428 		);
  3649 		);
  3429 	}
  3650 	}
  3430 
  3651 
  3431 	$done = count( $comments ) < $number;
  3652 	$done = count( $comments ) < $number;
  3432 
  3653 
  3439 /**
  3660 /**
  3440  * Registers the personal data eraser for comments.
  3661  * Registers the personal data eraser for comments.
  3441  *
  3662  *
  3442  * @since 4.9.6
  3663  * @since 4.9.6
  3443  *
  3664  *
  3444  * @param  array $erasers An array of personal data erasers.
  3665  * @param array $erasers An array of personal data erasers.
  3445  * @return array $erasers An array of personal data erasers.
  3666  * @return array An array of personal data erasers.
  3446  */
  3667  */
  3447 function wp_register_comment_personal_data_eraser( $erasers ) {
  3668 function wp_register_comment_personal_data_eraser( $erasers ) {
  3448 	$erasers['wordpress-comments'] = array(
  3669 	$erasers['wordpress-comments'] = array(
  3449 		'eraser_friendly_name' => __( 'WordPress Comments' ),
  3670 		'eraser_friendly_name' => __( 'WordPress Comments' ),
  3450 		'callback'             => 'wp_comments_personal_data_eraser',
  3671 		'callback'             => 'wp_comments_personal_data_eraser',
  3456 /**
  3677 /**
  3457  * Erases personal data associated with an email address from the comments table.
  3678  * Erases personal data associated with an email address from the comments table.
  3458  *
  3679  *
  3459  * @since 4.9.6
  3680  * @since 4.9.6
  3460  *
  3681  *
  3461  * @param  string $email_address The comment author email address.
  3682  * @param string $email_address The comment author email address.
  3462  * @param  int    $page          Comment page.
  3683  * @param int    $page          Comment page.
  3463  * @return array
  3684  * @return array
  3464  */
  3685  */
  3465 function wp_comments_personal_data_eraser( $email_address, $page = 1 ) {
  3686 function wp_comments_personal_data_eraser( $email_address, $page = 1 ) {
  3466 	global $wpdb;
  3687 	global $wpdb;
  3467 
  3688 
  3509 		/**
  3730 		/**
  3510 		 * Filters whether to anonymize the comment.
  3731 		 * Filters whether to anonymize the comment.
  3511 		 *
  3732 		 *
  3512 		 * @since 4.9.6
  3733 		 * @since 4.9.6
  3513 		 *
  3734 		 *
  3514 		 * @param bool|string                    Whether to apply the comment anonymization (bool).
  3735 		 * @param bool|string $anon_message       Whether to apply the comment anonymization (bool) or a custom
  3515 		 *                                       Custom prevention message (string). Default true.
  3736 		 *                                        message (string). Default true.
  3516 		 * @param WP_Comment $comment            WP_Comment object.
  3737 		 * @param WP_Comment  $comment            WP_Comment object.
  3517 		 * @param array      $anonymized_comment Anonymized comment data.
  3738 		 * @param array       $anonymized_comment Anonymized comment data.
  3518 		 */
  3739 		 */
  3519 		$anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
  3740 		$anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
  3520 
  3741 
  3521 		if ( true !== $anon_message ) {
  3742 		if ( true !== $anon_message ) {
  3522 			if ( $anon_message && is_string( $anon_message ) ) {
  3743 			if ( $anon_message && is_string( $anon_message ) ) {
  3523 				$messages[] = esc_html( $anon_message );
  3744 				$messages[] = esc_html( $anon_message );
  3524 			} else {
  3745 			} else {
  3525 				/* translators: %d: Comment ID */
  3746 				/* translators: %d: Comment ID. */
  3526 				$messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
  3747 				$messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
  3527 			}
  3748 			}
  3528 
  3749 
  3529 			$items_retained = true;
  3750 			$items_retained = true;
  3530 
  3751 
  3561  * @since 5.0.0
  3782  * @since 5.0.0
  3562  */
  3783  */
  3563 function wp_cache_set_comments_last_changed() {
  3784 function wp_cache_set_comments_last_changed() {
  3564 	wp_cache_set( 'last_changed', microtime(), 'comment' );
  3785 	wp_cache_set( 'last_changed', microtime(), 'comment' );
  3565 }
  3786 }
       
  3787 
       
  3788 /**
       
  3789  * Updates the comment type for a batch of comments.
       
  3790  *
       
  3791  * @since 5.5.0
       
  3792  *
       
  3793  * @global wpdb $wpdb WordPress database abstraction object.
       
  3794  */
       
  3795 function _wp_batch_update_comment_type() {
       
  3796 	global $wpdb;
       
  3797 
       
  3798 	$lock_name = 'update_comment_type.lock';
       
  3799 
       
  3800 	// Try to lock.
       
  3801 	$lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
       
  3802 
       
  3803 	if ( ! $lock_result ) {
       
  3804 		$lock_result = get_option( $lock_name );
       
  3805 
       
  3806 		// Bail if we were unable to create a lock, or if the existing lock is still valid.
       
  3807 		if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) {
       
  3808 			wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_update_comment_type_batch' );
       
  3809 			return;
       
  3810 		}
       
  3811 	}
       
  3812 
       
  3813 	// Update the lock, as by this point we've definitely got a lock, just need to fire the actions.
       
  3814 	update_option( $lock_name, time() );
       
  3815 
       
  3816 	// Check if there's still an empty comment type.
       
  3817 	$empty_comment_type = $wpdb->get_var(
       
  3818 		"SELECT comment_ID FROM $wpdb->comments
       
  3819 		WHERE comment_type = ''
       
  3820 		LIMIT 1"
       
  3821 	);
       
  3822 
       
  3823 	// No empty comment type, we're done here.
       
  3824 	if ( ! $empty_comment_type ) {
       
  3825 		update_option( 'finished_updating_comment_type', true );
       
  3826 		delete_option( $lock_name );
       
  3827 		return;
       
  3828 	}
       
  3829 
       
  3830 	// Empty comment type found? We'll need to run this script again.
       
  3831 	wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_update_comment_type_batch' );
       
  3832 
       
  3833 	/**
       
  3834 	 * Filters the comment batch size for updating the comment type.
       
  3835 	 *
       
  3836 	 * @since 5.5.0
       
  3837 	 *
       
  3838 	 * @param int $comment_batch_size The comment batch size. Default 100.
       
  3839 	 */
       
  3840 	$comment_batch_size = (int) apply_filters( 'wp_update_comment_type_batch_size', 100 );
       
  3841 
       
  3842 	// Get the IDs of the comments to update.
       
  3843 	$comment_ids = $wpdb->get_col(
       
  3844 		$wpdb->prepare(
       
  3845 			"SELECT comment_ID
       
  3846 			FROM {$wpdb->comments}
       
  3847 			WHERE comment_type = ''
       
  3848 			ORDER BY comment_ID DESC
       
  3849 			LIMIT %d",
       
  3850 			$comment_batch_size
       
  3851 		)
       
  3852 	);
       
  3853 
       
  3854 	if ( $comment_ids ) {
       
  3855 		$comment_id_list = implode( ',', $comment_ids );
       
  3856 
       
  3857 		// Update the `comment_type` field value to be `comment` for the next batch of comments.
       
  3858 		$wpdb->query(
       
  3859 			"UPDATE {$wpdb->comments}
       
  3860 			SET comment_type = 'comment'
       
  3861 			WHERE comment_type = ''
       
  3862 			AND comment_ID IN ({$comment_id_list})" // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
       
  3863 		);
       
  3864 
       
  3865 		// Make sure to clean the comment cache.
       
  3866 		clean_comment_cache( $comment_ids );
       
  3867 	}
       
  3868 
       
  3869 	delete_option( $lock_name );
       
  3870 }
       
  3871 
       
  3872 /**
       
  3873  * In order to avoid the _wp_batch_update_comment_type() job being accidentally removed,
       
  3874  * check that it's still scheduled while we haven't finished updating comment types.
       
  3875  *
       
  3876  * @ignore
       
  3877  * @since 5.5.0
       
  3878  */
       
  3879 function _wp_check_for_scheduled_update_comment_type() {
       
  3880 	if ( ! get_option( 'finished_updating_comment_type' ) && ! wp_next_scheduled( 'wp_update_comment_type_batch' ) ) {
       
  3881 		wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_update_comment_type_batch' );
       
  3882 	}
       
  3883 }