From 19bd2d4e1d4d00bf951763a5a28216042f0d65f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Ka=CC=88gy?= Date: Wed, 14 Oct 2026 12:11:02 +0200 Subject: [PATCH 1/4] Editor: Add author support to the wp_block post type. This exposes each pattern's author through the REST API, so the editor can tell the current user's patterns apart from the rest of the site's patterns. --- src/wp-includes/post.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 8d9b58c037501..3c41d5a108fab 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -353,6 +353,7 @@ function create_initial_post_types() { 'editor', 'revisions', 'custom-fields', + 'author', ), ) ); From 76cb9b21cd0155e69f4932a6b11655093122ace3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Ka=CC=88gy?= Date: Thu, 15 Oct 2026 12:15:27 +0200 Subject: [PATCH 2/4] Editor: Rename the "My patterns" view to "Site patterns". The view lists every user-created pattern, not only the current user's. Co-Authored-By: Claude Opus 5.5 --- src/wp-includes/view-config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/view-config.php b/src/wp-includes/view-config.php index 8765a5d095008..e87558331bc49 100644 --- a/src/wp-includes/view-config.php +++ b/src/wp-includes/view-config.php @@ -369,7 +369,7 @@ function _wp_get_entity_view_config_posttype_wp_block( $data ) { 'slug' => 'all-patterns', ), array( - 'title' => __( 'My patterns' ), + 'title' => __( 'Site patterns' ), 'slug' => 'my-patterns', ), ); From ffe690b3b7fc8810533eef1b1a33ad14e8743db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Ka=CC=88gy?= Date: Thu, 15 Oct 2026 13:02:32 +0200 Subject: [PATCH 3/4] Tests: Cover author support for the wp_block post type. Covers the author in the blocks controller's response, filtering patterns by author, changing a pattern's author, and what happens to a user's patterns when the user is deleted. Regenerates the REST API client fixtures for the new author arguments. Co-Authored-By: Claude Opus 5.5 --- .../tests/rest-api/rest-blocks-controller.php | 100 ++++++++++++++++++ tests/phpunit/tests/user/wpDeleteUser.php | 40 +++++++ tests/qunit/fixtures/wp-api-generated.js | 33 ++++++ 3 files changed, 173 insertions(+) diff --git a/tests/phpunit/tests/rest-api/rest-blocks-controller.php b/tests/phpunit/tests/rest-api/rest-blocks-controller.php index 43a181683c788..aad645344d6d2 100644 --- a/tests/phpunit/tests/rest-api/rest-blocks-controller.php +++ b/tests/phpunit/tests/rest-api/rest-blocks-controller.php @@ -255,4 +255,104 @@ public function test_wp_patterns_sync_status_post_meta() { $this->assertArrayHasKey( 'wp_pattern_sync_status', $data ); $this->assertArrayNotHasKey( 'wp_pattern_sync_status', $data['meta'] ); } + + /** + * Check that the response includes the pattern's author. + * + * @ticket 66307 + */ + public function test_author_in_response() { + wp_set_current_user( self::$user_ids['editor'] ); + + $post_id = self::factory()->post->create( + array( + 'post_type' => 'wp_block', + 'post_author' => self::$user_ids['author'], + ) + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . $post_id ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertSame( self::$user_ids['author'], $data['author'] ); + } + + /** + * Check that patterns can be filtered by author. + * + * @ticket 66307 + */ + public function test_filter_by_author() { + wp_set_current_user( self::$user_ids['editor'] ); + + $editor_post_id = self::factory()->post->create( + array( + 'post_type' => 'wp_block', + 'post_author' => self::$user_ids['editor'], + ) + ); + $author_post_id = self::factory()->post->create( + array( + 'post_type' => 'wp_block', + 'post_author' => self::$user_ids['author'], + ) + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/blocks' ); + $request->set_param( 'author', self::$user_ids['author'] ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( array( $author_post_id ), wp_list_pluck( $response->get_data(), 'id' ), 'The author filter should only return the author\'s patterns.' ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/blocks' ); + $request->set_param( 'author_exclude', self::$user_ids['author'] ); + $response = rest_get_server()->dispatch( $request ); + $ids = wp_list_pluck( $response->get_data(), 'id' ); + + $this->assertContains( $editor_post_id, $ids, 'The author_exclude filter should return other users\' patterns.' ); + $this->assertNotContains( $author_post_id, $ids, 'The author_exclude filter should not return the author\'s patterns.' ); + } + + /** + * Check that only users who can edit others' patterns can change a pattern's author. + * + * @ticket 66307 + * + * @dataProvider data_change_author + * + * @param string $role User role to test. + * @param int $expected_status Expected HTTP response status. + */ + public function test_change_author( $role, $expected_status ) { + $user_id = self::$user_ids[ $role ]; + wp_set_current_user( $user_id ); + + $post_id = self::factory()->post->create( + array( + 'post_type' => 'wp_block', + 'post_author' => $user_id, + ) + ); + $new_author = 'editor' === $role ? self::$user_ids['author'] : self::$user_ids['editor']; + + $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . $post_id ); + $request->set_body_params( array( 'author' => $new_author ) ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( $expected_status, $response->get_status(), 'The response status should match.' ); + $this->assertSame( 200 === $expected_status ? $new_author : $user_id, (int) get_post( $post_id )->post_author, 'The pattern\'s author should match.' ); + } + + /** + * Test cases for test_change_author(). + * + * @return array[] + */ + public function data_change_author() { + return array( + 'editor' => array( 'editor', 200 ), + 'author' => array( 'author', 403 ), + ); + } } diff --git a/tests/phpunit/tests/user/wpDeleteUser.php b/tests/phpunit/tests/user/wpDeleteUser.php index b2eec9be1fcb9..3e10c136a7f8b 100644 --- a/tests/phpunit/tests/user/wpDeleteUser.php +++ b/tests/phpunit/tests/user/wpDeleteUser.php @@ -124,6 +124,46 @@ public function test_wp_delete_user_reassignment_clears_post_caches() { $this->assertSame( (string) $reassign, $post->post_author ); } + /** + * Patterns support authors, so they're deleted with their author. Only posts + * and pages are moved to the trash, so patterns are deleted permanently. + * + * @ticket 66307 + */ + public function test_delete_user_deletes_patterns() { + $user_id = self::factory()->user->create( array( 'role' => 'author' ) ); + $pattern_id = self::factory()->post->create( + array( + 'post_type' => 'wp_block', + 'post_author' => $user_id, + ) + ); + + wp_delete_user( $user_id ); + + $this->assertNull( get_post( $pattern_id ) ); + } + + /** + * @ticket 66307 + */ + public function test_delete_user_reassigns_patterns() { + $user_id = self::factory()->user->create( array( 'role' => 'author' ) ); + $reassign = self::factory()->user->create( array( 'role' => 'author' ) ); + $pattern_id = self::factory()->post->create( + array( + 'post_type' => 'wp_block', + 'post_author' => $user_id, + ) + ); + + wp_delete_user( $user_id, $reassign ); + + $pattern = get_post( $pattern_id ); + $this->assertSame( 'publish', $pattern->post_status, 'The pattern should not be deleted.' ); + $this->assertSame( (string) $reassign, $pattern->post_author, 'The pattern should be reassigned.' ); + } + /** * @group ms-excluded */ diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index dba0cd776b59f..065333e1fdb0f 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -4669,6 +4669,24 @@ mockedApiResponse.Schema = { "format": "date-time", "required": false }, + "author": { + "description": "Limit result set to posts assigned to specific authors.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "author_exclude": { + "description": "Ensure result set excludes posts assigned to specific authors.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, "before": { "description": "Limit response to posts published before a given ISO8601 compliant date.", "type": "string", @@ -4970,6 +4988,11 @@ mockedApiResponse.Schema = { }, "required": false }, + "author": { + "description": "The ID for the author of the post.", + "type": "integer", + "required": false + }, "excerpt": { "description": "The excerpt for the post.", "type": "object", @@ -5179,6 +5202,11 @@ mockedApiResponse.Schema = { }, "required": false }, + "author": { + "description": "The ID for the author of the post.", + "type": "integer", + "required": false + }, "excerpt": { "description": "The excerpt for the post.", "type": "object", @@ -5543,6 +5571,11 @@ mockedApiResponse.Schema = { }, "required": false }, + "author": { + "description": "The ID for the author of the post.", + "type": "integer", + "required": false + }, "excerpt": { "description": "The excerpt for the post.", "type": "object", From 2a93ee3720dbb164c5738a942bc50efced37ca30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Ka=CC=88gy?= Date: Thu, 15 Oct 2026 13:13:16 +0200 Subject: [PATCH 4/4] Editor: Keep patterns when their author is deleted. Patterns may be used across the site, so deleting a user shouldn't delete their patterns, now that the post type supports authors. Co-Authored-By: Claude Opus 5.5 --- src/wp-includes/post.php | 2 ++ tests/phpunit/tests/user/wpDeleteUser.php | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 3c41d5a108fab..088b692b6081b 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -355,6 +355,8 @@ function create_initial_post_types() { 'custom-fields', 'author', ), + // Keep patterns when their author is deleted, as they may be used across the site. + 'delete_with_user' => false, ) ); diff --git a/tests/phpunit/tests/user/wpDeleteUser.php b/tests/phpunit/tests/user/wpDeleteUser.php index 3e10c136a7f8b..a74705d6dd104 100644 --- a/tests/phpunit/tests/user/wpDeleteUser.php +++ b/tests/phpunit/tests/user/wpDeleteUser.php @@ -125,12 +125,11 @@ public function test_wp_delete_user_reassignment_clears_post_caches() { } /** - * Patterns support authors, so they're deleted with their author. Only posts - * and pages are moved to the trash, so patterns are deleted permanently. + * Patterns may be used across the site, so they're kept when their author is deleted. * * @ticket 66307 */ - public function test_delete_user_deletes_patterns() { + public function test_delete_user_keeps_patterns() { $user_id = self::factory()->user->create( array( 'role' => 'author' ) ); $pattern_id = self::factory()->post->create( array( @@ -141,7 +140,7 @@ public function test_delete_user_deletes_patterns() { wp_delete_user( $user_id ); - $this->assertNull( get_post( $pattern_id ) ); + $this->assertSame( 'publish', get_post_status( $pattern_id ) ); } /**