Index: /trunk/src/wp-includes/block-template-utils.php
===================================================================
--- /trunk/src/wp-includes/block-template-utils.php	(revision 57626)
+++ /trunk/src/wp-includes/block-template-utils.php	(revision 57627)
@@ -1433,2 +1433,38 @@
 	return $template_hierarchy;
 }
+/**
+ * Inject ignoredHookedBlocks metadata attributes into a template or template part.
+ *
+ * Given a `wp_template` or `wp_template_part` post object, locate all blocks that have
+ * hooked blocks, and inject a `metadata.ignoredHookedBlocks` attribute into the anchor
+ * blocks to reflect the latter.
+ *
+ * @param WP_Post $post A post object with post type set to `wp_template` or `wp_template_part`.
+ * @return WP_Post The updated post object.
+ */
+function inject_ignored_hooked_blocks_metadata_attributes( $post ) {
+	$hooked_blocks = get_hooked_blocks();
+	if ( empty( $hooked_blocks ) && ! has_filter( 'hooked_block_types' ) ) {
+		return;
+	}
+
+	// At this point, the post has already been created.
+	// We need to build the corresponding `WP_Block_Template` object as context argument for the visitor.
+	// To that end, we need to suppress hooked blocks from getting inserted into the template.
+	add_filter( 'hooked_block_types', '__return_empty_array', 99999, 0 );
+	$template = _build_block_template_result_from_post( $post );
+	remove_filter( 'hooked_block_types', '__return_empty_array', 99999 );
+
+	$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( $template->content );
+	$content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
+
+	wp_update_post(
+		array(
+			'ID'            => $post->ID,
+			'post_content'  => $content,
+		)
+	);
+}
Index: /trunk/src/wp-includes/blocks.php
===================================================================
--- /trunk/src/wp-includes/blocks.php	(revision 57626)
+++ /trunk/src/wp-includes/blocks.php	(revision 57627)
@@ -852,42 +852,4 @@
 
 /**
- * Conditionally returns the markup for a given hooked block.
- *
- * Accepts three arguments: A hooked block, its type, and a reference to an anchor block.
- * If the anchor block has already been processed, and the given hooked block type is in the list
- * of ignored hooked blocks, an empty string is returned.
- *
- * The hooked block type is specified separately as it's possible that a filter might've modified
- * the hooked block such that `$hooked_block['blockName']` does no longer reflect the original type.
- *
- * This function is meant for internal use only.
- *
- * @since 6.5.0
- * @access private
- *
- * @param array  $hooked_block      The hooked block, represented as a parsed block array.
- * @param string $hooked_block_type The type of the hooked block. This could be different from
- *                                  $hooked_block['blockName'], as a filter might've modified the latter.
- * @param array  $anchor_block      The anchor block, represented as a parsed block array.
- *                                  Passed by reference.
- * @return string The markup for the given hooked block, or an empty string if the block is ignored.
- */
-function get_hooked_block_markup( $hooked_block, $hooked_block_type, &$anchor_block ) {
-	if ( ! isset( $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
-		$anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array();
-	}
-
-	if ( in_array( $hooked_block_type, $anchor_block['attrs']['metadata']['ignoredHookedBlocks'], true ) ) {
-		return '';
-	}
-
-	// The following is only needed for the REST API endpoint.
-	// However, its presence does not affect the frontend.
-	$anchor_block['attrs']['metadata']['ignoredHookedBlocks'][] = $hooked_block_type;
-
-	return serialize_block( $hooked_block );
-}
-
-/**
  * Returns the markup for blocks hooked to the given anchor block in a specific relative position.
  *
@@ -947,9 +909,56 @@
 
 		// It's possible that the `hooked_block_{$hooked_block_type}` filter returned a block of a different type,
-		// so we need to pass the original $hooked_block_type as well.
-		$markup .= get_hooked_block_markup( $parsed_hooked_block, $hooked_block_type, $parsed_anchor_block );
+		// so we explicitly look for the original `$hooked_block_type` in the `ignoredHookedBlocks` metadata.
+		if (
+			! isset( $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ||
+			! in_array( $hooked_block_type, $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'], true )
+		) {
+			$markup .= serialize_block( $parsed_hooked_block );
+		}
 	}
 
 	return $markup;
+}
+
+/**
+ * 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.5.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'.
+ * @param array                   $hooked_blocks       An array of hooked block types, grouped by anchor block and relative position.
+ * @param WP_Block_Template|array $context             The block template, template part, or pattern that the anchor block belongs to.
+ * @return string An empty string.
+ */
+function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
+	$anchor_block_type  = $parsed_anchor_block['blockName'];
+	$hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
+		? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
+		: array();
+
+	/** This filter is documented in wp-includes/blocks.php */
+	$hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
+	if ( empty( $hooked_block_types ) ) {
+		return '';
+	}
+
+	$previously_ignored_hooked_blocks = isset( $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] )
+		? $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks']
+		: array();
+
+	$parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array_unique(
+		array_merge(
+			$previously_ignored_hooked_blocks,
+			$hooked_block_types
+		)
+	);
+
+	// Markup for the hooked blocks has already been created (in `insert_hooked_blocks`).
+	return '';
 }
 
