Skip to content

Commit 2c49c06

Browse files
Comments: Check comment approval before the notify_post_author filter.
The `notify_post_author` filter is documented as overriding the site setting, but the comment approval and type checks ran after the filter, so a callback returning true could not force a notification for an unapproved comment. Move those checks before the filter by using the comment status and type to build the default value: notes default to the `wp_notes_notify` option regardless of approval status, unapproved comments default to false, and approved comments default to the `comments_notify` option. The filter now receives false for unapproved comments instead of the raw option value, giving developers complete control over notifications. Invalid comment IDs now return false without firing the filter. Props westonruter, jorbin. Fixes #64217. git-svn-id: https://develop.svn.wordpress.org/trunk@62818 602fd350-edb4-49c9-b593-d223f7449a82
1 parent ffb25fd commit 2c49c06

2 files changed

Lines changed: 143 additions & 13 deletions

File tree

src/wp-includes/comment.php

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,25 +2462,46 @@ function wp_new_comment_notify_moderator( $comment_id ) {
24622462
/**
24632463
* Sends a notification of a new comment to the post author.
24642464
*
2465-
* @since 4.4.0
2466-
*
24672465
* Uses the {@see 'notify_post_author'} filter to determine whether the post author
24682466
* should be notified when a new comment is added, overriding site setting.
24692467
*
2468+
* @since 4.4.0
2469+
* @since 7.1.0 The comment approval status is now checked before the
2470+
* {@see 'notify_post_author'} filter, and invalid comment IDs
2471+
* return false without firing the filter.
2472+
*
24702473
* @param int $comment_id Comment ID.
24712474
* @return bool True on success, false on failure.
24722475
*/
24732476
function wp_new_comment_notify_postauthor( $comment_id ) {
24742477
$comment = get_comment( $comment_id );
2475-
$is_note = ( $comment && 'note' === $comment->comment_type );
2478+
if ( ! ( $comment instanceof WP_Comment ) ) {
2479+
return false;
2480+
}
2481+
$comment_id = (int) $comment->comment_ID;
2482+
$is_note = ( 'note' === $comment->comment_type );
24762483

2477-
$maybe_notify = $is_note ? get_option( 'wp_notes_notify', 1 ) : get_option( 'comments_notify' );
2484+
/*
2485+
* Determine the default notification behavior. Notes are eligible regardless
2486+
* of approval status, based on the 'wp_notes_notify' option. Other comments
2487+
* are only eligible once approved, based on the 'comments_notify' option.
2488+
*/
2489+
if ( $is_note ) {
2490+
$maybe_notify = (bool) get_option( 'wp_notes_notify', 1 );
2491+
} elseif ( '1' !== $comment->comment_approved ) {
2492+
$maybe_notify = false;
2493+
} else {
2494+
$maybe_notify = (bool) get_option( 'comments_notify' );
2495+
}
24782496

24792497
/**
2480-
* Filters whether to send the post author new comment notification emails,
2481-
* overriding the site setting.
2498+
* Filters whether to send the post author new comment and note notification emails,
2499+
* overriding the site settings and defaults. By default, notifications are sent for
2500+
* all notes and for approved comments.
24822501
*
24832502
* @since 4.4.0
2503+
* @since 7.1.0 Comment approval status is checked before this filter,
2504+
* and the filter no longer fires for invalid comment IDs.
24842505
*
24852506
* @param bool $maybe_notify Whether to notify the post author about the new comment.
24862507
* @param int $comment_id The ID of the comment for the notification.
@@ -2495,13 +2516,6 @@ function wp_new_comment_notify_postauthor( $comment_id ) {
24952516
return false;
24962517
}
24972518

2498-
// Send notifications for approved comments and all notes.
2499-
if (
2500-
! isset( $comment->comment_approved ) ||
2501-
( '1' !== $comment->comment_approved && ! $is_note ) ) {
2502-
return false;
2503-
}
2504-
25052519
return wp_notify_postauthor( $comment_id );
25062520
}
25072521

tests/phpunit/tests/comment.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,122 @@ public function test_wp_new_comment_notify_postauthor_should_not_send_email_when
11091109
$this->assertFalse( $sent );
11101110
}
11111111

1112+
/**
1113+
* @ticket 64217
1114+
*
1115+
* @covers ::wp_new_comment_notify_postauthor
1116+
*/
1117+
public function test_wp_new_comment_notify_postauthor_filter_should_receive_false_for_unapproved_comment(): void {
1118+
$c = self::factory()->comment->create(
1119+
array(
1120+
'comment_post_ID' => self::$post_id,
1121+
'comment_approved' => '0',
1122+
)
1123+
);
1124+
$this->assertIsInt( $c );
1125+
1126+
update_option( 'comments_notify', 1 );
1127+
1128+
$filter = new MockAction();
1129+
add_filter( 'notify_post_author', array( $filter, 'filter' ) );
1130+
1131+
$sent = wp_new_comment_notify_postauthor( $c );
1132+
1133+
$this->assertSame( 1, $filter->get_call_count() );
1134+
$args = array_first( $filter->get_args() );
1135+
$this->assertFalse( $args[0] ?? null, 'The filter should receive a default of false for an unapproved comment.' );
1136+
$this->assertFalse( $sent, 'No notification should be sent for an unapproved comment by default.' );
1137+
}
1138+
1139+
/**
1140+
* @ticket 64217
1141+
*
1142+
* @covers ::wp_new_comment_notify_postauthor
1143+
*/
1144+
public function test_wp_new_comment_notify_postauthor_filter_should_override_unapproved_comment(): void {
1145+
$c = self::factory()->comment->create(
1146+
array(
1147+
'comment_post_ID' => self::$post_id,
1148+
'comment_approved' => '0',
1149+
)
1150+
);
1151+
$this->assertIsInt( $c );
1152+
1153+
add_filter( 'notify_post_author', '__return_true' );
1154+
1155+
$sent = wp_new_comment_notify_postauthor( $c );
1156+
1157+
$this->assertTrue( $sent, 'The notify_post_author filter should be able to force a notification for an unapproved comment.' );
1158+
}
1159+
1160+
/**
1161+
* @ticket 64217
1162+
*
1163+
* @covers ::wp_new_comment_notify_postauthor
1164+
*/
1165+
public function test_wp_new_comment_notify_postauthor_should_not_send_email_for_invalid_comment(): void {
1166+
$filter = new MockAction();
1167+
add_filter( 'notify_post_author', array( $filter, 'filter' ) );
1168+
1169+
// An empty ID such as 0 would fall back to the global comment in get_comment().
1170+
$sent = wp_new_comment_notify_postauthor( PHP_INT_MAX );
1171+
1172+
$this->assertFalse( $sent, 'No notification should be sent for an invalid comment ID.' );
1173+
$this->assertSame( array(), $filter->get_events(), 'The notify_post_author filter should not fire for an invalid comment ID.' );
1174+
}
1175+
1176+
/**
1177+
* @ticket 64217
1178+
*
1179+
* @covers ::wp_new_comment_notify_postauthor
1180+
*/
1181+
public function test_wp_new_comment_notify_postauthor_filter_should_receive_truthy_default_for_unapproved_note(): void {
1182+
$c = self::factory()->comment->create(
1183+
array(
1184+
'comment_post_ID' => self::$post_id,
1185+
'comment_type' => 'note',
1186+
'comment_approved' => '0',
1187+
)
1188+
);
1189+
$this->assertIsInt( $c );
1190+
1191+
update_option( 'wp_notes_notify', 1 );
1192+
1193+
$filter = new MockAction();
1194+
add_filter( 'notify_post_author', array( $filter, 'filter' ) );
1195+
1196+
$sent = wp_new_comment_notify_postauthor( $c );
1197+
1198+
$this->assertTrue( $sent, 'The notification comment should have been sent.' );
1199+
$args = array_first( $filter->get_args() );
1200+
$this->assertTrue( (bool) ( $args[0] ?? null ), 'The filter should receive a truthy default for an unapproved note.' );
1201+
}
1202+
1203+
/**
1204+
* @ticket 64217
1205+
*
1206+
* @covers ::wp_new_comment_notify_postauthor
1207+
*/
1208+
public function test_wp_new_comment_notify_postauthor_filter_should_receive_option_value_for_approved_comment(): void {
1209+
$c = self::factory()->comment->create(
1210+
array(
1211+
'comment_post_ID' => self::$post_id,
1212+
)
1213+
);
1214+
$this->assertIsInt( $c );
1215+
1216+
update_option( 'comments_notify', 0 );
1217+
1218+
$filter = new MockAction();
1219+
add_filter( 'notify_post_author', array( $filter, 'filter' ) );
1220+
1221+
$sent = wp_new_comment_notify_postauthor( $c );
1222+
1223+
$args = array_first( $filter->get_args() );
1224+
$this->assertFalse( (bool) ( $args[0] ?? null ), 'The filter should receive the comments_notify option value as the default for an approved comment.' );
1225+
$this->assertFalse( $sent, 'No notification should be sent for an approved comment when comments_notify is disabled.' );
1226+
}
1227+
11121228
/**
11131229
* @ticket 43805
11141230
*

0 commit comments

Comments
 (0)