$comment_author_url = '';
if ( isset( $_COOKIE[ 'comment_author_url_' . COOKIEHASH ] ) ) {
$comment_author_url = $_COOKIE[ 'comment_author_url_' . COOKIEHASH ];
* Filters the current commenter's name, email, and URL.
* @param array $comment_author_data {
* An array of current commenter variables.
* @type string $comment_author The name of the current commenter, or an empty string.
* @type string $comment_author_email The email address of the current commenter, or an empty string.
* @type string $comment_author_url The URL address of the current commenter, or an empty string.
return apply_filters( 'wp_get_current_commenter', compact( 'comment_author', 'comment_author_email', 'comment_author_url' ) );
* Gets unapproved comment author's email.
* Used to allow the commenter to see their pending comment.
* @since 5.7.0 The window within which the author email for an unapproved comment
* can be retrieved was extended to 10 minutes.
* @return string The unapproved comment author's email (when supplied).
function wp_get_unapproved_comment_author_email() {
if ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) {
$comment_id = (int) $_GET['unapproved'];
$comment = get_comment( $comment_id );
if ( $comment && hash_equals( $_GET['moderation-hash'], wp_hash( $comment->comment_date_gmt ) ) ) {
// The comment will only be viewable by the comment author for 10 minutes.
$comment_preview_expires = strtotime( $comment->comment_date_gmt . '+10 minutes' );
if ( time() < $comment_preview_expires ) {
$commenter_email = $comment->comment_author_email;
if ( ! $commenter_email ) {
$commenter = wp_get_current_commenter();
$commenter_email = $commenter['comment_author_email'];
* Inserts a comment into the database.
* @since 4.4.0 Introduced the `$comment_meta` argument.
* @since 5.5.0 Default value for `$comment_type` argument changed to `comment`.
* @global wpdb $wpdb WordPress database abstraction object.
* @param array $commentdata {
* Array of arguments for inserting a new comment.
* @type string $comment_agent The HTTP user agent of the `$comment_author` when
* the comment was submitted. Default empty.
* @type int|string $comment_approved Whether the comment has been approved. Default 1.
* @type string $comment_author The name of the author of the comment. Default empty.
* @type string $comment_author_email The email address of the `$comment_author`. Default empty.
* @type string $comment_author_IP The IP address of the `$comment_author`. Default empty.
* @type string $comment_author_url The URL address of the `$comment_author`. Default empty.
* @type string $comment_content The content of the comment. Default empty.
* @type string $comment_date The date the comment was submitted. To set the date
* manually, `$comment_date_gmt` must also be specified.
* Default is the current time.
* @type string $comment_date_gmt The date the comment was submitted in the GMT timezone.
* Default is `$comment_date` in the site's GMT timezone.
* @type int $comment_karma The karma of the comment. Default 0.
* @type int $comment_parent ID of this comment's parent, if any. Default 0.
* @type int $comment_post_ID ID of the post that relates to the comment, if any.
* @type string $comment_type Comment type. Default 'comment'.
* @type array $comment_meta Optional. Array of key/value pairs to be stored in commentmeta for the
* @type int $user_id ID of the user who submitted the comment. Default 0.
* @return int|false The new comment's ID on success, false on failure.
function wp_insert_comment( $commentdata ) {
$data = wp_unslash( $commentdata );
$comment_author = ! isset( $data['comment_author'] ) ? '' : $data['comment_author'];
$comment_author_email = ! isset( $data['comment_author_email'] ) ? '' : $data['comment_author_email'];
$comment_author_url = ! isset( $data['comment_author_url'] ) ? '' : $data['comment_author_url'];
$comment_author_ip = ! isset( $data['comment_author_IP'] ) ? '' : $data['comment_author_IP'];
$comment_date = ! isset( $data['comment_date'] ) ? current_time( 'mysql' ) : $data['comment_date'];
$comment_date_gmt = ! isset( $data['comment_date_gmt'] ) ? get_gmt_from_date( $comment_date ) : $data['comment_date_gmt'];
$comment_post_id = ! isset( $data['comment_post_ID'] ) ? 0 : $data['comment_post_ID'];
$comment_content = ! isset( $data['comment_content'] ) ? '' : $data['comment_content'];
$comment_karma = ! isset( $data['comment_karma'] ) ? 0 : $data['comment_karma'];
$comment_approved = ! isset( $data['comment_approved'] ) ? 1 : $data['comment_approved'];
$comment_agent = ! isset( $data['comment_agent'] ) ? '' : $data['comment_agent'];
$comment_type = empty( $data['comment_type'] ) ? 'comment' : $data['comment_type'];
$comment_parent = ! isset( $data['comment_parent'] ) ? 0 : $data['comment_parent'];
$user_id = ! isset( $data['user_id'] ) ? 0 : $data['user_id'];
'comment_post_ID' => $comment_post_id,
'comment_author_IP' => $comment_author_ip,
if ( ! $wpdb->insert( $wpdb->comments, $compacted ) ) {
$id = (int) $wpdb->insert_id;
if ( 1 === (int) $comment_approved ) {
wp_update_comment_count( $comment_post_id );
foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
$data[] = "lastcommentmodified:$timezone";
wp_cache_delete_multiple( $data, 'timeinfo' );
clean_comment_cache( $id );
$comment = get_comment( $id );
// If metadata is provided, store it.
if ( isset( $commentdata['comment_meta'] ) && is_array( $commentdata['comment_meta'] ) ) {
foreach ( $commentdata['comment_meta'] as $meta_key => $meta_value ) {
add_comment_meta( $comment->comment_ID, $meta_key, $meta_value, true );
* Fires immediately after a comment is inserted into the database.
* @param int $id The comment ID.
* @param WP_Comment $comment Comment object.
do_action( 'wp_insert_comment', $id, $comment );
* Filters and sanitizes comment data.
* Sets the comment data 'filtered' field to true when finished. This can be
* checked as to whether the comment should be filtered and to keep from
* filtering the same comment more than once.
* @param array $commentdata Contains information on the comment.
* @return array Parsed comment information.
function wp_filter_comment( $commentdata ) {
if ( isset( $commentdata['user_ID'] ) ) {
* Filters the comment author's user ID before it is set.
* The first time this filter is evaluated, `user_ID` is checked
* (for back-compat), followed by the standard `user_id` value.
* @param int $user_id The comment author's user ID.
$commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_ID'] );
} elseif ( isset( $commentdata['user_id'] ) ) {
/** This filter is documented in wp-includes/comment.php */
$commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_id'] );
* Filters the comment author's browser user agent before it is set.
* @param string $comment_agent The comment author's browser user agent.
$commentdata['comment_agent'] = apply_filters( 'pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
/** This filter is documented in wp-includes/comment.php */
$commentdata['comment_author'] = apply_filters( 'pre_comment_author_name', $commentdata['comment_author'] );
* Filters the comment content before it is set.
* @param string $comment_content The comment content.
$commentdata['comment_content'] = apply_filters( 'pre_comment_content', $commentdata['comment_content'] );
* Filters the comment author's IP address before it is set.
* @param string $comment_author_ip The comment author's IP address.
$commentdata['comment_author_IP'] = apply_filters( 'pre_comment_user_ip', $commentdata['comment_author_IP'] );
/** This filter is documented in wp-includes/comment.php */
$commentdata['comment_author_url'] = apply_filters( 'pre_comment_author_url', $commentdata['comment_author_url'] );
/** This filter is documented in wp-includes/comment.php */
$commentdata['comment_author_email'] = apply_filters( 'pre_comment_author_email', $commentdata['comment_author_email'] );
$commentdata['filtered'] = true;
* Determines whether a comment should be blocked because of comment flood.
* @param bool $block Whether plugin has already blocked comment.
* @param int $time_lastcomment Timestamp for last comment.
* @param int $time_newcomment Timestamp for new comment.
* @return bool Whether comment should be blocked.
function wp_throttle_comment_flood( $block, $time_lastcomment, $time_newcomment ) {
if ( $block ) { // A plugin has already blocked... we'll let that decision stand.
if ( ( $time_newcomment - $time_lastcomment ) < 15 ) {
* Adds a new comment to the database.
* Filters new comment to ensure that the fields are sanitized and valid before
* inserting comment into database. Calls {@see 'comment_post'} action with comment ID
* and whether comment is approved by WordPress. Also has {@see 'preprocess_comment'}
* filter for processing the comment data before the function handles it.
* We use `REMOTE_ADDR` here directly. If you are behind a proxy, you should ensure
* that it is properly set, such as in wp-config.php, for your environment.
* See {@link https://core.trac.wordpress.org/ticket/9235}
* @since 4.3.0 Introduced the `comment_agent` and `comment_author_IP` arguments.
* @since 4.7.0 The `$avoid_die` parameter was added, allowing the function
* to return a WP_Error object instead of dying.
* @since 5.5.0 The `$avoid_die` parameter was renamed to `$wp_error`.
* @since 5.5.0 Introduced the `comment_type` argument.
* @see wp_insert_comment()
* @global wpdb $wpdb WordPress database abstraction object.
* @param array $commentdata {
* @type string $comment_author The name of the comment author.
* @type string $comment_author_email The comment author email address.
* @type string $comment_author_url The comment author URL.
* @type string $comment_content The content of the comment.
* @type string $comment_date The date the comment was submitted. Default is the current time.
* @type string $comment_date_gmt The date the comment was submitted in the GMT timezone.
* Default is `$comment_date` in the GMT timezone.
* @type string $comment_type Comment type. Default 'comment'.
* @type int $comment_parent The ID of this comment's parent, if any. Default 0.
* @type int $comment_post_ID The ID of the post that relates to the comment.
* @type int $user_id The ID of the user who submitted the comment. Default 0.
* @type int $user_ID Kept for backward-compatibility. Use `$user_id` instead.
* @type string $comment_agent Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
* in the `$_SERVER` superglobal sent in the original request.
* @type string $comment_author_IP Comment author IP address in IPv4 format. Default is the value of
* 'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
* @param bool $wp_error Should errors be returned as WP_Error objects instead of
* executing wp_die()? Default false.
* @return int|false|WP_Error The ID of the comment on success, false or WP_Error on failure.
function wp_new_comment( $commentdata, $wp_error = false ) {
* Normalize `user_ID` to `user_id`, but pass the old key
* to the `preprocess_comment` filter for backward compatibility.
if ( isset( $commentdata['user_ID'] ) ) {
$commentdata['user_ID'] = (int) $commentdata['user_ID'];
$commentdata['user_id'] = $commentdata['user_ID'];
} elseif ( isset( $commentdata['user_id'] ) ) {
$commentdata['user_id'] = (int) $commentdata['user_id'];
$commentdata['user_ID'] = $commentdata['user_id'];
$prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
if ( ! isset( $commentdata['comment_author_IP'] ) ) {
$commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
if ( ! isset( $commentdata['comment_agent'] ) ) {
$commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
* Filters a comment's data before it is sanitized and inserted into the database.
* @since 5.6.0 Comment data includes the `comment_agent` and `comment_author_IP` values.
* @param array $commentdata Comment data.
$commentdata = apply_filters( 'preprocess_comment', $commentdata );
$commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
// Normalize `user_ID` to `user_id` again, after the filter.
if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
$commentdata['user_ID'] = (int) $commentdata['user_ID'];
$commentdata['user_id'] = $commentdata['user_ID'];
} elseif ( isset( $commentdata['user_id'] ) ) {
$commentdata['user_id'] = (int) $commentdata['user_id'];
$commentdata['user_ID'] = $commentdata['user_id'];
$commentdata['comment_parent'] = isset( $commentdata['comment_parent'] ) ? absint( $commentdata['comment_parent'] ) : 0;
$parent_status = ( $commentdata['comment_parent'] > 0 ) ? wp_get_comment_status( $commentdata['comment_parent'] ) : '';
$commentdata['comment_parent'] = ( 'approved' === $parent_status || 'unapproved' === $parent_status ) ? $commentdata['comment_parent'] : 0;
$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
$commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 );
if ( empty( $commentdata['comment_date'] ) ) {
$commentdata['comment_date'] = current_time( 'mysql' );
if ( empty( $commentdata['comment_date_gmt'] ) ) {
$commentdata['comment_date_gmt'] = current_time( 'mysql', true );
if ( empty( $commentdata['comment_type'] ) ) {
$commentdata['comment_type'] = 'comment';
$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $wp_error );
if ( is_wp_error( $commentdata['comment_approved'] ) ) {
return $commentdata['comment_approved'];
$commentdata = wp_filter_comment( $commentdata );
if ( ! in_array( $commentdata['comment_approved'], array( 'trash', 'spam' ), true ) ) {
// Validate the comment again after filters are applied to comment data.
$commentdata['comment_approved'] = wp_check_comment_data( $commentdata );
if ( is_wp_error( $commentdata['comment_approved'] ) ) {
return $commentdata['comment_approved'];
$comment_id = wp_insert_comment( $commentdata );
$fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
foreach ( $fields as $field ) {
if ( isset( $commentdata[ $field ] ) ) {
$commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
$commentdata = wp_filter_comment( $commentdata );
$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $wp_error );
if ( is_wp_error( $commentdata['comment_approved'] ) ) {
return $commentdata['comment_approved'];
$comment_id = wp_insert_comment( $commentdata );
* Fires immediately after a comment is inserted into the database.
* @since 4.5.0 The `$commentdata` parameter was added.
* @param int $comment_id The comment ID.
* @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
* @param array $commentdata Comment data.
do_action( 'comment_post', $comment_id, $commentdata['comment_approved'], $commentdata );
* Sends a comment moderation notification to the comment moderator.
* @param int $comment_id ID of the comment.
* @return bool True on success, false on failure.
function wp_new_comment_notify_moderator( $comment_id ) {
$comment = get_comment( $comment_id );
// Only send notifications for pending comments.
$maybe_notify = ( '0' === $comment->comment_approved );
/** This filter is documented in wp-includes/pluggable.php */
$maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_id );
return wp_notify_moderator( $comment_id );
* Sends a notification of a new comment to the post author.
* Uses the {@see 'notify_post_author'} filter to determine whether the post author
* should be notified when a new comment is added, overriding site setting.
* @param int $comment_id Comment ID.
* @return bool True on success, false on failure.
function wp_new_comment_notify_postauthor( $comment_id ) {
$comment = get_comment( $comment_id );
$is_note = ( $comment && 'note' === $comment->comment_type );
$maybe_notify = $is_note ? get_option( 'wp_notes_notify', 1 ) : get_option( 'comments_notify' );
* Filters whether to send the post author new comment notification emails,
* overriding the site setting.
* @param bool $maybe_notify Whether to notify the post author about the new comment.
* @param int $comment_id The ID of the comment for the notification.
$maybe_notify = apply_filters( 'notify_post_author', $maybe_notify, $comment_id );
* wp_notify_postauthor() checks if notifying the author of their own comment.
* By default, it won't, but filters can override this.
// Send notifications for approved comments and all notes.
! isset( $comment->comment_approved ) ||
( '1' !== $comment->comment_approved && ! $is_note ) ) {