@@ -964,4 +973,5 @@
  *
  * @since 6.4.0
+ * @since 6.5.0 Added $callback argument.
  * @access private
  *
@@ -969,8 +979,11 @@
  * @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 callable A function that returns the serialized markup for the given block,
  *                  including the markup for any hooked blocks before it.
  */
-function make_before_block_visitor( $hooked_blocks, $context ) {
+function make_before_block_visitor( $hooked_blocks, $context, $callback = 'insert_hooked_blocks' ) {
 	/**
 	 * Injects hooked blocks before the given block, injects the `theme` attribute into Template Part blocks, and returns the serialized markup.
@@ -985,5 +998,5 @@
 	 * @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it.
 	 */
-	return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) {
+	return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context, $callback ) {
 		_inject_theme_attribute_in_template_part_block( $block );
 
@@ -992,8 +1005,14 @@
 		if ( $parent_block && ! $prev ) {
 			// Candidate for first-child insertion.
-			$markup .= insert_hooked_blocks( $parent_block, 'first_child', $hooked_blocks, $context );
-		}
-
-		$markup .= insert_hooked_blocks( $block, 'before', $hooked_blocks, $context );
+			$markup .= call_user_func_array(
+				$callback,
+				array( &$parent_block, 'first_child', $hooked_blocks, $context )
+			);
+		}
+
+		$markup .= call_user_func_array(
+			$callback,
+			array( &$block, 'before', $hooked_blocks, $context )
+		);
 
 		return $markup;
@@ -1011,4 +1030,5 @@
  *
  * @since 6.4.0
+ * @since 6.5.0 Added $callback argument.
  * @access private
  *
@@ -1016,8 +1036,11 @@
  * @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 callable A function that returns the serialized markup for the given block,
  *                  including the markup for any hooked blocks after it.
  */
-function make_after_block_visitor( $hooked_blocks, $context ) {
+function make_after_block_visitor( $hooked_blocks, $context, $callback = 'insert_hooked_blocks' ) {
 	/**
 	 * Injects hooked blocks after the given block, and returns the serialized markup.
@@ -1031,10 +1054,16 @@
 	 * @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it.
 	 */
-	return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
-		$markup = insert_hooked_blocks( $block, 'after', $hooked_blocks, $context );
+	return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context, $callback ) {
+		$markup = call_user_func_array(
+			$callback,
+			array( &$block, 'after', $hooked_blocks, $context )
+		);
 
 		if ( $parent_block && ! $next ) {
 			// Candidate for last-child insertion.
-			$markup .= insert_hooked_blocks( $parent_block, 'last_child', $hooked_blocks, $context );
+			$markup .= call_user_func_array(
+				$callback,
+				array( &$parent_block, 'last_child', $hooked_blocks, $context )
+			);
 		}
 
Index: /trunk/src/wp-includes/default-filters.php
===================================================================
--- /trunk/src/wp-includes/default-filters.php	(revision 57626)
+++ /trunk/src/wp-includes/default-filters.php	(revision 57627)
@@ -753,3 +753,8 @@
 add_action( 'init', '_wp_register_default_font_collections' );
 
+// It might be nice to use a filter instead of an action, but the `WP_REST_Templates_Controller` doesn't
+// provide one (unlike e.g. `WP_REST_Posts_Controller`, which has `rest_pre_insert_{$this->post_type}`).
+add_action( 'rest_after_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes', 10, 3 );
+add_action( 'rest_after_insert_wp_template_part', 'inject_ignored_hooked_blocks_metadata_attributes', 10, 3 );
+
 unset( $filter, $action );
Index: /trunk/tests/phpunit/tests/block-templates/base.php
===================================================================
--- /trunk/tests/phpunit/tests/block-templates/base.php	(revision 57626)
+++ /trunk/tests/phpunit/tests/block-templates/base.php	(revision 57627)
@@ -40,5 +40,5 @@
 				'post_name'    => 'my_template',
 				'post_title'   => 'My Template',
-				'post_content' => '<!-- wp:heading {"level":1} --><h1>Template</h1><!-- /wp:heading -->',
+				'post_content' => '<!-- wp:heading {"level":1,"metadata":{"ignoredHookedBlocks":["tests/ignored"]}} --><h1>Template</h1><!-- /wp:heading -->',
 				'post_excerpt' => 'Description of my template',
 				'tax_input'    => array(
@@ -58,5 +58,5 @@
 				'post_name'    => 'my_template_part',
 				'post_title'   => 'My Template Part',
-				'post_content' => '<!-- wp:heading {"level":2} --><h2>Template Part</h2><!-- /wp:heading -->',
+				'post_content' => '<!-- wp:heading {"level":2,"metadata":{"ignoredHookedBlocks":["tests/ignored"]}} --><h2>Template Part</h2><!-- /wp:heading -->',
 				'post_excerpt' => 'Description of my template part',
 				'tax_input'    => array(
Index: /trunk/tests/phpunit/tests/block-templates/buildBlockTemplateResultFromPost.php
===================================================================
--- /trunk/tests/phpunit/tests/block-templates/buildBlockTemplateResultFromPost.php	(revision 57626)
+++ /trunk/tests/phpunit/tests/block-templates/buildBlockTemplateResultFromPost.php	(revision 57627)
@@ -19,4 +19,8 @@
 		if ( $registry->is_registered( 'tests/my-block' ) ) {
 			$registry->unregister( 'tests/my-block' );
+		}
+
+		if ( $registry->is_registered( 'tests/ignored' ) ) {
+			$registry->unregister( 'tests/ignored' );
 		}
 
@@ -68,4 +72,5 @@
 	/**
 	 * @ticket 59646
+	 * @ticket 60506
 	 */
 	public function test_should_inject_hooked_block_into_template() {
@@ -84,9 +89,9 @@
 		);
 		$this->assertStringStartsWith( '<!-- wp:tests/my-block /-->', $template->content );
-		$this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $template->content );
 	}
 
 	/**
 	 * @ticket 59646
+	 * @ticket 60506
 	 */
 	public function test_should_inject_hooked_block_into_template_part() {
@@ -105,5 +110,46 @@
 		);
 		$this->assertStringEndsWith( '<!-- wp:tests/my-block /-->', $template_part->content );
-		$this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $template_part->content );
+	}
+
+	/**
+	 * @ticket 59646
+	 * @ticket 60506
+	 */
+	public function test_should_not_inject_ignored_hooked_block_into_template() {
+		register_block_type(
+			'tests/ignored',
+			array(
+				'block_hooks' => array(
+					'core/heading' => 'after',
+				),
+			)
+		);
+
+		$template = _build_block_template_result_from_post(
+			self::$template_post,
+			'wp_template'
+		);
+		$this->assertStringNotContainsString( '<!-- wp:tests/ignored /-->', $template->content );
+	}
+
+	/**
+	 * @ticket 59646
+	 * @ticket 60506
+	 */
+	public function test_should_not_inject_ignored_hooked_block_into_template_part() {
+		register_block_type(
+			'tests/ignored',
+			array(
+				'block_hooks' => array(
+					'core/heading' => 'after',
+				),
+			)
+		);
+
+		$template_part = _build_block_template_result_from_post(
+			self::$template_part_post,
+			'wp_template_part'
+		);
+		$this->assertStringNotContainsString( '<!-- wp:tests/ignored /-->', $template_part->content );
 	}
 }
