Index: src/wp-comments-post.php
===================================================================
--- src/wp-comments-post.php	(revision 34693)
+++ src/wp-comments-post.php	(working copy)
@@ -17,129 +17,17 @@
 
 nocache_headers();
 
-$comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : 0;
-
-$post = get_post($comment_post_ID);
-
-if ( empty( $post->comment_status ) ) {
-	/**
-	 * Fires when a comment is attempted on a post that does not exist.
-	 *
-	 * @since 1.5.0
-	 *
-	 * @param int $comment_post_ID Post ID.
-	 */
-	do_action( 'comment_id_not_found', $comment_post_ID );
-	exit;
-}
-
-// get_post_status() will get the parent status for attachments.
-$status = get_post_status($post);
-
-$status_obj = get_post_status_object($status);
-
-if ( ! comments_open( $comment_post_ID ) ) {
-	/**
-	 * Fires when a comment is attempted on a post that has comments closed.
-	 *
-	 * @since 1.5.0
-	 *
-	 * @param int $comment_post_ID Post ID.
-	 */
-	do_action( 'comment_closed', $comment_post_ID );
-	wp_die( __( 'Sorry, comments are closed for this item.' ), 403 );
-} elseif ( 'trash' == $status ) {
-	/**
-	 * Fires when a comment is attempted on a trashed post.
-	 *
-	 * @since 2.9.0
-	 *
-	 * @param int $comment_post_ID Post ID.
-	 */
-	do_action( 'comment_on_trash', $comment_post_ID );
-	exit;
-} elseif ( ! $status_obj->public && ! $status_obj->private ) {
-	/**
-	 * Fires when a comment is attempted on a post in draft mode.
-	 *
-	 * @since 1.5.1
-	 *
-	 * @param int $comment_post_ID Post ID.
-	 */
-	do_action( 'comment_on_draft', $comment_post_ID );
-	exit;
-} elseif ( post_password_required( $comment_post_ID ) ) {
-	/**
-	 * Fires when a comment is attempted on a password-protected post.
-	 *
-	 * @since 2.9.0
-	 *
-	 * @param int $comment_post_ID Post ID.
-	 */
-	do_action( 'comment_on_password_protected', $comment_post_ID );
-	exit;
-} else {
-	/**
-	 * Fires before a comment is posted.
-	 *
-	 * @since 2.8.0
-	 *
-	 * @param int $comment_post_ID Post ID.
-	 */
-	do_action( 'pre_comment_on_post', $comment_post_ID );
-}
-
-$comment_author       = ( isset( $_POST['author'] ) && is_string( $_POST['author'] ) ) ? trim( strip_tags( $_POST['author'] ) ) : null;
-$comment_author_email = ( isset( $_POST['email'] ) && is_string( $_POST['email'] ) ) ? trim( $_POST['email'] ) : null;
-$comment_author_url   = ( isset( $_POST['url'] ) && is_string( $_POST['url'] ) ) ? trim( $_POST['url'] ) : null;
-$comment_content      = ( isset( $_POST['comment'] ) && is_string( $_POST['comment'] ) ) ? trim( $_POST['comment'] ) : null;
-
-// If the user is logged in
-$user = wp_get_current_user();
-if ( $user->exists() ) {
-	if ( empty( $user->display_name ) )
-		$user->display_name=$user->user_login;
-	$comment_author       = wp_slash( $user->display_name );
-	$comment_author_email = wp_slash( $user->user_email );
-	$comment_author_url   = wp_slash( $user->user_url );
-	if ( current_user_can( 'unfiltered_html' ) ) {
-		if ( ! isset( $_POST['_wp_unfiltered_html_comment'] )
-			|| ! wp_verify_nonce( $_POST['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
-		) {
-			kses_remove_filters(); // start with a clean slate
-			kses_init_filters(); // set up the filters
-		}
-	}
-} else {
-	if ( get_option( 'comment_registration' ) || 'private' == $status ) {
-		wp_die( __( 'Sorry, you must be logged in to post a comment.' ), 403 );
+$comment = wp_handle_comment_post( wp_unslash( $_POST ) );
+if ( is_wp_error( $comment ) ) {
+	$data = $comment->get_error_data();
+	if ( ! empty( $data ) ) {
+		wp_die( $comment->get_error_message(), $data );
+	} else {
+		exit;
 	}
 }
 
-$comment_type = '';
-
-if ( get_option('require_name_email') && !$user->exists() ) {
-	if ( 6 > strlen( $comment_author_email ) || '' == $comment_author ) {
-		wp_die( __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
-	} elseif ( ! is_email( $comment_author_email ) ) {
-		wp_die( __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
-	}
-}
-
-if ( '' == $comment_content ) {
-	wp_die( __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
-}
-
-$comment_parent = isset($_POST['comment_parent']) ? absint($_POST['comment_parent']) : 0;
-
-$commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
-
-$comment_id = wp_new_comment( $commentdata );
-if ( ! $comment_id ) {
-	wp_die( __( "<strong>ERROR</strong>: The comment could not be saved. Please try again later." ) );
-}
-
-$comment = get_comment( $comment_id );
+$user = wp_get_current_user();
 
 /**
  * Perform other actions when comment cookies are set.
@@ -151,7 +39,7 @@
  */
 do_action( 'set_comment_cookies', $comment, $user );
 
-$location = empty($_POST['redirect_to']) ? get_comment_link( $comment ) : $_POST['redirect_to'] . '#comment-' . $comment_id;
+$location = empty( $_POST['redirect_to'] ) ? get_comment_link( $comment ) : $_POST['redirect_to'] . '#comment-' . $comment->comment_ID;
 
 /**
  * Filter the location URI to send the commenter after posting.
Index: tests/phpunit/tests/comments-post.php
===================================================================
--- tests/phpunit/tests/comments-post.php	(revision 0)
+++ tests/phpunit/tests/comments-post.php	(working copy)
@@ -0,0 +1,515 @@
+<?php
+
+/**
+ * @group comment
+ */
+class Tests_Comments_Post extends WP_UnitTestCase {
+
+	function setUp() {
+		parent::setUp();
+		require_once ABSPATH . WPINC . '/class-phpass.php';
+	}
+
+	function tearDown() {
+		wp_set_current_user( 0 );
+		parent::tearDown();
+	}
+
+	public function test_posting_comment_to_invalid_post_returns_error() {
+
+		$error = 'comment_id_not_found';
+
+		$this->assertSame( 0, did_action( $error ) );
+
+		$data = array(
+			'comment_post_ID' => 0,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertSame( 1, did_action( $error ) );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_post_with_closed_comments_returns_error() {
+
+		$error = 'comment_closed';
+
+		$this->assertSame( 0, did_action( $error ) );
+
+		$post = $this->factory->post->create_and_get( array(
+			'comment_status' => 'closed',
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertSame( 1, did_action( $error ) );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_trashed_post_returns_error() {
+
+		$error = 'comment_on_trash';
+
+		$this->assertSame( 0, did_action( $error ) );
+
+		$post = $this->factory->post->create_and_get();
+		wp_trash_post( $post );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertSame( 1, did_action( $error ) );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_draft_post_returns_error() {
+
+		$error = 'comment_on_draft';
+
+		$this->assertSame( 0, did_action( $error ) );
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_status' => 'draft',
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertSame( 1, did_action( $error ) );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_scheduled_post_returns_error() {
+
+		// Same error as commenting on a draft
+		$error = 'comment_on_draft';
+
+		$this->assertSame( 0, did_action( $error ) );
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_date' => date( 'Y-m-d H:i:s', strtotime( '+1 day' ) ),
+		) );
+
+		$this->assertSame( 'future', $post->post_status );
+
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertSame( 1, did_action( $error ) );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_password_required_post_returns_error() {
+
+		$error = 'comment_on_password_protected';
+
+		$this->assertSame( 0, did_action( $error ) );
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_password' => 'password',
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertSame( 1, did_action( $error ) );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_password_protected_post_succeeds() {
+
+		$password = 'password';
+		$hasher   = new PasswordHash( 8, true );
+
+		$_COOKIE['wp-postpass_' . COOKIEHASH] = $hasher->HashPassword( $password );
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_password' => $password,
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+			'author'          => 'Comment Author',
+			'email'           => 'comment@example.org',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		unset( $_COOKIE['wp-postpass_' . COOKIEHASH] );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+
+	}
+
+	public function test_posting_valid_comment_as_logged_in_user_succeeds() {
+
+		$user = $this->factory->user->create_and_get( array(
+			'user_url' => 'http://user.example.org'
+		) );
+
+		wp_set_current_user( $user->ID );
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+
+		$this->assertSame( 'Comment', $comment->comment_content);
+		$this->assertSame( $user->display_name, $comment->comment_author );
+		$this->assertSame( $user->user_email, $comment->comment_author_email );
+		$this->assertSame( $user->user_url, $comment->comment_author_url );
+
+	}
+
+	public function test_posting_valid_comment_anonymously_succeeds() {
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+			'author'          => 'Comment Author',
+			'email'           => 'comment@example.org',
+			'url'             => 'user.example.org'
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+
+		$this->assertSame( 'Comment', $comment->comment_content);
+		$this->assertSame( 'Comment Author', $comment->comment_author );
+		$this->assertSame( 'comment@example.org', $comment->comment_author_email );
+		$this->assertSame( 'http://user.example.org', $comment->comment_author_url );
+
+	}
+
+	public function test_posting_comment_anonymously_to_private_post_returns_error() {
+
+		$error = 'not_logged_in';
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_status' => 'private',
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertFalse( is_user_logged_in() );
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_to_own_private_post_succeeds() {
+
+		$user = $this->factory->user->create_and_get();
+
+		wp_set_current_user( $user->ID );
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_status' => 'private',
+			'post_author' => $user->ID,
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertTrue( current_user_can( 'read_post', $post->ID ) );
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+
+	}
+
+	public function test_posting_comment_to_accessible_private_post_succeeds() {
+
+		$author = $this->factory->user->create_and_get( array(
+			'role' => 'author',
+		) );
+		$user = $this->factory->user->create_and_get( array(
+			'role' => 'editor',
+		) );
+
+		wp_set_current_user( $user->ID );
+
+		$post = $this->factory->post->create_and_get( array(
+			'post_status' => 'private',
+			'post_author' => $author->ID,
+		) );
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertTrue( current_user_can( 'read_post', $post->ID ) );
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+
+	}
+
+	public function test_anonymous_user_cannot_comment_unfiltered_html() {
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment <script>alert(document.cookie);</script>',
+			'author'          => 'Comment Author',
+			'email'           => 'comment@example.org',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+		$this->assertNotContains( '<script', $comment->comment_content );
+
+	}
+
+	public function test_unprivileged_user_cannot_comment_unfiltered_html() {
+
+		$user = $this->factory->user->create_and_get( array(
+			'role' => 'author',
+		) );
+		wp_set_current_user( $user->ID );
+
+		$this->assertFalse( current_user_can( 'unfiltered_html' ) );
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment <script>alert(document.cookie);</script>',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+		$this->assertNotContains( '<script', $comment->comment_content );
+
+	}
+
+	public function test_unprivileged_user_cannot_comment_unfiltered_html_even_with_valid_nonce() {
+
+		$user = $this->factory->user->create_and_get( array(
+			'role' => 'author',
+		) );
+		wp_set_current_user( $user->ID );
+
+		$this->assertFalse( current_user_can( 'unfiltered_html' ) );
+
+		$post   = $this->factory->post->create_and_get();
+		$action = 'unfiltered-html-comment_' . $post->ID;
+		$nonce  = wp_create_nonce( $action );
+
+		$this->assertNotFalse( wp_verify_nonce( $nonce, $action ) );
+
+		$data = array(
+			'comment_post_ID'             => $post->ID,
+			'comment'                     => 'Comment <script>alert(document.cookie);</script>',
+			'_wp_unfiltered_html_comment' => $nonce,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+		$this->assertNotContains( '<script', $comment->comment_content );
+
+	}
+
+	public function test_privileged_user_can_comment_unfiltered_html_with_valid_nonce() {
+
+		$this->assertFalse( defined( 'DISALLOW_UNFILTERED_HTML' ) );
+
+		$user = $this->factory->user->create_and_get( array(
+			'role' => 'editor',
+		) );
+
+		if ( is_multisite() ) {
+			// In multisite, only Super Admins can post unfiltered HTML
+			$this->assertFalse( user_can( $user->ID, 'unfiltered_html' ) );
+			grant_super_admin( $user->ID );
+		}
+
+		wp_set_current_user( $user->ID );
+
+		$this->assertTrue( current_user_can( 'unfiltered_html' ) );
+
+		$post   = $this->factory->post->create_and_get();
+		$action = 'unfiltered-html-comment_' . $post->ID;
+		$nonce  = wp_create_nonce( $action );
+
+		$this->assertNotFalse( wp_verify_nonce( $nonce, $action ) );
+
+		$data = array(
+			'comment_post_ID'             => $post->ID,
+			'comment'                     => 'Comment <script>alert(document.cookie);</script>',
+			'_wp_unfiltered_html_comment' => $nonce,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+		$this->assertContains( '<script', $comment->comment_content );
+
+	}
+
+	public function test_privileged_user_cannot_comment_unfiltered_html_without_valid_nonce() {
+
+		$user = $this->factory->user->create_and_get( array(
+			'role' => 'editor',
+		) );
+
+		if ( is_multisite() ) {
+			// In multisite, only Super Admins can post unfiltered HTML
+			$this->assertFalse( user_can( $user->ID, 'unfiltered_html' ) );
+			grant_super_admin( $user->ID );
+		}
+
+		wp_set_current_user( $user->ID );
+
+		$this->assertTrue( current_user_can( 'unfiltered_html' ) );
+
+		$post   = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment <script>alert(document.cookie);</script>',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertNotWPError( $comment );
+		$this->assertInstanceOf( 'WP_Comment', $comment );
+		$this->assertNotContains( '<script', $comment->comment_content );
+
+	}
+
+	public function test_posting_comment_as_anonymous_user_when_registration_required_returns_error() {
+
+		$error = 'not_logged_in';
+
+		$_comment_registration = get_option( 'comment_registration' );
+		update_option( 'comment_registration', '1' );
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		update_option( 'comment_registration', $_comment_registration );
+
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_with_no_name_when_name_email_required_returns_error() {
+
+		$error = 'require_name_email';
+
+		$_require_name_email = get_option( 'require_name_email' );
+		update_option( 'require_name_email', '1' );
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+			'email'           => 'comment@example.org',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		update_option( 'require_name_email', $_require_name_email );
+
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_with_no_email_when_name_email_required_returns_error() {
+
+		$error = 'require_name_email';
+
+		$_require_name_email = get_option( 'require_name_email' );
+		update_option( 'require_name_email', '1' );
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+			'author'          => 'Comment Author',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		update_option( 'require_name_email', $_require_name_email );
+
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_with_invalid_email_when_name_email_required_returns_error() {
+
+		$error = 'require_valid_email';
+
+		$_require_name_email = get_option( 'require_name_email' );
+		update_option( 'require_name_email', '1' );
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => 'Comment',
+			'author'          => 'Comment Author',
+			'email'           => 'not_an_email',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		update_option( 'require_name_email', $_require_name_email );
+
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+	public function test_posting_comment_with_no_comment_content_returns_error() {
+
+		$error = 'require_valid_comment';
+
+		$post = $this->factory->post->create_and_get();
+		$data = array(
+			'comment_post_ID' => $post->ID,
+			'comment'         => '',
+			'author'          => 'Comment Author',
+			'email'           => 'comment@example.org',
+		);
+		$comment = wp_handle_comment_post( $data );
+
+		$this->assertWPError( $comment );
+		$this->assertSame( $error, $comment->get_error_code() );
+
+	}
+
+}
Index: src/wp-includes/comment-functions.php
===================================================================
--- src/wp-includes/comment-functions.php	(revision 34689)
+++ src/wp-includes/comment-functions.php	(working copy)
@@ -2550,3 +2550,187 @@
 
 	return $open;
 }
+
+/**
+ * Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form.
+ *
+ * @param array $comment_data {
+ *     Comment data.
+ *
+ *     @type string|int $comment_post_ID             The ID of the post that relates to the comment.
+ *     @type string     $author                      The name of the comment author.
+ *     @type string     $email                       The comment author email address.
+ *     @type string     $url                         The comment author URL.
+ *     @type string     $comment                     The content of the comment.
+ *     @type string|int $comment_parent              The ID of this comment's parent, if any. Default 0.
+ *     @type string     $_wp_unfiltered_html_comment The nonce value for allowing unfiltered HTML.
+ * }
+ * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
+ */
+function wp_handle_comment_post( $comment_data ) {
+
+	$comment_post_ID = isset( $comment_data['comment_post_ID'] )
+		? (int) $comment_data['comment_post_ID']
+		: 0;
+	$comment_author = ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) )
+		? trim( strip_tags( $comment_data['author'] ) )
+		: null;
+	$comment_author_email = ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) )
+		? trim( $comment_data['email'] )
+		: null;
+	$comment_author_url = ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) )
+		? trim( $comment_data['url'] )
+		: null;
+	$comment_content = ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) )
+		? trim( $comment_data['comment'] )
+		: null;
+	$comment_parent = isset( $comment_data['comment_parent'] )
+		? absint( $comment_data['comment_parent'] )
+		: 0;
+	$_wp_unfiltered_html_comment = ( isset( $comment_data['_wp_unfiltered_html_comment'] ) && is_string( $comment_data['_wp_unfiltered_html_comment'] ) )
+		? trim( $comment_data['_wp_unfiltered_html_comment'] )
+		: null;
+
+	$post = get_post( $comment_post_ID );
+
+	if ( empty( $post->comment_status ) ) {
+
+		/**
+		 * Fires when a comment is attempted on a post that does not exist.
+		 *
+		 * @since 1.5.0
+		 *
+		 * @param int $comment_post_ID Post ID.
+		 */
+		do_action( 'comment_id_not_found', $comment_post_ID );
+
+		return new WP_Error( 'comment_id_not_found' );
+
+	}
+
+	// get_post_status() will get the parent status for attachments.
+	$status = get_post_status( $post );
+
+	$status_obj = get_post_status_object( $status );
+
+	if ( ! comments_open( $comment_post_ID ) ) {
+
+		/**
+		 * Fires when a comment is attempted on a post that has comments closed.
+		 *
+		 * @since 1.5.0
+		 *
+		 * @param int $comment_post_ID Post ID.
+		 */
+		do_action( 'comment_closed', $comment_post_ID );
+
+		return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
+
+	} elseif ( 'trash' == $status ) {
+
+		/**
+		 * Fires when a comment is attempted on a trashed post.
+		 *
+		 * @since 2.9.0
+		 *
+		 * @param int $comment_post_ID Post ID.
+		 */
+		do_action( 'comment_on_trash', $comment_post_ID );
+
+		return new WP_Error( 'comment_on_trash' );
+
+	} elseif ( ! $status_obj->public && ! $status_obj->private ) {
+
+		/**
+		 * Fires when a comment is attempted on a post in draft mode.
+		 *
+		 * @since 1.5.1
+		 *
+		 * @param int $comment_post_ID Post ID.
+		 */
+		do_action( 'comment_on_draft', $comment_post_ID );
+
+		return new WP_Error( 'comment_on_draft' );
+
+	} elseif ( post_password_required( $comment_post_ID ) ) {
+
+		/**
+		 * Fires when a comment is attempted on a password-protected post.
+		 *
+		 * @since 2.9.0
+		 *
+		 * @param int $comment_post_ID Post ID.
+		 */
+		do_action( 'comment_on_password_protected', $comment_post_ID );
+
+		return new WP_Error( 'comment_on_password_protected' );
+
+	} else {
+
+		/**
+		 * Fires before a comment is posted.
+		 *
+		 * @since 2.8.0
+		 *
+		 * @param int $comment_post_ID Post ID.
+		 */
+		do_action( 'pre_comment_on_post', $comment_post_ID );
+
+	}
+
+	// If the user is logged in
+	$user = wp_get_current_user();
+	if ( $user->exists() ) {
+		if ( empty( $user->display_name ) ) {
+			$user->display_name=$user->user_login;
+		}
+		$comment_author       = $user->display_name;
+		$comment_author_email = $user->user_email;
+		$comment_author_url   = $user->user_url;
+		if ( current_user_can( 'unfiltered_html' ) ) {
+			if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
+				|| ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
+			) {
+				kses_remove_filters(); // start with a clean slate
+				kses_init_filters(); // set up the filters
+			}
+		}
+	} else {
+		if ( get_option( 'comment_registration' ) || 'private' == $status ) {
+			return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to post a comment.' ), 403 );
+		}
+	}
+
+	$comment_type = '';
+
+	if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
+		if ( 6 > strlen( $comment_author_email ) || '' == $comment_author ) {
+			return new WP_Error( 'require_name_email', __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
+		} elseif ( ! is_email( $comment_author_email ) ) {
+			return new WP_Error( 'require_valid_email', __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
+		}
+	}
+
+	if ( '' == $comment_content ) {
+		return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
+	}
+
+	$commentdata = compact(
+		'comment_post_ID',
+		'comment_author',
+		'comment_author_email',
+		'comment_author_url',
+		'comment_content',
+		'comment_type',
+		'comment_parent',
+		'user_ID'
+	);
+
+	$comment_id = wp_new_comment( wp_slash( $commentdata ) );
+	if ( ! $comment_id ) {
+		return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
+	}
+
+	return get_comment( $comment_id );
+
+}
