wp_new_comment( array $commentdata, bool $wp_error = false ): int|false|WP_Error

Adds a new comment to the database.

Description

Filters new comment to ensure that the fields are sanitized and valid before inserting comment into database. Calls ‘comment_post’ action with comment ID and whether comment is approved by WordPress. Also has ‘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 https://core.trac.wordpress.org/ticket/9235

See also

Parameters

$commentdataarrayrequired
Comment data.
  • comment_author string
    The name of the comment author.
  • comment_author_email string
    The comment author email address.
  • comment_author_url string
    The comment author URL.
  • comment_content string
    The content of the comment.
  • comment_date string
    The date the comment was submitted. Default is the current time.
  • comment_date_gmt string
    The date the comment was submitted in the GMT timezone.
    Default is $comment_date in the GMT timezone.
  • comment_type string
    Comment type. Default 'comment'.
  • comment_parent int
    The ID of this comment’s parent, if any. Default 0.
  • comment_post_ID int
    The ID of the post that relates to the comment.
  • user_id int
    The ID of the user who submitted the comment. Default 0.
  • user_ID int
    Kept for backward-compatibility. Use $user_id instead.
  • comment_agent string
    Comment author user agent. Default is the value of 'HTTP_USER_AGENT' in the $_SERVER superglobal sent in the original request.
  • comment_author_IP string
    Comment author IP address in IPv4 format. Default is the value of 'REMOTE_ADDR' in the $_SERVER superglobal sent in the original request.
$wp_errorbooloptional
Should errors be returned as WP_Error objects instead of executing wp_die() ?
More Arguments from wp_die( … $args )Arguments to control behavior. If $args is an integer, then it is treated as the response code.
  • response int
    The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
  • link_url string
    A URL to include a link to. Only works in combination with $link_text.
    Default empty string.
  • link_text string
    A label for the link to include. Only works in combination with $link_url.
    Default empty string.
  • back_link bool
    Whether to include a link to go back. Default false.
  • text_direction string
    The text direction. This is only useful internally, when WordPress is still loading and the site’s locale is not set up yet. Accepts 'rtl' and 'ltr'.
    Default is the value of is_rtl() .
  • charset string
    Character set of the HTML output. Default 'utf-8'.
  • code string
    Error code to use. Default is 'wp_die', or the main error code if $message is a WP_Error.
  • exit bool
    Whether to exit the process after completion. Default true.

Default:false

Return

int|false|WP_Error The ID of the comment on success, false or WP_Error on failure.

Source

function wp_new_comment( $commentdata, $wp_error = false ) {
	global $wpdb;

	/*
	 * 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 1.5.0
	 * @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', 1 );
	}

	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 );

	if ( ! $comment_id ) {
		$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 );
		if ( ! $comment_id ) {
			return false;
		}
	}

	/**
	 * Fires immediately after a comment is inserted into the database.
	 *
	 * @since 1.2.0
	 * @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 );

	return $comment_id;
}

Hooks

do_action( ‘comment_post’, int $comment_id, int|string $comment_approved, array $commentdata )

Fires immediately after a comment is inserted into the database.

apply_filters( ‘preprocess_comment’, array $commentdata )

Filters a comment’s data before it is sanitized and inserted into the database.

Changelog

VersionDescription
5.5.0Introduced the comment_type argument.
4.7.0The $avoid_die parameter was added, allowing the function to return a WP_Error object instead of dying.
4.3.0Introduced the comment_agent and comment_author_IP arguments.
1.5.0Introduced.

User Contributed Notes

  1. Skip to note 3 content

    Basic Example

    global $post, $current_user; //for this example only :)
    
    $commentdata = array(
    	'comment_post_ID'      => $post->ID,             // To which post the comment will show up.
    	'comment_author'       => 'Another Someone',     // Fixed value - can be dynamic.
    	'comment_author_email' => 'someone@example.com', // Fixed value - can be dynamic.
    	'comment_author_url'   => 'http://example.com',  // Fixed value - can be dynamic.
    	'comment_content'      => 'Comment messsage...', // Fixed value - can be dynamic.
    	'comment_type'         => '',                    // Empty for regular comments, 'pingback' for pingbacks, 'trackback' for trackbacks.
    	'comment_parent'       => 0,                     // 0 if it's not a reply to another comment; if it's a reply, mention the parent comment ID here.
    	'user_id'              => $current_user->ID,     // Passing current user ID or any predefined as per the demand.
    );
    
    // Insert new comment and get the comment ID.
    $comment_id = wp_new_comment( $commentdata );
  2. Skip to note 4 content

    Warning: If you set comment_type to one of these words:

    “all”, “comment”, “comments”, “pings”

    WordPress will save the comment with that type but you will be unable to retrieve it using normal WordPress comment functions. Here’s what happens to those reserved words inside `WP_Comment_Query`, where types are gathered into comment_type__in whether you send them via the type or type__in argument:

    • all – No 'comment_type__in' clause will be in query
    • comment or comments'' added to comment_type_in
    • pings'pingback','trackback' added to comment_type_in

    Because of this, you will not be able to retrieve the comment using “normal” WordPress functions. To get it, you will have to filter comments_clauses to ensure your type is added to the WHERE clause. For example, the following will replace the '' inserted instead of “comment” with 'comment':

    add_filter( 'comments_clauses', 'add_comment_to_clauses', 10, 2 );
    
    function add_comment_to_clauses( $clauses, $WP_Comment_object ) {
        
        // use regex to find the empty string in where clause
        $clauses['where'] = preg_replace_callback(
            "~(comment_type[ ]*IN[ ]*\\(.*)('')~i",
            function ( $matches ) {
                // $matches[1] was everything up to the '' 
                // $matches[2] was the empty string
                return $matches[1] . "'','comment'";
            },
            $clauses['where']
        );
    
        return $clauses;
    }

You must log in before being able to contribute a note or feedback.