Index: unk/tests/phpunit/tests/blocks/getHookedBlockMarkup.php
===================================================================
--- /trunk/tests/phpunit/tests/blocks/getHookedBlockMarkup.php	(revision 57626)
+++ 	(revision )
@@ -1,112 +1,0 @@
-<?php
-/**
- * Tests for the get_hooked_block_markup function.
- *
- * @package WordPress
- * @subpackage Blocks
- *
- * @since 6.5.0
- *
- * @group blocks
- * @group block-hooks
- */
-class Tests_Blocks_GetHookedBlockMarkup extends WP_UnitTestCase {
-	const HOOKED_BLOCK_TYPE = 'tests/hooked-block';
-	const HOOKED_BLOCK      = array(
-		'blockName'    => 'tests/different-hooked-block',
-		'attrs'        => array(),
-		'innerContent' => array(),
-	);
-
-	/**
-	 * @ticket 59572
-	 * @ticket 60008
-	 * @ticket 60126
-	 *
-	 * @covers ::get_hooked_block_markup
-	 */
-	public function test_get_hooked_block_markup_adds_metadata() {
-		$anchor_block = array(
-			'blockName' => 'tests/anchor-block',
-		);
-
-		$actual = get_hooked_block_markup( self::HOOKED_BLOCK, self::HOOKED_BLOCK_TYPE, $anchor_block );
-		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"Hooked block type wasn't added to ignoredHookedBlocks metadata."
-		);
-		$this->assertSame(
-			'<!-- wp:' . self::HOOKED_BLOCK['blockName'] . ' /-->',
-			$actual,
-			"Markup for hooked block wasn't generated correctly."
-		);
-	}
-
-	/**
-	 * @ticket 59572
-	 * @ticket 60008
-	 * @ticket 60126
-	 *
-	 * @covers ::get_hooked_block_markup
-	 */
-	public function test_get_hooked_block_markup_if_block_is_already_hooked() {
-		$anchor_block = array(
-			'blockName' => 'tests/anchor-block',
-			'attrs'     => array(
-				'metadata' => array(
-					'ignoredHookedBlocks' => array( self::HOOKED_BLOCK_TYPE ),
-				),
-			),
-		);
-
-		$actual = get_hooked_block_markup( self::HOOKED_BLOCK, self::HOOKED_BLOCK_TYPE, $anchor_block );
-		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"ignoredHookedBlocks metadata shouldn't have been modified."
-		);
-		$this->assertSame(
-			'',
-			$actual,
-			"No markup should've been generated for ignored hooked block."
-		);
-	}
-
-	/**
-	 * @ticket 59572
-	 * @ticket 60008
-	 * @ticket 60126
-	 *
-	 * @covers ::get_hooked_block_markup
-	 */
-	public function test_get_hooked_block_markup_adds_to_ignored_hooked_blocks() {
-		$other_hooked_block_type = 'tests/other-hooked-block';
-		$other_hooked_block      = array(
-			'blockName'    => $other_hooked_block_type,
-			'attrs'        => array(),
-			'innerContent' => array(),
-		);
-
-		$anchor_block = array(
-			'blockName' => 'tests/anchor-block',
-			'attrs'     => array(
-				'metadata' => array(
-					'ignoredHookedBlocks' => array( self::HOOKED_BLOCK_TYPE ),
-				),
-			),
-		);
-
-		$actual = get_hooked_block_markup( $other_hooked_block, $other_hooked_block_type, $anchor_block );
-		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE, $other_hooked_block_type ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"Newly hooked block should've been added to ignoredHookedBlocks metadata while retaining previously ignored one."
-		);
-		$this->assertSame(
-			'<!-- wp:' . $other_hooked_block_type . ' /-->',
-			$actual,
-			"Markup for newly hooked block should've been generated."
-		);
-	}
-}
Index: /trunk/tests/phpunit/tests/blocks/getHookedBlocks.php
===================================================================
--- /trunk/tests/phpunit/tests/blocks/getHookedBlocks.php	(revision 57626)
+++ /trunk/tests/phpunit/tests/blocks/getHookedBlocks.php	(revision 57627)
@@ -137,4 +137,5 @@
 	 * @ticket 59313
 	 * @ticket 60008
