From bcd149cfc0001dcfcfc0ca3d4ce29910aba28ddc Mon Sep 17 00:00:00 2001 From: David Herrera Date: Thu, 13 Nov 2025 00:03:43 -0500 Subject: [PATCH 1/7] REST API: Make sure the `class_list` property is a list --- .../class-wp-rest-posts-controller.php | 2 +- .../tests/rest-api/rest-posts-controller.php | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 14afb8c2eeddf..bffbb15da51e1 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -2101,7 +2101,7 @@ public function prepare_item_for_response( $item, $request ) { } if ( rest_is_field_included( 'class_list', $fields ) ) { - $data['class_list'] = get_post_class( array(), $post->ID ); + $data['class_list'] = array_values( get_post_class( array(), $post->ID ) ); } } diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index bd0b9a3af48b3..1a35df2d4b65f 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -2775,6 +2775,35 @@ public function test_prepare_item_override_excerpt_length() { ); } + /** + * Test that the `class_list` property is a list. + * + * @ticket 64247 + * + * @covers WP_REST_Posts_Controller::prepare_item_for_response + */ + public function test_class_list_is_list() { + $post_id = self::factory()->post->create(); + + // Filter 'post_class' to add a duplicate, which should be removed by `array_unique()`, causing a non-indexed array. + add_filter( + 'post_class', + function ( $classes ) { + return array_merge( + array( 'duplicate-class', 'duplicate-class' ), + $classes, + ); + } + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id ); + $response = rest_do_request( $request ); + $data = $response->get_data(); + + $this->assertTrue( isset( $data['class_list'] ) ); + $this->assertTrue( array_is_list( $data['class_list'] ) ); + } + public function test_create_item() { wp_set_current_user( self::$editor_id ); From ed57e517c67bfe7a13f5b9bd6e9c1e4d30aea059 Mon Sep 17 00:00:00 2001 From: David Herrera Date: Thu, 13 Nov 2025 00:26:00 -0500 Subject: [PATCH 2/7] Spacin' --- tests/phpunit/tests/rest-api/rest-posts-controller.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index 1a35df2d4b65f..73f84e6e7fac5 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -2796,9 +2796,9 @@ function ( $classes ) { } ); - $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id ); $response = rest_do_request( $request ); - $data = $response->get_data(); + $data = $response->get_data(); $this->assertTrue( isset( $data['class_list'] ) ); $this->assertTrue( array_is_list( $data['class_list'] ) ); From 810f75961efdaef1a596d1f63d6093ce707bbc2e Mon Sep 17 00:00:00 2001 From: David Herrera Date: Thu, 13 Nov 2025 00:46:34 -0500 Subject: [PATCH 3/7] Nix trailing comma --- tests/phpunit/tests/rest-api/rest-posts-controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index 73f84e6e7fac5..d7ede09e663cf 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -2791,7 +2791,7 @@ public function test_class_list_is_list() { function ( $classes ) { return array_merge( array( 'duplicate-class', 'duplicate-class' ), - $classes, + $classes ); } ); From 21674417171058f551d45e559a37ca2500eebbc1 Mon Sep 17 00:00:00 2001 From: David Herrera Date: Sat, 15 Nov 2025 16:31:10 -0500 Subject: [PATCH 4/7] Normalize in `get_post_class()` instead --- src/wp-includes/post-template.php | 5 ++++- .../rest-api/endpoints/class-wp-rest-posts-controller.php | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/post-template.php b/src/wp-includes/post-template.php index edcc1e0f035ec..3d82ba81b641b 100644 --- a/src/wp-includes/post-template.php +++ b/src/wp-includes/post-template.php @@ -606,7 +606,10 @@ function get_post_class( $css_class = '', $post = null ) { */ $classes = apply_filters( 'post_class', $classes, $css_class, $post->ID ); - return array_unique( $classes ); + $classes = array_unique( $classes ); + $classes = array_values( $classes ); + + return $classes; } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index bffbb15da51e1..14afb8c2eeddf 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -2101,7 +2101,7 @@ public function prepare_item_for_response( $item, $request ) { } if ( rest_is_field_included( 'class_list', $fields ) ) { - $data['class_list'] = array_values( get_post_class( array(), $post->ID ) ); + $data['class_list'] = get_post_class( array(), $post->ID ); } } From f329ef595c523544448b86397461b1614c38b96b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 18 Nov 2025 21:34:45 -0800 Subject: [PATCH 5/7] Refine assertions for WP_Test_REST_Posts_Controller::test_class_list_is_list() --- tests/phpunit/tests/rest-api/rest-posts-controller.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index d7ede09e663cf..bd9b9ece44160 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -2800,8 +2800,9 @@ function ( $classes ) { $response = rest_do_request( $request ); $data = $response->get_data(); - $this->assertTrue( isset( $data['class_list'] ) ); - $this->assertTrue( array_is_list( $data['class_list'] ) ); + $this->assertArrayHasKey( 'class_list', $data ); + $this->assertContains( 'duplicate-class', $data['class_list'] ); + $this->assertTrue( array_is_list( $data['class_list'] ), 'Expected class_list to be a list.' ); } public function test_create_item() { From 193b5da6081f4d200f6e2cd52f1bcc824510f7ef Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 18 Nov 2025 21:35:31 -0800 Subject: [PATCH 6/7] Add dedicated test for get_post_class() --- tests/phpunit/tests/post/getPostClass.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/phpunit/tests/post/getPostClass.php b/tests/phpunit/tests/post/getPostClass.php index 64f60a2636c2a..be7045bc0efdf 100644 --- a/tests/phpunit/tests/post/getPostClass.php +++ b/tests/phpunit/tests/post/getPostClass.php @@ -135,4 +135,27 @@ public function test_taxonomy_classes_hit_cache() { $this->assertSame( $num_queries, get_num_queries() ); } + + /** + * @ticket 64247 + */ + public function test_class_list_is_list() { + + // Filter 'post_class' to add a duplicate, which should be removed by `array_unique()`, causing a non-indexed array. + add_filter( + 'post_class', + function ( $classes ) { + return array_merge( + array( 'duplicate-class', 'duplicate-class' ), + $classes + ); + } + ); + + $class_list = get_post_class( 'original', $this->post_id ); + + $this->assertTrue( array_is_list( $class_list ), 'Expected get_post_class() to return list.' ); + $this->assertContains( 'duplicate-class', $class_list ); + $this->assertContains( 'original', $class_list ); + } } From 06911fd48351d847694509184b60ac9fb82d662e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 18 Nov 2025 21:44:01 -0800 Subject: [PATCH 7/7] Tidy tests --- tests/phpunit/tests/post/getPostClass.php | 5 ++--- tests/phpunit/tests/rest-api/rest-posts-controller.php | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/phpunit/tests/post/getPostClass.php b/tests/phpunit/tests/post/getPostClass.php index be7045bc0efdf..1ec18ade78dfd 100644 --- a/tests/phpunit/tests/post/getPostClass.php +++ b/tests/phpunit/tests/post/getPostClass.php @@ -139,9 +139,9 @@ public function test_taxonomy_classes_hit_cache() { /** * @ticket 64247 */ - public function test_class_list_is_list() { + public function test_list_return_value_when_duplicate_classes() { - // Filter 'post_class' to add a duplicate, which should be removed by `array_unique()`, causing a non-indexed array. + // Filter 'post_class' to add a duplicate which should be removed by `array_unique()`. add_filter( 'post_class', function ( $classes ) { @@ -153,7 +153,6 @@ function ( $classes ) { ); $class_list = get_post_class( 'original', $this->post_id ); - $this->assertTrue( array_is_list( $class_list ), 'Expected get_post_class() to return list.' ); $this->assertContains( 'duplicate-class', $class_list ); $this->assertContains( 'original', $class_list ); diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index bd9b9ece44160..d701d12f9dd68 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -2785,7 +2785,7 @@ public function test_prepare_item_override_excerpt_length() { public function test_class_list_is_list() { $post_id = self::factory()->post->create(); - // Filter 'post_class' to add a duplicate, which should be removed by `array_unique()`, causing a non-indexed array. + // Filter 'post_class' to add a duplicate which should be removed by `array_unique()`. add_filter( 'post_class', function ( $classes ) {