mirror of
git://develop.git.wordpress.org/
synced 2025-04-07 21:53:21 +02:00
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core. In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.) Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854). Props tomjcafferkey, bernhard-reiter. Fixes #60759. git-svn-id: https://develop.svn.wordpress.org/trunk@58291 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
f466cecadc
commit
b39f58ec3e
@ -1599,11 +1599,7 @@ function inject_ignored_hooked_blocks_metadata_attributes( $changes, $deprecated
|
||||
return $template;
|
||||
}
|
||||
|
||||
$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template, 'set_ignored_hooked_blocks_metadata' );
|
||||
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $template, 'set_ignored_hooked_blocks_metadata' );
|
||||
|
||||
$blocks = parse_blocks( $changes->post_content );
|
||||
$changes->post_content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
|
||||
$changes->post_content = apply_block_hooks_to_content( $changes->post_content, $template, 'set_ignored_hooked_blocks_metadata' );
|
||||
|
||||
return $changes;
|
||||
}
|
||||
|
@ -1003,14 +1003,124 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the hooked blocks algorithm on the given content.
|
||||
*
|
||||
* @since 6.6.0
|
||||
* @access private
|
||||
*
|
||||
* @param string $content Serialized content.
|
||||
* @param WP_Block_Template|WP_Post|array $context A block template, template part, `wp_navigation` post object,
|
||||
* or pattern that the blocks belong to.
|
||||
* @param callable $callback A function that will be called for each block to generate
|
||||
* the markup for a given list of blocks that are hooked to it.
|
||||
* Default: 'insert_hooked_blocks'.
|
||||
* @return string The serialized markup.
|
||||
*/
|
||||
function apply_block_hooks_to_content( $content, $context, $callback = 'insert_hooked_blocks' ) {
|
||||
$hooked_blocks = get_hooked_blocks();
|
||||
if ( empty( $hooked_blocks ) && ! has_filter( 'hooked_block_types' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$blocks = parse_blocks( $content );
|
||||
|
||||
$before_block_visitor = make_before_block_visitor( $hooked_blocks, $context, $callback );
|
||||
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $context, $callback );
|
||||
|
||||
return traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the inner blocks.
|
||||
*
|
||||
* @since 6.6.0
|
||||
* @access private
|
||||
*
|
||||
* @param string $serialized_block The serialized markup of a block and its inner blocks.
|
||||
* @return string The serialized markup of the inner blocks.
|
||||
*/
|
||||
function remove_serialized_parent_block( $serialized_block ) {
|
||||
$start = strpos( $serialized_block, '-->' ) + strlen( '-->' );
|
||||
$end = strrpos( $serialized_block, '<!--' );
|
||||
return substr( $serialized_block, $start, $end - $start );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the wp_postmeta with the list of ignored hooked blocks where the inner blocks are stored as post content.
|
||||
* Currently only supports `wp_navigation` post types.
|
||||
*
|
||||
* @since 6.6.0
|
||||
* @access private
|
||||
*
|
||||
* @param stdClass $post Post object.
|
||||
* @return stdClass The updated post object.
|
||||
*/
|
||||
function update_ignored_hooked_blocks_postmeta( $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip meta generation when the post content is not a navigation block.
|
||||
*/
|
||||
if ( ! isset( $post->post_type ) || 'wp_navigation' !== $post->post_type ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
$attributes = array();
|
||||
|
||||
$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,
|
||||
);
|
||||
}
|
||||
|
||||
$markup = get_comment_delimited_block_content(
|
||||
'core/navigation',
|
||||
$attributes,
|
||||
$post->post_content
|
||||
);
|
||||
|
||||
$serialized_block = apply_block_hooks_to_content( $markup, get_post( $post->ID ), 'set_ignored_hooked_blocks_metadata' );
|
||||
$root_block = parse_blocks( $serialized_block )[0];
|
||||
|
||||
$ignored_hooked_blocks = isset( $root_block['attrs']['metadata']['ignoredHookedBlocks'] )
|
||||
? $root_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 = remove_serialized_parent_block( $serialized_block );
|
||||
return $post;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the markup for blocks hooked to the given anchor block in a specific relative position and then
|
||||
* adds a list of hooked block types to an anchor block's ignored hooked block types.
|
||||
*
|
||||
* This function is meant for internal use only.
|
||||
*
|
||||
* @since 6.6.0
|
||||
* @access private
|
||||
*
|
||||
* @param array $parsed_anchor_block The anchor block, in parsed block array format.
|
||||
* @param string $relative_position The relative position of the hooked blocks.
|
||||
* Can be one of 'before', 'after', 'first_child', or 'last_child'.
|
||||
@ -1019,7 +1129,7 @@ function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_po
|
||||
* @return string
|
||||
*/
|
||||
function insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
|
||||
$markup = insert_hooked_blocks( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
|
||||
$markup = insert_hooked_blocks( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
|
||||
$markup .= set_ignored_hooked_blocks_metadata( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
|
||||
|
||||
return $markup;
|
||||
|
@ -757,4 +757,7 @@ add_action( 'init', '_wp_register_default_font_collections' );
|
||||
add_filter( 'rest_pre_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes' );
|
||||
add_filter( 'rest_pre_insert_wp_template_part', 'inject_ignored_hooked_blocks_metadata_attributes' );
|
||||
|
||||
// Update ignoredHookedBlocks postmeta for wp_navigation post type.
|
||||
add_filter( 'rest_pre_insert_wp_navigation', 'update_ignored_hooked_blocks_postmeta' );
|
||||
|
||||
unset( $filter, $action );
|
||||
|
196
tests/phpunit/tests/blocks/updateIgnoredHookedBlocksPostMeta.php
Normal file
196
tests/phpunit/tests/blocks/updateIgnoredHookedBlocksPostMeta.php
Normal file
@ -0,0 +1,196 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for update_ignored_hooked_blocks_postmeta
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Blocks
|
||||
*
|
||||
* @since 6.6.0
|
||||
*
|
||||
* @group blocks
|
||||
* @covers ::update_ignored_hooked_blocks_postmeta
|
||||
*/
|
||||
class Tests_Blocks_UpdateIgnoredHookedBlocksPostMeta extends WP_UnitTestCase {
|
||||
/**
|
||||
* Post object.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected static $navigation_post;
|
||||
|
||||
/**
|
||||
* Setup method.
|
||||
*/
|
||||
public static function wpSetUpBeforeClass() {
|
||||
self::$navigation_post = self::factory()->post->create_and_get(
|
||||
array(
|
||||
'post_type' => 'wp_navigation',
|
||||
'post_title' => 'Navigation Menu',
|
||||
'post_content' => 'Original content',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down each test method.
|
||||
*/
|
||||
public function tear_down() {
|
||||
$registry = WP_Block_Type_Registry::get_instance();
|
||||
|
||||
if ( $registry->is_registered( 'tests/my-block' ) ) {
|
||||
$registry->unregister( 'tests/my-block' );
|
||||
}
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 60759
|
||||
*/
|
||||
public function test_update_ignored_hooked_blocks_postmeta_preserves_entities() {
|
||||
register_block_type(
|
||||
'tests/my-block',
|
||||
array(
|
||||
'block_hooks' => array(
|
||||
'core/navigation' => 'last_child',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$original_markup = '<!-- wp:navigation-link {"label":"News & About","type":"page","id":2,"url":"http://localhost:8888/?page_id=2","kind":"post-type"} /-->';
|
||||
$post = new stdClass();
|
||||
$post->ID = self::$navigation_post->ID;
|
||||
$post->post_content = $original_markup;
|
||||
$post->post_type = 'wp_navigation';
|
||||
|
||||
$post = update_ignored_hooked_blocks_postmeta( $post );
|
||||
|
||||
// We expect the '&' character to be replaced with its unicode representation.
|
||||
$expected_markup = str_replace( '&', '\u0026', $original_markup );
|
||||
|
||||
$this->assertSame(
|
||||
$expected_markup,
|
||||
$post->post_content,
|
||||
'Post content did not match expected markup with entities escaped.'
|
||||
);
|
||||
$this->assertSame(
|
||||
array( 'tests/my-block' ),
|
||||
json_decode( get_post_meta( self::$navigation_post->ID, '_wp_ignored_hooked_blocks', true ), true ),
|
||||
'Block was not added to ignored hooked blocks metadata.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 60759
|
||||
*/
|
||||
public function test_update_ignored_hooked_blocks_postmeta_dont_modify_no_post_id() {
|
||||
register_block_type(
|
||||
'tests/my-block',
|
||||
array(
|
||||
'block_hooks' => array(
|
||||
'core/navigation' => 'last_child',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$original_markup = '<!-- wp:navigation-link {"label":"News","type":"page","id":2,"url":"http://localhost:8888/?page_id=2","kind":"post-type"} /-->';
|
||||
$post = new stdClass();
|
||||
$post->post_content = $original_markup;
|
||||
$post->post_type = 'wp_navigation';
|
||||
|
||||
$post = update_ignored_hooked_blocks_postmeta( $post );
|
||||
|
||||
$this->assertSame(
|
||||
$original_markup,
|
||||
$post->post_content,
|
||||
'Post content did not match the original markup.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 60759
|
||||
*/
|
||||
public function test_update_ignored_hooked_blocks_postmeta_retains_content_if_not_set() {
|
||||
register_block_type(
|
||||
'tests/my-block',
|
||||
array(
|
||||
'block_hooks' => array(
|
||||
'core/navigation' => 'last_child',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$post = new stdClass();
|
||||
$post->ID = self::$navigation_post->ID;
|
||||
$post->post_title = 'Navigation Menu with changes';
|
||||
$post->post_type = 'wp_navigation';
|
||||
|
||||
$post = update_ignored_hooked_blocks_postmeta( $post );
|
||||
|
||||
$this->assertSame(
|
||||
'Navigation Menu with changes',
|
||||
$post->post_title,
|
||||
'Post title was changed.'
|
||||
);
|
||||
|
||||
$this->assertFalse(
|
||||
isset( $post->post_content ),
|
||||
'Post content should not be set.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 60759
|
||||
*/
|
||||
public function test_update_ignored_hooked_blocks_postmeta_dont_modify_if_not_navigation() {
|
||||
register_block_type(
|
||||
'tests/my-block',
|
||||
array(
|
||||
'block_hooks' => array(
|
||||
'core/navigation' => 'last_child',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$original_markup = '<!-- wp:navigation-link {"label":"News","type":"page","id":2,"url":"http://localhost:8888/?page_id=2","kind":"post-type"} /-->';
|
||||
$post = new stdClass();
|
||||
$post->ID = self::$navigation_post->ID;
|
||||
$post->post_content = $original_markup;
|
||||
$post->post_type = 'post';
|
||||
|
||||
$post = update_ignored_hooked_blocks_postmeta( $post );
|
||||
|
||||
$this->assertSame(
|
||||
$original_markup,
|
||||
$post->post_content,
|
||||
'Post content did not match the original markup.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 60759
|
||||
*/
|
||||
public function test_update_ignored_hooked_blocks_postmeta_dont_modify_if_no_post_type() {
|
||||
register_block_type(
|
||||
'tests/my-block',
|
||||
array(
|
||||
'block_hooks' => array(
|
||||
'core/navigation' => 'last_child',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$original_markup = '<!-- wp:navigation-link {"label":"News","type":"page","id":2,"url":"http://localhost:8888/?page_id=2","kind":"post-type"} /-->';
|
||||
$post = new stdClass();
|
||||
$post->ID = self::$navigation_post->ID;
|
||||
$post->post_content = $original_markup;
|
||||
|
||||
$post = update_ignored_hooked_blocks_postmeta( $post );
|
||||
|
||||
$this->assertSame(
|
||||
$original_markup,
|
||||
$post->post_content,
|
||||
'Post content did not match the original markup.'
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user