+	 * @ticket 60506
 	 *
 	 * @covers ::get_hooked_blocks
@@ -151,5 +152,5 @@
 		);
 		$this->assertStringContainsString(
-			'<!-- wp:post-content {"layout":{"type":"constrained"},"metadata":{"ignoredHookedBlocks":["tests/hooked-after"]}} /-->'
+			'<!-- wp:post-content {"layout":{"type":"constrained"}} /-->'
 			. '<!-- wp:tests/hooked-after /-->',
 			$template->content
@@ -168,4 +169,5 @@
 	 * @ticket 59313
 	 * @ticket 60008
+	 * @ticket 60506
 	 *
 	 * @covers ::get_hooked_blocks
@@ -179,5 +181,5 @@
 		$this->assertStringContainsString(
 			'<!-- wp:tests/hooked-before /-->'
-			. '<!-- wp:navigation {"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"},"metadata":{"ignoredHookedBlocks":["tests/hooked-before"]}} /-->',
+			. '<!-- wp:navigation {"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"}} /-->',
 			$template->content
 		);
@@ -199,4 +201,5 @@
 	 * @ticket 59313
 	 * @ticket 60008
+	 * @ticket 60506
 	 *
 	 * @covers ::get_hooked_blocks
@@ -219,5 +222,5 @@
 		);
 		$this->assertStringContainsString(
-			'<!-- wp:comments {"metadata":{"ignoredHookedBlocks":["tests/hooked-first-child"]}} -->'
+			'<!-- wp:comments -->'
 			. '<div class="wp-block-comments">'
 			. '<!-- wp:tests/hooked-first-child /-->',
Index: /trunk/tests/phpunit/tests/blocks/insertHookedBlocks.php
===================================================================
--- /trunk/tests/phpunit/tests/blocks/insertHookedBlocks.php	(revision 57626)
+++ /trunk/tests/phpunit/tests/blocks/insertHookedBlocks.php	(revision 57627)
@@ -26,8 +26,9 @@
 	 * @ticket 59572
 	 * @ticket 60126
+	 * @ticket 60506
 	 *
 	 * @covers ::insert_hooked_blocks
 	 */
-	public function test_insert_hooked_blocks_adds_metadata() {
+	public function test_insert_hooked_blocks_returns_correct_markup() {
 		$anchor_block = array(
 			'blockName' => self::ANCHOR_BLOCK_TYPE,
@@ -35,9 +36,4 @@
 
 		$actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() );
-		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"Hooked block type wasn't added to ignoredHookedBlocks metadata."
-		);
 		$this->assertSame(
 			'<!-- wp:' . self::HOOKED_BLOCK_TYPE . ' /-->',
@@ -50,8 +46,9 @@
 	 * @ticket 59572
 	 * @ticket 60126
+	 * @ticket 60506
 	 *
 	 * @covers ::insert_hooked_blocks
 	 */
-	public function test_insert_hooked_blocks_if_block_is_already_hooked() {
+	public function test_insert_hooked_blocks_if_block_is_ignored() {
 		$anchor_block = array(
 			'blockName' => 'tests/anchor-block',
@@ -65,9 +62,4 @@
 		$actual = insert_hooked_blocks( $anchor_block, 'after', self::HOOKED_BLOCKS, array() );
 		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"ignoredHookedBlocks metadata shouldn't have been modified."
-		);
-		$this->assertSame(
 			'',
 			$actual,
@@ -79,8 +71,9 @@
 	 * @ticket 59572
 	 * @ticket 60126
+	 * @ticket 60506
 	 *
 	 * @covers ::insert_hooked_blocks
 	 */
-	public function test_insert_hooked_blocks_adds_to_ignored_hooked_blocks() {
+	public function test_insert_hooked_blocks_if_other_block_is_ignored() {
 		$anchor_block = array(
 			'blockName' => 'tests/anchor-block',
@@ -94,9 +87,4 @@
 		$actual = insert_hooked_blocks( $anchor_block, 'before', self::HOOKED_BLOCKS, array() );
 		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE, self::OTHER_HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"Newly hooked block should've been added to ignoredHookedBlocks metadata while retaining previously ignored one."
-		);
-		$this->assertSame(
 			'<!-- wp:' . self::OTHER_HOOKED_BLOCK_TYPE . ' /-->',
 			$actual,
@@ -108,4 +96,5 @@
 	 * @ticket 59572
 	 * @ticket 60126
+	 * @ticket 60506
 	 *
 	 * @covers ::insert_hooked_blocks
@@ -141,9 +130,4 @@
 
 		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"Hooked block type wasn't added to ignoredHookedBlocks metadata."
-		);
-		$this->assertSame(
 			'<!-- wp:' . self::HOOKED_BLOCK_TYPE . ' {"layout":{"type":"constrained"}} /-->',
 			$actual,
@@ -155,4 +139,5 @@
 	 * @ticket 59572
 	 * @ticket 60126
+	 * @ticket 60506
 	 *
 	 * @covers ::insert_hooked_blocks
@@ -191,9 +176,4 @@
 
 		$this->assertSame(
-			array( self::HOOKED_BLOCK_TYPE ),
-			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
-			"Hooked block type wasn't added to ignoredHookedBlocks metadata."
-		);
-		$this->assertSame(
 			'<!-- wp:group --><div class="wp-block-group"><!-- wp:' . self::HOOKED_BLOCK_TYPE . ' /--></div><!-- /wp:group -->',
 			$actual,
Index: /trunk/tests/phpunit/tests/blocks/setIgnoredHookedBlocksMetadata.php
===================================================================
--- /trunk/tests/phpunit/tests/blocks/setIgnoredHookedBlocksMetadata.php	(revision 57627)
+++ /trunk/tests/phpunit/tests/blocks/setIgnoredHookedBlocksMetadata.php	(revision 57627)
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Tests for the set_ignored_hooked_blocks_metadata function.
+ *
+ * @package WordPress
+ * @subpackage Blocks
+ *
+ * @since 6.5.0
+ *
+ * @group blocks
+ * @group block-hooks
+ */
+class Tests_Blocks_SetIgnoredHookedBlocksMetadata extends WP_UnitTestCase {
+	/**
+	 * @ticket 60506
+	 */
+	private static function create_block_template_object() {
+		$template              = new WP_Block_Template();
+		$template->type        = 'wp_template';
+		$template->theme       = 'test-theme';
+		$template->slug        = 'single';
+		$template->id          = $template->theme . '//' . $template->slug;
+		$template->title       = 'Single';
+		$template->content     = '<!-- wp:tests/anchor-block /-->';
+		$template->description = 'Description of my template';
+
+		return $template;
+	}
+
+	/**
+	 * @ticket 60506
+	 *
+	 * @covers ::set_ignored_hooked_blocks_metadata
+	 */
+	public function test_set_ignored_hooked_blocks_metadata() {
+		$anchor_block = array(
+			'blockName' => 'tests/anchor-block',
+		);
+
+		$hooked_blocks = array(
+			'tests/anchor-block' => array(
+				'after' => array( 'tests/hooked-block' ),
+			),
+		);
+
+		set_ignored_hooked_blocks_metadata( $anchor_block, 'after', $hooked_blocks, null );
+		$this->assertSame( $anchor_block['attrs']['metadata']['ignoredHookedBlocks'], array( 'tests/hooked-block' ) );
+	}
+
+	/**
+	 * @ticket 60506
+	 *
+	 * @covers ::set_ignored_hooked_blocks_metadata
+	 */
+	public function test_set_ignored_hooked_blocks_metadata_retains_existing_items() {
+		$anchor_block = array(
+			'blockName' => 'tests/anchor-block',
+			'attrs'     => array(
+				'metadata' => array(
+					'ignoredHookedBlocks' => array( 'tests/other-ignored-block' ),
+				),
+			),
+		);
+
+		$hooked_blocks = array(
+			'tests/anchor-block' => array(
+				'after' => array( 'tests/hooked-block' ),
+			),
+		);
+
+		set_ignored_hooked_blocks_metadata( $anchor_block, 'after', $hooked_blocks, null );
+		$this->assertSame(
+			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
+			array( 'tests/other-ignored-block', 'tests/hooked-block' )
+		);
+	}
+
+	/**
+	 * @ticket 60506
+	 *
+	 * @covers ::set_ignored_hooked_blocks_metadata
+	 */
+	public function test_set_ignored_hooked_blocks_metadata_for_block_added_by_filter() {
+		$anchor_block = array(
+			'blockName' => 'tests/anchor-block',
+			'attrs'     => array(),
+		);
+
+		$hooked_blocks = array();
+
+		$filter = function ( $hooked_block_types, $relative_position, $anchor_block_type ) {
+			if ( 'tests/anchor-block' === $anchor_block_type && 'after' === $relative_position ) {
+				$hooked_block_types[] = 'tests/hooked-block-added-by-filter';
+			}
+
+			return $hooked_block_types;
+		};
+
+		add_filter( 'hooked_block_types', $filter, 10, 3 );
+		set_ignored_hooked_blocks_metadata( $anchor_block, 'after', $hooked_blocks, null );
+		remove_filter( 'hooked_block_types', $filter, 10 );
+
+		$this->assertSame(
+			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
+			array( 'tests/hooked-block-added-by-filter' )
+		);
+	}
+
+	/**
+	 * @ticket 60506
+	 *
+	 * @covers ::set_ignored_hooked_blocks_metadata
+	 */
+	public function test_set_ignored_hooked_blocks_metadata_for_block_added_by_context_aware_filter() {
+		$anchor_block = array(
+			'blockName' => 'tests/anchor-block',
+			'attrs'     => array(),
+		);
+
+		$filter = function ( $hooked_block_types, $relative_position, $anchor_block_type, $context ) {
+			if (
+				! $context instanceof WP_Block_Template ||
+				! property_exists( $context, 'slug' ) ||
+				'single' !== $context->slug
+			) {
+				return $hooked_block_types;
+			}
+
+			if ( 'tests/anchor-block' === $anchor_block_type && 'after' === $relative_position ) {
+				$hooked_block_types[] = 'tests/hooked-block-added-by-filter';
+			}
+
+			return $hooked_block_types;
+		};
+
+		$template = self::create_block_template_object();
+
+		add_filter( 'hooked_block_types', $filter, 10, 4 );
+		set_ignored_hooked_blocks_metadata( $anchor_block, 'after', array(), $template );
+		remove_filter( 'hooked_block_types', $filter, 10 );
+
+		$this->assertSame(
+			$anchor_block['attrs']['metadata']['ignoredHookedBlocks'],
+			array( 'tests/hooked-block-added-by-filter' )
+		);
+	}
+}
Index: /trunk/tests/phpunit/tests/blocks/wpBlockPatternsRegistry.php
===================================================================
--- /trunk/tests/phpunit/tests/blocks/wpBlockPatternsRegistry.php	(revision 57626)
+++ /trunk/tests/phpunit/tests/blocks/wpBlockPatternsRegistry.php	(revision 57627)
@@ -345,4 +345,5 @@
 	 * @ticket 59476
 	 * @ticket 60008
+	 * @ticket 60506
 	 *
 	 * @covers WP_Block_Patterns_Registry::register
@@ -386,7 +387,5 @@
 		$this->assertCount( 3, $registered );
 		$this->assertStringEndsWith( '<!-- wp:tests/my-block /-->', $registered[1]['content'] );
-		$this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $registered[1]['content'] );
 		$this->assertStringEndsWith( '<!-- wp:tests/my-block /-->', $registered[2]['content'] );
-		$this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $registered[2]['content'] );
 	}
 
@@ -419,4 +418,5 @@
 	 * @ticket 59476
 	 * @ticket 60008
+	 * @ticket 60506
 	 *
 	 * @covers WP_Block_Patterns_Registry::register
@@ -447,5 +447,4 @@
 		$pattern = $this->registry->get_registered( 'test/one' );
 		$this->assertStringStartsWith( '<!-- wp:tests/my-block /-->', $pattern['content'] );
-		$this->assertStringContainsString( '"metadata":{"ignoredHookedBlocks":["tests/my-block"]}', $pattern['content'] );
 	}
 
