From 42b2ad0002e6ecb30324be5c9aeea6c6a80084bc Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 20 Nov 2024 13:02:39 +0100 Subject: [PATCH 1/8] Navigation Block: Deprecate obsolete Block Hooks helper functions --- src/wp-includes/deprecated.php | 112 +++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index a47e7015b1348..13b43a5879818 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6422,3 +6422,115 @@ function wp_create_block_style_variation_instance_name( $block, $variation ) { function current_user_can_for_blog( $blog_id, $capability, ...$args ) { return current_user_can_for_site( $blog_id, $capability, ...$args ); } + +/** + * Insert ignoredHookedBlocks meta into the Navigation block and its inner blocks. + * + * Given a Navigation block's inner blocks and its corresponding `wp_navigation` post object, + * this function inserts ignoredHookedBlocks meta into it, and returns the serialized inner blocks in a + * mock Navigation block wrapper. + * + * @since 6.5.0 + * + * @param array $inner_blocks Parsed inner blocks of a Navigation block. + * @param WP_Post $post `wp_navigation` post object corresponding to the block. + * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any. + */ +function block_core_navigation_set_ignored_hooked_blocks_metadata( $inner_blocks, $post ) { + $mock_navigation_block = block_core_navigation_mock_parsed_block( $inner_blocks, $post ); + $hooked_blocks = get_hooked_blocks(); + $before_block_visitor = null; + $after_block_visitor = null; + + if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { + $before_block_visitor = make_before_block_visitor( $hooked_blocks, $post, 'set_ignored_hooked_blocks_metadata' ); + $after_block_visitor = make_after_block_visitor( $hooked_blocks, $post, 'set_ignored_hooked_blocks_metadata' ); + } + + return traverse_and_serialize_block( $mock_navigation_block, $before_block_visitor, $after_block_visitor ); +} + +/** + * Updates the post meta with the list of ignored hooked blocks when the navigation is created or updated via the REST API. + * + * @access private + * @since 6.5.0 + * + * @param stdClass $post Post object. + * @return stdClass The updated post object. + */ +function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { + /* + * In this scenario the user has likely tried to create a navigation via the REST API. + * In which case we won't have a post ID to work with and store meta against. + */ + if ( empty( $post->ID ) ) { + return $post; + } + + /** + * Skip meta generation when consumers intentionally update specific Navigation fields + * and omit the content update. + */ + if ( ! isset( $post->post_content ) ) { + return $post; + } + + /* + * We run the Block Hooks mechanism to inject the `metadata.ignoredHookedBlocks` attribute into + * all anchor blocks. For the root level, we create a mock Navigation and extract them from there. + */ + $blocks = parse_blocks( $post->post_content ); + + /* + * Block Hooks logic requires a `WP_Post` object (rather than the `stdClass` with the updates that + * we're getting from the `rest_pre_insert_wp_navigation` filter) as its second argument (to be + * used as context for hooked blocks insertion). + * We thus have to look it up from the DB,based on `$post->ID`. + */ + $markup = block_core_navigation_set_ignored_hooked_blocks_metadata( $blocks, get_post( $post->ID ) ); + + $root_nav_block = parse_blocks( $markup )[0]; + $ignored_hooked_blocks = isset( $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] ) + ? $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] + : array(); + + if ( ! empty( $ignored_hooked_blocks ) ) { + $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); + if ( ! empty( $existing_ignored_hooked_blocks ) ) { + $existing_ignored_hooked_blocks = json_decode( $existing_ignored_hooked_blocks, true ); + $ignored_hooked_blocks = array_unique( array_merge( $ignored_hooked_blocks, $existing_ignored_hooked_blocks ) ); + } + update_post_meta( $post->ID, '_wp_ignored_hooked_blocks', json_encode( $ignored_hooked_blocks ) ); + } + + $post->post_content = block_core_navigation_remove_serialized_parent_block( $markup ); + return $post; +} + +/** + * Hooks into the REST API response for the core/navigation block and adds the first and last inner blocks. + * + * @since 6.5.0 + * + * @param WP_REST_Response $response The response object. + * @param WP_Post $post Post object. + * @return WP_REST_Response The response object. + */ +function block_core_navigation_insert_hooked_blocks_into_rest_response( $response, $post ) { + if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) { + return $response; + } + $parsed_blocks = parse_blocks( $response->data['content']['raw'] ); + $content = block_core_navigation_insert_hooked_blocks( $parsed_blocks, $post ); + + // Remove mock Navigation block wrapper. + $content = block_core_navigation_remove_serialized_parent_block( $content ); + + $response->data['content']['raw'] = $content; + + /** This filter is documented in wp-includes/post-template.php */ + $response->data['content']['rendered'] = apply_filters( 'the_content', $content ); + + return $response; +} From 11c52808505622a801ecdc7ee25af03847cb27cc Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 20 Nov 2024 13:08:11 +0100 Subject: [PATCH 2/8] Add deprecated PHPDoc and _deprecated_function_ --- src/wp-includes/deprecated.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 13b43a5879818..ab3aabddfb207 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6455,11 +6455,14 @@ function block_core_navigation_set_ignored_hooked_blocks_metadata( $inner_blocks * * @access private * @since 6.5.0 + * @deprecated 6.8.0 Use update_ignored_hooked_blocks_postmeta() instead. * * @param stdClass $post Post object. * @return stdClass The updated post object. */ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { + _deprecated_function( __FUNCTION__, '6.8.0', 'update_ignored_hooked_blocks_postmeta' ); + /* * In this scenario the user has likely tried to create a navigation via the REST API. * In which case we won't have a post ID to work with and store meta against. @@ -6512,12 +6515,14 @@ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { * Hooks into the REST API response for the core/navigation block and adds the first and last inner blocks. * * @since 6.5.0 + * @deprecated 6.8.0 Use insert_hooked_blocks_into_rest_response() instead. * * @param WP_REST_Response $response The response object. * @param WP_Post $post Post object. * @return WP_REST_Response The response object. */ function block_core_navigation_insert_hooked_blocks_into_rest_response( $response, $post ) { + _deprecated_function( __FUNCTION__, '6.8.0', 'insert_hooked_blocks_into_rest_response' ); if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) { return $response; } From f1e49c05efb0b01dbf40299644cafdb1ee81ffc7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 20 Nov 2024 15:04:37 +0100 Subject: [PATCH 3/8] Invoke new functions --- src/wp-includes/deprecated.php | 64 ++-------------------------------- 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index ab3aabddfb207..aeb02e8ebab5a 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6462,53 +6462,7 @@ function block_core_navigation_set_ignored_hooked_blocks_metadata( $inner_blocks */ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { _deprecated_function( __FUNCTION__, '6.8.0', 'update_ignored_hooked_blocks_postmeta' ); - - /* - * In this scenario the user has likely tried to create a navigation via the REST API. - * In which case we won't have a post ID to work with and store meta against. - */ - if ( empty( $post->ID ) ) { - return $post; - } - - /** - * Skip meta generation when consumers intentionally update specific Navigation fields - * and omit the content update. - */ - if ( ! isset( $post->post_content ) ) { - return $post; - } - - /* - * We run the Block Hooks mechanism to inject the `metadata.ignoredHookedBlocks` attribute into - * all anchor blocks. For the root level, we create a mock Navigation and extract them from there. - */ - $blocks = parse_blocks( $post->post_content ); - - /* - * Block Hooks logic requires a `WP_Post` object (rather than the `stdClass` with the updates that - * we're getting from the `rest_pre_insert_wp_navigation` filter) as its second argument (to be - * used as context for hooked blocks insertion). - * We thus have to look it up from the DB,based on `$post->ID`. - */ - $markup = block_core_navigation_set_ignored_hooked_blocks_metadata( $blocks, get_post( $post->ID ) ); - - $root_nav_block = parse_blocks( $markup )[0]; - $ignored_hooked_blocks = isset( $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] ) - ? $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] - : array(); - - if ( ! empty( $ignored_hooked_blocks ) ) { - $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); - if ( ! empty( $existing_ignored_hooked_blocks ) ) { - $existing_ignored_hooked_blocks = json_decode( $existing_ignored_hooked_blocks, true ); - $ignored_hooked_blocks = array_unique( array_merge( $ignored_hooked_blocks, $existing_ignored_hooked_blocks ) ); - } - update_post_meta( $post->ID, '_wp_ignored_hooked_blocks', json_encode( $ignored_hooked_blocks ) ); - } - - $post->post_content = block_core_navigation_remove_serialized_parent_block( $markup ); - return $post; + return update_ignored_hooked_blocks_postmeta( $post ); } /** @@ -6523,19 +6477,5 @@ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { */ function block_core_navigation_insert_hooked_blocks_into_rest_response( $response, $post ) { _deprecated_function( __FUNCTION__, '6.8.0', 'insert_hooked_blocks_into_rest_response' ); - if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) { - return $response; - } - $parsed_blocks = parse_blocks( $response->data['content']['raw'] ); - $content = block_core_navigation_insert_hooked_blocks( $parsed_blocks, $post ); - - // Remove mock Navigation block wrapper. - $content = block_core_navigation_remove_serialized_parent_block( $content ); - - $response->data['content']['raw'] = $content; - - /** This filter is documented in wp-includes/post-template.php */ - $response->data['content']['rendered'] = apply_filters( 'the_content', $content ); - - return $response; + return insert_hooked_blocks_into_rest_response( $response, $post ); } From 7f311542bdf518ccb8f7bebae3e9f98d01bc7643 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 20 Nov 2024 15:09:31 +0100 Subject: [PATCH 4/8] Add parens to function name in _deprecated_function call --- src/wp-includes/deprecated.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index aeb02e8ebab5a..d64ed7450dcd3 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6461,7 +6461,7 @@ function block_core_navigation_set_ignored_hooked_blocks_metadata( $inner_blocks * @return stdClass The updated post object. */ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { - _deprecated_function( __FUNCTION__, '6.8.0', 'update_ignored_hooked_blocks_postmeta' ); + _deprecated_function( __FUNCTION__, '6.8.0', 'update_ignored_hooked_blocks_postmeta()' ); return update_ignored_hooked_blocks_postmeta( $post ); } @@ -6476,6 +6476,6 @@ function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) { * @return WP_REST_Response The response object. */ function block_core_navigation_insert_hooked_blocks_into_rest_response( $response, $post ) { - _deprecated_function( __FUNCTION__, '6.8.0', 'insert_hooked_blocks_into_rest_response' ); + _deprecated_function( __FUNCTION__, '6.8.0', 'insert_hooked_blocks_into_rest_response()' ); return insert_hooked_blocks_into_rest_response( $response, $post ); } From 90938cf98a11851fba05ce5bac3202a754d5f4b1 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 20 Nov 2024 15:11:10 +0100 Subject: [PATCH 5/8] Add deprecated PHPDoc and _deprecated_function to block_core_navigation_set_ignored_hooked_blocks_metadata --- src/wp-includes/deprecated.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index d64ed7450dcd3..8c09fd460e500 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6431,12 +6431,15 @@ function current_user_can_for_blog( $blog_id, $capability, ...$args ) { * mock Navigation block wrapper. * * @since 6.5.0 + * @deprecated 6.8.0 * * @param array $inner_blocks Parsed inner blocks of a Navigation block. * @param WP_Post $post `wp_navigation` post object corresponding to the block. * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any. */ function block_core_navigation_set_ignored_hooked_blocks_metadata( $inner_blocks, $post ) { + _deprecated_function( __FUNCTION__, '6.8.0' ); + $mock_navigation_block = block_core_navigation_mock_parsed_block( $inner_blocks, $post ); $hooked_blocks = get_hooked_blocks(); $before_block_visitor = null; From ec8ca6da0de645aa9bc0ca96030f857430d688c6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 21 Nov 2024 10:10:55 +0100 Subject: [PATCH 6/8] Deprecate block_core_navigation_remove_serialized_parent_block --- src/wp-includes/deprecated.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 8c09fd460e500..b369840a19db3 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6423,6 +6423,20 @@ function current_user_can_for_blog( $blog_id, $capability, ...$args ) { return current_user_can_for_site( $blog_id, $capability, ...$args ); } +/** + * Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the inner blocks. + * + * @since 6.5.0 + * @deprecated 6.8.0 Use remove_serialized_parent_block() instead. + * + * @param string $serialized_block The serialized markup of a block and its inner blocks. + * @return string + */ +function block_core_navigation_remove_serialized_parent_block( $serialized_block ) { + _deprecated_function( __FUNCTION__, '6.8.0', 'remove_serialized_parent_block()' ); + return remove_serialized_parent_block( $serialized_block ); +} + /** * Insert ignoredHookedBlocks meta into the Navigation block and its inner blocks. * From 23088175b57d0c6b49ca84fb611f29c307004bba Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 29 Jan 2025 17:09:14 +0100 Subject: [PATCH 7/8] Deprecate block_core_navigation_mock_parsed_block and block_core_navigation_insert_hooked_blocks --- src/wp-includes/deprecated.php | 62 ++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index b369840a19db3..5797f6f054c37 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6437,6 +6437,68 @@ function block_core_navigation_remove_serialized_parent_block( $serialized_block return remove_serialized_parent_block( $serialized_block ); } +/** + * Mock a parsed block for the Navigation block given its inner blocks and the `wp_navigation` post object. + * The `wp_navigation` post's `_wp_ignored_hooked_blocks` meta is queried to add the `metadata.ignoredHookedBlocks` attribute. + * + * @since 6.5.0 + * @deprecated 6.8.0 + * + * @param array $inner_blocks Parsed inner blocks of a Navigation block. + * @param WP_Post $post `wp_navigation` post object corresponding to the block. + * + * @return array the normalized parsed blocks. + */ +function block_core_navigation_mock_parsed_block( $inner_blocks, $post ) { + _deprecated_function( __FUNCTION__, '6.8.0' ); + $attributes = array(); + + if ( isset( $post->ID ) ) { + $ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true ); + if ( ! empty( $ignored_hooked_blocks ) ) { + $ignored_hooked_blocks = json_decode( $ignored_hooked_blocks, true ); + $attributes['metadata'] = array( + 'ignoredHookedBlocks' => $ignored_hooked_blocks, + ); + } + } + + $mock_anchor_parent_block = array( + 'blockName' => 'core/navigation', + 'attrs' => $attributes, + 'innerBlocks' => $inner_blocks, + 'innerContent' => array_fill( 0, count( $inner_blocks ), null ), + ); + + return $mock_anchor_parent_block; +} + +/** + * Insert hooked blocks into a Navigation block. + * + * Given a Navigation block's inner blocks and its corresponding `wp_navigation` post object, + * this function inserts hooked blocks into it, and returns the serialized inner blocks in a + * mock Navigation block wrapper. + * + * If there are any hooked blocks that need to be inserted as the Navigation block's first or last + * children, the `wp_navigation` post's `_wp_ignored_hooked_blocks` meta is checked to see if any + * of those hooked blocks should be exempted from insertion. + * + * @since 6.5.0 + * @deprecated 6.8.0 + * + * @param array $inner_blocks Parsed inner blocks of a Navigation block. + * @param WP_Post $post `wp_navigation` post object corresponding to the block. + * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any. + */ +function block_core_navigation_insert_hooked_blocks( $inner_blocks, $post ) { + _deprecated_function( __FUNCTION__, '6.8.0' ); + $mock_navigation_block = block_core_navigation_mock_parsed_block( $inner_blocks, $post ); + + $mock_navigation_block_markup = serialize_block( $mock_navigation_block ); + return apply_block_hooks_to_content( $mock_navigation_block_markup, $post, 'insert_hooked_blocks' ); +} + /** * Insert ignoredHookedBlocks meta into the Navigation block and its inner blocks. * From ed5f75797b9fe8a9c12847bb5221f2ec01be0b00 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 29 Jan 2025 17:13:19 +0100 Subject: [PATCH 8/8] Change implementation --- src/wp-includes/deprecated.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 5797f6f054c37..ccd7516e4bd40 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6485,18 +6485,20 @@ function block_core_navigation_mock_parsed_block( $inner_blocks, $post ) { * of those hooked blocks should be exempted from insertion. * * @since 6.5.0 - * @deprecated 6.8.0 + * @deprecated 6.8.0 Use apply_block_hooks_to_content_from_post_object() on the the blocks' serialized markup instead. * * @param array $inner_blocks Parsed inner blocks of a Navigation block. * @param WP_Post $post `wp_navigation` post object corresponding to the block. * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any. */ function block_core_navigation_insert_hooked_blocks( $inner_blocks, $post ) { - _deprecated_function( __FUNCTION__, '6.8.0' ); - $mock_navigation_block = block_core_navigation_mock_parsed_block( $inner_blocks, $post ); + _deprecated_function( __FUNCTION__, '6.8.0', 'apply_block_hooks_to_content_from_post_object' ); - $mock_navigation_block_markup = serialize_block( $mock_navigation_block ); - return apply_block_hooks_to_content( $mock_navigation_block_markup, $post, 'insert_hooked_blocks' ); + return apply_block_hooks_to_content_from_post_object( + serialize_blocks( $inner_blocks ), + $post, + 'insert_hooked_blocks' + ); } /**