函数文档

apply_block_hooks_to_content()

💡 云策文档标注

概述

apply_block_hooks_to_content() 函数用于在给定内容上运行钩子块算法,自动插入或管理钩子块。它处理序列化内容,根据上下文和回调函数生成最终标记。

关键要点

  • 函数接受三个参数:$content(必需,序列化内容)、$context(可选,块模板、模板部分、文章对象或模式,默认为 null 时使用当前文章)、$callback(必需,用于生成钩子块标记的回调函数,默认为 'insert_hooked_blocks')。
  • 返回序列化标记字符串,通过遍历和序列化块来应用钩子块逻辑。
  • 自动处理钩子块的多实例支持,避免重复插入不支持多实例的块。
  • 使用 get_hooked_blocks() 获取钩子块,并通过 traverse_and_serialize_blocks() 结合前后访问器函数处理内容。

代码示例

function apply_block_hooks_to_content( $content, $context = null, $callback = 'insert_hooked_blocks' ) {
    // Default to the current post if no context is provided.
    if ( null === $context ) {
        $context = get_post();
    }

    $hooked_blocks = get_hooked_blocks();

    $before_block_visitor = '_inject_theme_attribute_in_template_part_block';
    $after_block_visitor  = null;
    if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
        $before_block_visitor = make_before_block_visitor( $hooked_blocks, $context, $callback );
        $after_block_visitor  = make_after_block_visitor( $hooked_blocks, $context, $callback );
    }

    // ... 处理多实例逻辑和过滤 ...

    $content = traverse_and_serialize_blocks(
        parse_blocks( $content ),
        $before_block_visitor,
        $after_block_visitor
    );

    return $content;
}

注意事项

  • 函数在 WordPress 6.6.0 中引入,后续版本有更新:6.7.0 添加了主题属性注入到模板部分块,6.8.0 使 $context 参数默认为 null 以使用当前文章。
  • 依赖多个辅助函数如 get_hooked_blocks()、traverse_and_serialize_blocks() 等,确保这些函数在环境中可用。
  • 钩子块算法考虑了 block_has_support() 检查,以处理块的多实例支持,避免内容重复。

📄 原文内容

Runs the hooked blocks algorithm on the given content.

Parameters

$contentstringrequired
Serialized content.
$contextWP_Block_Template|WP_Post|array|nulloptional
A block template, template part, post object, or pattern that the blocks belong to. If set to null, get_post() will be called to use the current post as context.
Default: null.

Default:null

$callbackcallablerequired
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.

Source

function apply_block_hooks_to_content( $content, $context = null, $callback = 'insert_hooked_blocks' ) {
	// Default to the current post if no context is provided.
	if ( null === $context ) {
		$context = get_post();
	}

	$hooked_blocks = get_hooked_blocks();

	$before_block_visitor = '_inject_theme_attribute_in_template_part_block';
	$after_block_visitor  = null;
	if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
		$before_block_visitor = make_before_block_visitor( $hooked_blocks, $context, $callback );
		$after_block_visitor  = make_after_block_visitor( $hooked_blocks, $context, $callback );
	}

	$block_allows_multiple_instances = array();
	/*
	 * Remove hooked blocks from `$hooked_block_types` if they have `multiple` set to false and
	 * are already present in `$content`.
	 */
	foreach ( $hooked_blocks as $anchor_block_type => $relative_positions ) {
		foreach ( $relative_positions as $relative_position => $hooked_block_types ) {
			foreach ( $hooked_block_types as $index => $hooked_block_type ) {
				$hooked_block_type_definition =
					WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type );

				$block_allows_multiple_instances[ $hooked_block_type ] =
					block_has_support( $hooked_block_type_definition, 'multiple', true );

				if (
					! $block_allows_multiple_instances[ $hooked_block_type ] &&
					has_block( $hooked_block_type, $content )
				) {
					unset( $hooked_blocks[ $anchor_block_type ][ $relative_position ][ $index ] );
				}
			}
			if ( empty( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) ) {
				unset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] );
			}
		}
		if ( empty( $hooked_blocks[ $anchor_block_type ] ) ) {
			unset( $hooked_blocks[ $anchor_block_type ] );
		}
	}

	/*
	 * We also need to cover the case where the hooked block is not present in
	 * `$content` at first and we're allowed to insert it once -- but not again.
	 */
	$suppress_single_instance_blocks = static function ( $hooked_block_types ) use ( &$block_allows_multiple_instances, $content ) {
		static $single_instance_blocks_present_in_content = array();
		foreach ( $hooked_block_types as $index => $hooked_block_type ) {
			if ( ! isset( $block_allows_multiple_instances[ $hooked_block_type ] ) ) {
				$hooked_block_type_definition =
					WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type );

				$block_allows_multiple_instances[ $hooked_block_type ] =
					block_has_support( $hooked_block_type_definition, 'multiple', true );
			}

			if ( $block_allows_multiple_instances[ $hooked_block_type ] ) {
				continue;
			}

			// The block doesn't allow multiple instances, so we need to check if it's already present.
			if (
				in_array( $hooked_block_type, $single_instance_blocks_present_in_content, true ) ||
				has_block( $hooked_block_type, $content )
			) {
				unset( $hooked_block_types[ $index ] );
			} else {
				// We can insert the block once, but need to remember not to insert it again.
				$single_instance_blocks_present_in_content[] = $hooked_block_type;
			}
		}
		return $hooked_block_types;
	};
	add_filter( 'hooked_block_types', $suppress_single_instance_blocks, PHP_INT_MAX );
	$content = traverse_and_serialize_blocks(
		parse_blocks( $content ),
		$before_block_visitor,
		$after_block_visitor
	);
	remove_filter( 'hooked_block_types', $suppress_single_instance_blocks, PHP_INT_MAX );

	return $content;
}

Changelog

Version Description
6.8.0 Have the $context parameter default to null, in which case get_post() will be called to use the current post as context.
6.7.0 Injects the theme attribute into Template Part blocks, even if no hooked blocks are registered.
6.6.0 Introduced.