各位代码界的泥石流们,晚上好!今天咱们来聊聊 WordPress 里一个挺有意思的小东西:get_blocks_for_post()
函数。这玩意儿就像个考古学家,专门从 WordPress 文章的内容里挖出各种各样的“区块化石”。
咱们的目标是:搞明白它到底是怎么挖的,挖出来的“化石”又是什么样子的。准备好,我们要开始“挖坟”了!
一、开场白:区块时代的“洛阳铲”
在古腾堡编辑器(也就是 WordPress 的区块编辑器)出现之前,咱们写文章那叫一个“自由”,各种 HTML 标签满天飞,排版样式全靠手撸。但自从有了区块,一切都变得井然有序,每个区块负责一块内容,就像搭积木一样。
get_blocks_for_post()
函数就是用来解析这种“积木式”文章内容的,它就像一把精准的“洛阳铲”,专门挖掘文章中的区块信息,然后把这些信息整理成易于理解的对象。
二、源码探秘:一步一步揭开神秘面纱
咱们先来看看 get_blocks_for_post()
函数的“真容”(简化版,保留核心逻辑):
/**
* 获取文章的区块列表.
*
* @param WP_Post|int|null $post 文章对象或 ID。默认使用全局 $post 对象。
* @return array|null 区块数组,如果文章不存在或内容为空,则返回 null。
*/
function get_blocks_for_post( $post = null ) {
$post = get_post( $post );
if ( ! $post || empty( $post->post_content ) ) {
return null;
}
$content = $post->post_content;
$blocks = parse_blocks( $content ); // 核心函数:解析区块
return $blocks;
}
这段代码简洁明了,主要做了三件事:
- 获取文章对象: 接收文章 ID 或者文章对象,如果没传,就用全局
$post
对象。 - 检查文章是否存在和内容是否为空: 如果文章不存在或者内容是空的,直接返回
null
,没啥好挖的。 - 解析区块: 这是最关键的一步,调用
parse_blocks()
函数来解析文章内容,把内容分割成一个个区块对象。
看到没?真正的“挖掘”工作是由 parse_blocks()
函数完成的。所以,咱们的重点要转移到这个函数身上。
三、parse_blocks()
:区块解析的“屠龙刀”
parse_blocks()
函数才是真正的“屠龙刀”,它负责把一坨字符串(文章内容)分解成一个个区块对象。这把刀的“刀法”可不简单,咱们来仔细看看:
/**
* 将内容解析为区块数组.
*
* @param string $content 要解析的内容。
* @return array 区块数组.
*/
function parse_blocks( $content ) {
$blocks = array();
$start = 0;
$length = strlen( $content );
while ( $start < $length ) {
$block = parse_block( substr( $content, $start ) ); // 核心函数:解析单个区块
if ( null === $block ) {
// 如果没有找到区块,就创建一个自由格式区块,包含剩余的内容
$text = substr( $content, $start );
$blocks[] = array(
'blockName' => null,
'attrs' => array(),
'innerBlocks' => array(),
'innerHTML' => $text,
'innerContent' => array( $text ),
);
break; // 结束循环,因为剩余的内容被视为一个整体
}
$blocks[] = $block;
$start += strlen( $block[0] ); // 更新起始位置
}
return $blocks;
}
这段代码稍微复杂一点,但核心思想是:
- 循环解析: 从文章内容的开头开始,循环查找和解析区块。
- 解析单个区块: 调用
parse_block()
函数来解析单个区块。 - 处理未识别的内容: 如果
parse_block()
函数返回null
,说明没有找到区块,就把剩余的内容当作一个自由格式的区块处理。 - 更新起始位置: 每次成功解析一个区块后,更新起始位置,继续查找下一个区块。
看到没?parse_block()
函数才是真正的“刀尖”,它负责解析单个区块。所以,咱们的重点要再次转移到这个函数身上。
四、parse_block()
:区块解析的“显微镜”
parse_block()
函数就像一个“显微镜”,它负责分析文章内容中的每一个细节,找出区块的开始标记、属性、内容等等。
/**
* 解析一个区块.
*
* @param string $content 要解析的内容.
* @return array|null 区块数据数组,如果未找到有效的区块开始标记,则返回 null。
*/
function parse_block( $content ) {
// 匹配区块的开始标记
if (
! preg_match(
'/<!--s+wp:([a-z0-9/-]+)s+({(?:[^{}]++|(?1))*})?s+-->/',
$content,
$matches,
PREG_OFFSET_CAPTURE
)
) {
return null; // 没有找到区块开始标记
}
$block_name = $matches[1][0]; // 区块名称
$block_start = $matches[0][1]; // 区块开始标记的位置
$block_length = strlen( $matches[0][0] ); // 区块开始标记的长度
$attrs = array();
if ( isset( $matches[2] ) && '' !== $matches[2][0] ) {
// 解析区块属性
$attrs = json_decode( $matches[2][0], true );
if ( ! is_array( $attrs ) ) {
$attrs = array(); // 如果解析失败,则使用空数组
}
}
// 获取 innerHTML 和 innerContent
$inner_blocks = array();
$inner_html = '';
$inner_content = array();
// 匹配区块的结束标记
$end_tag = "<!-- /wp:$block_name -->";
$end_tag_pos = strpos( $content, $end_tag, $block_start + $block_length );
if ( false !== $end_tag_pos ) {
// 找到结束标记
$block_content = substr( $content, $block_start + $block_length, $end_tag_pos - ($block_start + $block_length) );
$inner_html = $block_content;
// 递归解析内部区块
$inner_blocks = parse_blocks( $block_content );
// 构建 innerContent 数组
$inner_content = array( $inner_html );
} else {
// 没有找到结束标记,可能是自闭合区块
$inner_html = '';
$inner_content = array();
}
// 构建区块数据
$block = array(
'blockName' => $block_name,
'attrs' => $attrs,
'innerBlocks' => $inner_blocks,
'innerHTML' => $inner_html,
'innerContent' => $inner_content,
);
// 获取整个区块的内容(包括开始和结束标记)
$full_block = substr( $content, $block_start, (false === $end_tag_pos ? strlen( $content ) : $end_tag_pos + strlen( $end_tag ) ) - $block_start );
$block[0] = $full_block;
return $block;
}
这段代码是整个流程中最复杂的部分,咱们来分解一下:
- 匹配区块开始标记: 使用正则表达式匹配区块的开始标记,例如
<!-- wp:paragraph {"align":"center"} -->
。 - 提取区块名称和属性: 从匹配结果中提取区块的名称(例如
paragraph
)和属性(例如{"align":"center"}
)。 - 解析区块属性: 使用
json_decode()
函数解析区块属性,将其转换为 PHP 数组。 - 匹配区块结束标记: 查找区块的结束标记,例如
<!-- /wp:paragraph -->
。 - 提取内部内容: 如果找到结束标记,提取开始标记和结束标记之间的内容,作为区块的内部内容。
- 递归解析内部区块: 再次调用
parse_blocks()
函数,递归解析内部内容,找出嵌套的区块。 - 构建区块数据: 将区块的名称、属性、内部区块、内部 HTML 和内部内容等信息组合成一个数组,作为区块的数据。
- 返回区块数据: 返回包含区块信息的数组。
五、区块数据的结构:积木的蓝图
经过 get_blocks_for_post()
函数的“挖掘”和“解析”,咱们最终得到的是一个区块数组,每个区块都是一个包含以下信息的数组:
键名 | 类型 | 描述 | 示例 |
---|