From 215d932d46e489042f1c3568c17fa93a36b075be Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Mon, 19 Oct 2026 23:27:51 +0200 Subject: [PATCH 1/2] keep reader replies out of the comments feed --- .github/changelog/fix-reader-comments-feed | 4 +++ includes/class-comment.php | 29 +++++++++++++++- .../tests/includes/class-test-comment.php | 34 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 .github/changelog/fix-reader-comments-feed diff --git a/.github/changelog/fix-reader-comments-feed b/.github/changelog/fix-reader-comments-feed new file mode 100644 index 0000000000..a35ab08731 --- /dev/null +++ b/.github/changelog/fix-reader-comments-feed @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Replies to posts from accounts you follow no longer show up in your comments feed and comment widgets. diff --git a/includes/class-comment.php b/includes/class-comment.php index c3942632bf..1c89ada578 100644 --- a/includes/class-comment.php +++ b/includes/class-comment.php @@ -29,6 +29,7 @@ public static function init() { \add_filter( 'comment_reply_link', array( self::class, 'comment_reply_link' ), 10, 3 ); \add_filter( 'comment_class', array( self::class, 'comment_class' ), 10, 3 ); \add_filter( 'comment_feed_where', array( static::class, 'comment_feed_where' ) ); + \add_filter( 'widget_comments_args', array( static::class, 'widget_comments_args' ) ); \add_filter( 'get_comment_link', array( self::class, 'remote_comment_link' ), 11, 2 ); \add_action( 'pre_get_comments', array( static::class, 'comment_query' ) ); \add_filter( 'get_page_of_comment_query_args', array( static::class, 'get_page_of_comment_query_args' ) ); @@ -435,7 +436,8 @@ public static function comment_class( $classes, $css_class, $comment_id ) { /** * Makes the comment feed filterable by comment type. * - * Also excludes ActivityPub comment types from the feed when no type is specified. + * Also excludes ActivityPub comment types from the feed when no type is specified, + * and replies to remote posts in any case. * * @param string $where The `WHERE` clause for the comment feed query. * @@ -444,6 +446,14 @@ public static function comment_class( $classes, $css_class, $comment_id ) { public static function comment_feed_where( $where ) { global $wpdb; + // Replies to remote posts belong to the reader, not to the site's comments. + $hide_for = self::hide_for(); + if ( $hide_for ) { + $placeholders = \implode( ', ', \array_fill( 0, \count( $hide_for ), '%s' ) ); + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQL.NotPrepared + $where .= $wpdb->prepare( \sprintf( " AND {$wpdb->comments}.comment_post_ID NOT IN ( SELECT ID FROM {$wpdb->posts} WHERE post_type IN (%s) )", $placeholders ), ...$hide_for ); + } + $comment_type = \get_query_var( 'type' ); if ( 'all' === $comment_type ) { @@ -463,6 +473,23 @@ public static function comment_feed_where( $where ) { return $where; } + /** + * Keeps replies to remote posts out of the Recent Comments widget and the Latest Comments block. + * + * @since unreleased + * + * @param array $args The comment query arguments. + * + * @return array The filtered arguments. + */ + public static function widget_comments_args( $args ) { + if ( empty( $args['post_type'] ) ) { + $args['post_type'] = self::get_allowed_comment_post_types(); + } + + return $args; + } + /** * Gets the public comment id via the WordPress comments meta. * diff --git a/tests/phpunit/tests/includes/class-test-comment.php b/tests/phpunit/tests/includes/class-test-comment.php index c695265424..498ad012d8 100644 --- a/tests/phpunit/tests/includes/class-test-comment.php +++ b/tests/phpunit/tests/includes/class-test-comment.php @@ -872,6 +872,40 @@ public function test_comment_feed_where() { \set_query_var( 'type', null ); } + /** + * Replies to remote posts stay out of the comments feed and the comment widgets. + * + * @covers ::comment_feed_where + * @covers ::widget_comments_args + */ + public function test_remote_post_replies_stay_out_of_public_lists() { + $comment_ids = array(); + foreach ( array( 'post', Remote_Posts::POST_TYPE ) as $post_type ) { + $comment_ids[ $post_type ] = self::factory()->comment->create( + array( + 'comment_approved' => '1', + 'comment_post_ID' => self::factory()->post->create( array( 'post_type' => $post_type ) ), + ) + ); + } + $expected = array( (string) $comment_ids['post'] ); + + foreach ( array( null, 'all' ) as $type ) { + \set_query_var( 'type', $type ); + $query = new \WP_Query( + array( + 'feed' => 'comments-rss2', + 'withcomments' => true, + ) + ); + $this->assertSame( $expected, \wp_list_pluck( $query->comments, 'comment_ID' ) ); + } + \set_query_var( 'type', null ); + + $args = \apply_filters( 'widget_comments_args', array( 'post_status' => 'publish' ), array() ); + $this->assertSame( $expected, \wp_list_pluck( \get_comments( $args ), 'comment_ID' ) ); + } + /** * Test that comments on ap_post are excluded from admin comment queries. * From e0f54f859c254090aae93e22fbdec119b7e001ce Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Mon, 19 Oct 2026 23:36:53 +0200 Subject: [PATCH 2/2] only leave out the hidden post types in the widgets --- includes/class-comment.php | 7 +++++-- tests/phpunit/tests/includes/class-test-comment.php | 13 +++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/includes/class-comment.php b/includes/class-comment.php index 1c89ada578..c87e674d28 100644 --- a/includes/class-comment.php +++ b/includes/class-comment.php @@ -483,8 +483,11 @@ public static function comment_feed_where( $where ) { * @return array The filtered arguments. */ public static function widget_comments_args( $args ) { - if ( empty( $args['post_type'] ) ) { - $args['post_type'] = self::get_allowed_comment_post_types(); + $hide_for = self::hide_for(); + + // The comment query has no `post_type__not_in`, so list every other post type. + if ( $hide_for && empty( $args['post_type'] ) ) { + $args['post_type'] = \array_values( \array_diff( \get_post_types(), $hide_for ) ); } return $args; diff --git a/tests/phpunit/tests/includes/class-test-comment.php b/tests/phpunit/tests/includes/class-test-comment.php index 498ad012d8..95f698c7b6 100644 --- a/tests/phpunit/tests/includes/class-test-comment.php +++ b/tests/phpunit/tests/includes/class-test-comment.php @@ -879,8 +879,11 @@ public function test_comment_feed_where() { * @covers ::widget_comments_args */ public function test_remote_post_replies_stay_out_of_public_lists() { + // Comments on post types without comment support stay in the lists. + \register_post_type( 'no_comment_support', array( 'supports' => array( 'title' ) ) ); + $comment_ids = array(); - foreach ( array( 'post', Remote_Posts::POST_TYPE ) as $post_type ) { + foreach ( array( 'post', 'no_comment_support', Remote_Posts::POST_TYPE ) as $post_type ) { $comment_ids[ $post_type ] = self::factory()->comment->create( array( 'comment_approved' => '1', @@ -888,7 +891,7 @@ public function test_remote_post_replies_stay_out_of_public_lists() { ) ); } - $expected = array( (string) $comment_ids['post'] ); + $expected = array( (string) $comment_ids['post'], (string) $comment_ids['no_comment_support'] ); foreach ( array( null, 'all' ) as $type ) { \set_query_var( 'type', $type ); @@ -898,12 +901,14 @@ public function test_remote_post_replies_stay_out_of_public_lists() { 'withcomments' => true, ) ); - $this->assertSame( $expected, \wp_list_pluck( $query->comments, 'comment_ID' ) ); + $this->assertEqualSets( $expected, \wp_list_pluck( $query->comments, 'comment_ID' ) ); } \set_query_var( 'type', null ); $args = \apply_filters( 'widget_comments_args', array( 'post_status' => 'publish' ), array() ); - $this->assertSame( $expected, \wp_list_pluck( \get_comments( $args ), 'comment_ID' ) ); + $this->assertEqualSets( $expected, \wp_list_pluck( \get_comments( $args ), 'comment_ID' ) ); + + \unregister_post_type( 'no_comment_support' ); } /**