* Check whether a comment passes internal checks to be allowed to add.
* If manual comment moderation is set in the administration, then all checks,
* regardless of their type and substance, will fail and the function will
* If the number of links exceeds the amount in the administration, then the
* check fails. If any of the parameter contents contain any disallowed words,
* If the comment author was approved before, then the comment is automatically
* If all checks pass, the function will return true.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $author Comment author name.
* @param string $email Comment author email.
* @param string $url Comment author URL.
* @param string $comment Content of the comment.
* @param string $user_ip Comment author IP address.
* @param string $user_agent Comment author User-Agent.
* @param string $comment_type Comment type, either user-submitted comment,
* trackback, or pingback.
* @return bool If all checks pass, true, otherwise false.
function check_comment( $author, $email, $url, $comment, $user_ip, $user_agent, $comment_type ) {
// If manual moderation is enabled, skip all checks and return false.
if ( 1 == get_option( 'comment_moderation' ) ) {
/** This filter is documented in wp-includes/comment-template.php */
$comment = apply_filters( 'comment_text', $comment, null, array() );
// Check for the number of external links if a max allowed number is set.
$max_links = get_option( 'comment_max_links' );
$num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
* Filters the number of links found in a comment.
* @since 4.7.0 Added the `$comment` parameter.
* @param int $num_links The number of links found.
* @param string $url Comment author's URL. Included in allowed links total.
* @param string $comment Content of the comment.
$num_links = apply_filters( 'comment_max_links_url', $num_links, $url, $comment );
* If the number of links in the comment exceeds the allowed amount,
* fail the check by returning false.
if ( $num_links >= $max_links ) {
$mod_keys = trim( get_option( 'moderation_keys' ) );
// If moderation 'keys' (keywords) are set, process them.
if ( ! empty( $mod_keys ) ) {
$words = explode( "\n", $mod_keys );
foreach ( (array) $words as $word ) {
* Do some escaping magic so that '#' (number of) characters in the spam
* words don't break things:
$word = preg_quote( $word, '#' );
* Check the comment fields for moderation keywords. If any are found,
* fail the check for the given field by returning false.
if ( preg_match( $pattern, $author ) ) {
if ( preg_match( $pattern, $email ) ) {
if ( preg_match( $pattern, $url ) ) {
if ( preg_match( $pattern, $comment ) ) {
if ( preg_match( $pattern, $user_ip ) ) {
if ( preg_match( $pattern, $user_agent ) ) {
* Check if the option to approve comments by previously-approved authors is enabled.
* If it is enabled, check whether the comment author has a previously-approved comment,
* as well as whether there are any moderation keywords (if set) present in the author
* email address. If both checks pass, return true. Otherwise, return false.
if ( 1 == get_option( 'comment_previously_approved' ) ) {
if ( 'trackback' !== $comment_type && 'pingback' !== $comment_type && '' !== $author && '' !== $email ) {
$comment_user = get_user_by( 'email', wp_unslash( $email ) );
if ( ! empty( $comment_user->ID ) ) {
$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 ) );
// expected_slashed ($author, $email)
$ok_to_comment = $wpdb->get_var( $wpdb->prepare( "SELECT comment_approved FROM $wpdb->comments WHERE comment_author = %s AND comment_author_email = %s and comment_approved = '1' LIMIT 1", $author, $email ) );
if ( ( 1 == $ok_to_comment ) &&
( empty( $mod_keys ) || false === strpos( $email, $mod_keys ) ) ) {
* Retrieve the approved comments for post $post_id.
* @since 4.1.0 Refactored to leverage WP_Comment_Query over a direct query.
* @param int $post_id The ID of the post.
* @param array $args Optional. See WP_Comment_Query::__construct() for information on accepted arguments.
* @return int|array The approved comments, or number of comments if `$count`
function get_approved_comments( $post_id, $args = array() ) {
$parsed_args = wp_parse_args( $args, $defaults );
$query = new WP_Comment_Query;
return $query->query( $parsed_args );
* Retrieves comment data given a comment ID or comment object.
* If an object is passed then the comment data will be cached and then returned
* after being passed through a filter. If the comment is empty, then the global
* comment variable will be used, if it is set.
* @global WP_Comment $comment Global comment object.
* @param WP_Comment|string|int $comment Comment to retrieve.
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
* correspond to a WP_Comment object, an associative array, or a numeric array,
* respectively. Default OBJECT.
* @return WP_Comment|array|null Depends on $output value.
function get_comment( $comment = null, $output = OBJECT ) {
if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
$comment = $GLOBALS['comment'];
if ( $comment instanceof WP_Comment ) {
} elseif ( is_object( $comment ) ) {
$_comment = new WP_Comment( $comment );
$_comment = WP_Comment::get_instance( $comment );
* Fires after a comment is retrieved.
* @param WP_Comment $_comment Comment data.
$_comment = apply_filters( 'get_comment', $_comment );
if ( OBJECT == $output ) {
} elseif ( ARRAY_A == $output ) {
return $_comment->to_array();
} elseif ( ARRAY_N == $output ) {
return array_values( $_comment->to_array() );
* Retrieve a list of comments.
* The comment list can be for the blog as a whole or for an individual post.
* @param string|array $args Optional. Array or string of arguments. See WP_Comment_Query::__construct()
* for information on accepted arguments. Default empty.
* @return int|array List of comments or number of found comments if `$count` argument is true.
function get_comments( $args = '' ) {
$query = new WP_Comment_Query;
return $query->query( $args );
* Retrieve all of the WordPress supported comment statuses.
* Comments have a limited set of valid status values, this provides the comment
* status values and descriptions.
* @return string[] List of comment status labels keyed by status.
function get_comment_statuses() {
'hold' => __( 'Unapproved' ),
'approve' => _x( 'Approved', 'comment status' ),
'spam' => _x( 'Spam', 'comment status' ),
'trash' => _x( 'Trash', 'comment status' ),
* Gets the default comment status for a post type.
* @param string $post_type Optional. Post type. Default 'post'.
* @param string $comment_type Optional. Comment type. Default 'comment'.
* @return string Expected return value is 'open' or 'closed'.
function get_default_comment_status( $post_type = 'post', $comment_type = 'comment' ) {
switch ( $comment_type ) {
$supports = 'trackbacks';
if ( 'page' === $post_type ) {
} elseif ( post_type_supports( $post_type, $supports ) ) {
$status = get_option( "default_{$option}_status" );
* Filters the default comment status for the given post type.
* @param string $status Default status for the given post type,
* either 'open' or 'closed'.
* @param string $post_type Post type. Default is `post`.
* @param string $comment_type Type of comment. Default is `comment`.
return apply_filters( 'get_default_comment_status', $status, $post_type, $comment_type );
* The date the last comment was modified.
* @since 4.7.0 Replaced caching the modified date in a local static variable
* with the Object Cache API.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $timezone Which timezone to use in reference to 'gmt', 'blog', or 'server' locations.
* @return string|false Last comment modified date on success, false on failure.
function get_lastcommentmodified( $timezone = 'server' ) {
$timezone = strtolower( $timezone );
$key = "lastcommentmodified:$timezone";
$comment_modified_date = wp_cache_get( $key, 'timeinfo' );
if ( false !== $comment_modified_date ) {
return $comment_modified_date;
$comment_modified_date = $wpdb->get_var( "SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
$comment_modified_date = $wpdb->get_var( "SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
$add_seconds_server = gmdate( 'Z' );
$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 ) );
if ( $comment_modified_date ) {
wp_cache_set( $key, $comment_modified_date, 'timeinfo' );
return $comment_modified_date;
* Retrieves the total comment counts for the whole site or a single post.
* Unlike wp_count_comments(), this function always returns the live comment counts without caching.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int $post_id Optional. Restrict the comment counts to the given post. Default 0, which indicates that
* comment counts for the whole site will be retrieved.
* The number of comments keyed by their status.
* @type int $approved The number of approved comments.
* @type int $awaiting_moderation The number of comments awaiting moderation (a.k.a. pending).
* @type int $spam The number of spam comments.
* @type int $trash The number of trashed comments.
* @type int $post-trashed The number of comments for posts that are in the trash.
* @type int $total_comments The total number of non-trashed comments, including spam.
* @type int $all The total number of pending or approved comments.
function get_comment_count( $post_id = 0 ) {
$post_id = (int) $post_id;
$where = $wpdb->prepare( 'WHERE comment_post_ID = %d', $post_id );
$totals = (array) $wpdb->get_results(
SELECT comment_approved, COUNT( * ) AS total
GROUP BY comment_approved
'awaiting_moderation' => 0,
foreach ( $totals as $row ) {
switch ( $row['comment_approved'] ) {
$comment_count['trash'] = $row['total'];
$comment_count['post-trashed'] = $row['total'];
$comment_count['spam'] = $row['total'];
$comment_count['total_comments'] += $row['total'];
$comment_count['approved'] = $row['total'];
$comment_count['total_comments'] += $row['total'];
$comment_count['all'] += $row['total'];
$comment_count['awaiting_moderation'] = $row['total'];
$comment_count['total_comments'] += $row['total'];
$comment_count['all'] += $row['total'];
return array_map( 'intval', $comment_count );
// Comment meta functions.
* Add meta data field to a comment.
* @link https://developer.wordpress.org/reference/functions/add_comment_meta/
* @param int $comment_id Comment ID.
* @param string $meta_key Metadata name.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $unique Optional. Whether the same key should not be added.
* @return int|false Meta ID on success, false on failure.
function add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false ) {
return add_metadata( 'comment', $comment_id, $meta_key, $meta_value, $unique );
* Remove metadata matching criteria from a comment.
* You can match based on the key, or key and value. Removing based on key and
* value, will keep from removing duplicate metadata with the same key. It also
* allows removing all metadata matching key, if needed.
* @link https://developer.wordpress.org/reference/functions/delete_comment_meta/
* @param int $comment_id Comment ID.
* @param string $meta_key Metadata name.
* @param mixed $meta_value Optional. Metadata value. If provided,
* rows will only be removed that match the value.
* Must be serializable if non-scalar. Default empty.
* @return bool True on success, false on failure.
function delete_comment_meta( $comment_id, $meta_key, $meta_value = '' ) {
return delete_metadata( 'comment', $comment_id, $meta_key, $meta_value );
* Retrieve comment meta field for a comment.
* @link https://developer.wordpress.org/reference/functions/get_comment_meta/
* @param int $comment_id Comment ID.
* @param string $key Optional. The meta key to retrieve. By default,
* returns data for all keys.
* @param bool $single Optional. Whether to return a single value.
* This parameter has no effect if $key is not specified.
* @return mixed An array if $single is false. The value of meta data field
* if $single is true. False for an invalid $comment_id.