diff --git a/src/wp-includes/comment-functions.php b/src/wp-includes/comment-functions.php index c26bdc4234..6b055d1d22 100644 --- a/src/wp-includes/comment-functions.php +++ b/src/wp-includes/comment-functions.php @@ -1758,7 +1758,12 @@ function wp_new_comment_notify_moderator( $comment_ID ) { $comment = get_comment( $comment_ID ); // Only send notifications for pending comments. - if ( '0' != $comment->comment_approved ) { + $maybe_notify = ( '0' == $comment->comment_approved ); + + /** This filter is documented in wp-includes/comment-functions.php */ + $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_ID ); + + if ( ! $maybe_notify ) { return false; } @@ -1770,17 +1775,33 @@ function wp_new_comment_notify_moderator( $comment_ID ) { * * @since 4.4.0 * - * @param int $comment_ID ID of the comment. + * 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 ); + $maybe_notify = get_option( 'comments_notify' ); + + /** + * Filter whether to send the post author new comment notification emails, + * overriding the site setting. + * + * @since 4.4.0 + * + * @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. + * wp_notify_postauthor() checks if notifying the author of their own comment. * By default, it won't, but filters can override this. */ - if ( ! get_option( 'comments_notify' ) ) { + if ( ! $maybe_notify ) { return false; } @@ -1800,7 +1821,7 @@ function wp_new_comment_notify_postauthor( $comment_ID ) { * * @since 1.0.0 * - * global wpdb $wpdb + * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Comment $comment_id Comment ID or WP_Comment object. * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'. diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php index 93ad0acfca..6a19509c55 100644 --- a/src/wp-includes/pluggable.php +++ b/src/wp-includes/pluggable.php @@ -1561,20 +1561,36 @@ endif; if ( !function_exists('wp_notify_moderator') ) : /** - * Notifies the moderator of the blog about a new comment that is awaiting approval. + * Notifies the moderator of the site about a new comment that is awaiting approval. * * @since 1.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * - * @param int $comment_id Comment ID - * @return true Always returns true + * Uses the {@see 'notify_moderator'} filter to determine whether the site moderator + * should be notified, overriding the site setting. + * + * @param int $comment_id Comment ID. + * @return true Always returns true. */ function wp_notify_moderator($comment_id) { global $wpdb; - if ( 0 == get_option( 'moderation_notify' ) ) + $maybe_notify = get_option( 'moderation_notify' ); + + /** + * Filter whether to send the site moderator email notifications, overriding the site setting. + * + * @since 4.4.0 + * + * @param bool $maybe_notify Whether to notify blog moderator. + * @param int $comment_ID The id of the comment for the notification. + */ + $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_id ); + + if ( ! $maybe_notify ) { return true; + } $comment = get_comment($comment_id); $post = get_post($comment->comment_post_ID); @@ -2172,7 +2188,7 @@ function wp_rand( $min = 0, $max = 0 ) { } else { $use_random_int_functionality = false; } - } catch ( Throwable $t ) { + } catch ( Throwable $t ) { $use_random_int_functionality = false; } catch ( Exception $e ) { $use_random_int_functionality = false; diff --git a/tests/phpunit/tests/comment.php b/tests/phpunit/tests/comment.php index 7a6846bcf6..d3b0bf5c5e 100644 --- a/tests/phpunit/tests/comment.php +++ b/tests/phpunit/tests/comment.php @@ -7,8 +7,19 @@ class Tests_Comment extends WP_UnitTestCase { protected static $user_id; protected static $post_id; + public function setUp() { + parent::setUp(); + unset( $GLOBALS['phpmailer']->mock_sent ); + } + public static function wpSetUpBeforeClass( $factory ) { - self::$user_id = $factory->user->create(); + self::$user_id = $factory->user->create( array( + 'role' => 'author', + 'user_login' => 'test_wp_user_get', + 'user_pass' => 'password', + 'user_email' => 'test@test.com', + ) ); + self::$post_id = $factory->post->create( array( 'post_author' => self::$user_id ) ); @@ -359,4 +370,207 @@ class Tests_Comment extends WP_UnitTestCase { $this->assertSame( $post->$pf, $comment->$pf, $pf ); } } + + + /** + * Helper function to set up comment for 761 tests. + * + * @since 4.4.0 + * @access public + */ + public function setup_notify_comment(){ + /** + * Mock some server variables. + */ + $_SERVER['SERVER_NAME'] = 'phpunit.wordpress.dev'; + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + + /** + * Prevent flood alert from firing. + */ + add_filter( 'comment_flood_filter', '__return_false' ); + + /** + * Set up a comment for testing. + */ + $post = $this->factory->post->create( array( + 'post_author' => self::$user_id, + ) ); + + $comment = $this->factory->comment->create( array( + 'comment_post_ID' => $post, + ) ); + + return array( + 'post' => $post, + 'comment' => $comment, + ); + } + + /** + * @ticket 761 + */ + public function test_wp_notify_moderator_filter_moderation_notify_option_true_filter_false() { + $comment_data = $this->setup_notify_comment(); + + /** + * Test with moderator notification setting on, filter set to off. + * Should not send a notification. + */ + update_option( 'moderation_notify', 1 ); + add_filter( 'notify_moderator', '__return_false' ); + + $notification_sent = $this->try_sending_moderator_notification( $comment_data['comment'], $comment_data['post'] ); + + $this->assertFalse( $notification_sent, 'Moderator notification setting on, filter set to off' ); + + remove_filter( 'notify_moderator', '__return_false' ); + + } + + /** + * @ticket 761 + */ + public function test_wp_notify_moderator_filter_moderation_notify_option_false_filter_true() { + $comment_data = $this->setup_notify_comment(); + + /** + * Test with moderator notification setting off, filter set to on. + * Should send a notification. + */ + update_option( 'moderation_notify', 0 ); + add_filter( 'notify_moderator', '__return_true' ); + + $notification_sent = $this->try_sending_moderator_notification( $comment_data['comment'], $comment_data['post'] ); + + $this->assertTrue( $notification_sent, 'Moderator notification setting off, filter set to on' ); + + remove_filter( 'notify_moderator', '__return_true' ); + } + + /** + * @ticket 761 + */ + public function test_wp_notify_post_author_filter_comments_notify_option_true_filter_false() { + + $comment_data = $this->setup_notify_comment(); + + /** + * Test with author notification setting on, filter set to off. + * Should not send a notification. + */ + update_option( 'comments_notify', 1 ); + add_filter( 'notify_post_author', '__return_false' ); + + $notification_sent = $this->try_sending_author_notification( $comment_data['comment'], $comment_data['post'] ); + + $this->assertFalse( $notification_sent, 'Test with author notification setting on, filter set to off' ); + + remove_filter( 'notify_post_author', '__return_false' ); + } + + /** + * @ticket 761 + */ + public function test_wp_notify_post_author_filter_comments_notify_option_false_filter_true() { + $comment_data = $this->setup_notify_comment(); + + /** + * Test with author notification setting off, filter set to on. + * Should send a notification. + */ + update_option( 'comments_notify', 0 ); + add_filter( 'notify_post_author', '__return_true' ); + + $notification_sent = $this->try_sending_author_notification( $comment_data['comment'], $comment_data['post'] ); + + $this->assertTrue( $notification_sent, 'Test with author notification setting off, filter set to on' ); + + remove_filter( 'notify_post_author', '__return_true' ); + } + + /** + * Helper function to test moderator notifications. + * + * @since 4.4.0 + * @access public + */ + public function try_sending_moderator_notification( $comment, $post ) { + + // Don't approve comments, triggering notifications. + add_filter( 'pre_comment_approved', '__return_false' ); + + // Moderators are notified when a new comment is added. + $data = array( + 'comment_post_ID' => $post, + 'comment_author' => rand_str(), + 'comment_author_url' => '', + 'comment_author_email' => '', + 'comment_type' => '', + 'comment_content' => rand_str(), + ); + wp_new_comment( $data ); + + // Check to see if a notification email was sent to the moderator `admin@example.org`. + if ( isset( $GLOBALS['phpmailer']->mock_sent ) + && ! empty( $GLOBALS['phpmailer']->mock_sent ) + && 'admin@example.org' == $GLOBALS['phpmailer']->mock_sent[0]['to'][0][0] + ) { + $email_sent_when_comment_added = true; + unset( $GLOBALS['phpmailer']->mock_sent ); + } else { + $email_sent_when_comment_added = false; + } + + return $email_sent_when_comment_added; + } + + /** + * Helper function to test sending author notifications. + * + * @since 4.4.0 + * @access public + */ + public function try_sending_author_notification( $comment, $post ) { + + // Approve comments, triggering notifications. + add_filter( 'pre_comment_approved', '__return_true' ); + + // Post authors possibly notified when a comment is approved on their post. + wp_set_comment_status( $comment, 'approve' ); + + // Check to see if a notification email was sent to the post author `test@test.com`. + if ( isset( $GLOBALS['phpmailer']->mock_sent ) + && ! empty( $GLOBALS['phpmailer']->mock_sent ) + && 'test@test.com' == $GLOBALS['phpmailer']->mock_sent[0]['to'][0][0] + ) { + $email_sent_when_comment_approved = true; + } else { + $email_sent_when_comment_approved = false; + } + unset( $GLOBALS['phpmailer']->mock_sent ); + + // Post authors are notified when a new comment is added to their post. + $data = array( + 'comment_post_ID' => $post, + 'comment_author' => rand_str(), + 'comment_author_url' => '', + 'comment_author_email' => '', + 'comment_type' => '', + 'comment_content' => rand_str(), + ); + wp_new_comment( $data ); + + // Check to see if a notification email was sent to the post author `test@test.com`. + if ( isset( $GLOBALS['phpmailer']->mock_sent ) && + ! empty( $GLOBALS['phpmailer']->mock_sent ) && + 'test@test.com' == $GLOBALS['phpmailer']->mock_sent[0]['to'][0][0] ) { + $email_sent_when_comment_added = true; + unset( $GLOBALS['phpmailer']->mock_sent ); + } else { + $email_sent_when_comment_added = false; + } + + return $email_sent_when_comment_approved || $email_sent_when_comment_added; + } }