diff --git a/.github/changelog/fix-featured-password b/.github/changelog/fix-featured-password new file mode 100644 index 0000000000..76c2e91129 --- /dev/null +++ b/.github/changelog/fix-featured-password @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Password-protected sticky posts are no longer listed in your featured posts on the Fediverse. diff --git a/includes/rest/class-collections-controller.php b/includes/rest/class-collections-controller.php index 9f0bf8a853..84a8a38c9c 100644 --- a/includes/rest/class-collections-controller.php +++ b/includes/rest/class-collections-controller.php @@ -168,6 +168,7 @@ public function get_featured( $request, $user_id ) { $args = array( 'post__in' => $sticky_posts, 'ignore_sticky_posts' => 1, + 'has_password' => false, 'orderby' => 'date', 'order' => 'DESC', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query @@ -183,7 +184,8 @@ public function get_featured( $request, $user_id ) { $args['author'] = $user_id; } - $posts = \get_posts( $args ); + // The query leaves out password-protected posts; the rest of what keeps a post private (post type support, filters) is checked per post. + $posts = \array_values( \array_filter( \get_posts( $args ), 'Activitypub\is_post_publicly_queryable' ) ); } } @@ -191,7 +193,7 @@ public function get_featured( $request, $user_id ) { '@context' => Base_Object::JSON_LD_CONTEXT, 'id' => get_rest_url_by_path( \sprintf( 'actors/%d/collections/featured', $user_id ) ), 'type' => 'OrderedCollection', - 'totalItems' => \is_countable( $posts ) ? \count( $posts ) : 0, + 'totalItems' => \count( $posts ), 'orderedItems' => array(), ); diff --git a/tests/phpunit/tests/includes/rest/class-test-collections-controller.php b/tests/phpunit/tests/includes/rest/class-test-collections-controller.php index 39bd832116..92ba39d3cb 100644 --- a/tests/phpunit/tests/includes/rest/class-test-collections-controller.php +++ b/tests/phpunit/tests/includes/rest/class-test-collections-controller.php @@ -123,6 +123,31 @@ public function test_get_featured() { $this->assertEquals( 1, $response['totalItems'] ); } + /** + * A sticky post that is not publicly queryable, here a password-protected one, is not featured. + * + * @covers ::get_featured + */ + public function test_get_featured_skips_password_protected_posts() { + $protected_id = self::factory()->post->create( + array( + 'post_author' => self::$user_id, + 'post_password' => 'secret', + ) + ); + stick_post( self::$post_id ); + stick_post( $protected_id ); + + $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/' . self::$user_id . '/collections/featured' ); + $request->set_param( 'page', 1 ); + $request->set_param( 'per_page', 10 ); + $response = rest_get_server()->dispatch( $request )->get_data(); + + $this->assertSame( 1, $response['totalItems'], 'The password-protected post must not be counted.' ); + $this->assertCount( 1, $response['orderedItems'] ); + $this->assertSame( \get_permalink( self::$post_id ), $response['orderedItems'][0]['url'] ?? '' ); + } + /** * Test schema. *