分析 WordPress `get_post_block_type()` 函数的源码:如何从文章中识别出区块类型。

各位代码爱好者,今天咱来聊聊WordPress里一个有点意思的函数:get_post_block_type()。 别看名字平平无奇,它可是WordPress区分文章里那些花里胡哨的“区块”的大侦探。 咱们的目标是,拆解这个函数,看看它是怎么从一堆文本里揪出各种区块类型的。

一、先来认识一下咱们的侦探:get_post_block_type()

这个函数的作用很简单,就是从文章内容中提取出第一个出现的区块的类型。 比如,文章开头第一个区块是个段落,它就返回 core/paragraph。 如果文章里压根就没区块,或者内容为空,它就乖乖地返回 null

先看下源码的庐山真面目:

/**
 * Retrieves the block type of the first block in the content of a post.
 *
 * @since 5.0.0
 *
 * @param WP_Post|int|null $post Optional. Post ID or WP_Post object. Default is global $post.
 * @return string|null Block type string if found. Null if not found.
 */
function get_post_block_type( $post = null ) {
    $post = get_post( $post );

    if ( ! $post ) {
        return null;
    }

    $blocks = parse_blocks( $post->post_content );

    if ( ! $blocks ) {
        return null;
    }

    if ( ! isset( $blocks[0]['blockName'] ) ) {
        return null;
    }

    return $blocks[0]['blockName'];
}

二、拆解侦探的办案流程

  1. 确认身份:get_post( $post )

    首先,函数要确认它要侦查的是哪个文章。 get_post() 函数负责把传入的参数(文章ID或者文章对象)转化为一个标准的 WP_Post 对象。 如果传入的是空值,它就尝试使用全局的 $post 对象。 如果最终还是没找到文章,那说明无案可查,直接返回 null

    $post = get_post( $post );
    
    if ( ! $post ) {
        return null;
    }

    简单来说,这段代码就是确保我们手里有一个有效的文章对象,没有文章,侦查个寂寞。

  2. 提取证据:parse_blocks( $post->post_content )

    这是最关键的一步! parse_blocks() 函数负责把文章的内容($post->post_content)分解成一个区块数组。 这个函数会扫描文章内容,找到那些符合区块格式的字符串,然后把它们解析成一个个独立的区块对象。

    $blocks = parse_blocks( $post->post_content );
    
    if ( ! $blocks ) {
        return null;
    }
    • parse_blocks() 的工作原理 (简述)

      parse_blocks() 函数内部使用了正则表达式来匹配区块的开始和结束标记,然后提取区块的属性和内容。 区块的格式通常是这样的:

      <!-- wp:core/paragraph -->
      <p>这是一个段落。</p>
      <!-- /wp:core/paragraph -->

      parse_blocks() 会识别 <!-- wp:core/paragraph --> 这个标记,知道这是一个 core/paragraph 类型的区块,然后提取 <p>这是一个段落。</p> 作为区块的内容。

      如果文章内容不是标准的区块格式,parse_blocks() 可能无法正确解析,返回一个空数组。

  3. 锁定嫌疑人:$blocks[0]['blockName']

    现在我们有了一个区块数组($blocks)。 get_post_block_type() 只关心第一个区块的类型,所以它直接访问 $blocks[0]['blockName']blockName 属性存储了区块的类型(例如 core/paragraphcore/image 等)。

    if ( ! isset( $blocks[0]['blockName'] ) ) {
        return null;
    }
    
    return $blocks[0]['blockName'];

    如果 $blocks 数组为空(说明文章里没有区块),或者第一个区块没有 blockName 属性(这种情况不应该发生,除非区块数据损坏了),函数就返回 null

  4. 宣布结果:return $blocks[0]['blockName']return null

    最后,函数把找到的区块类型($blocks[0]['blockName'])返回。 如果没找到任何区块,或者文章内容为空,它就返回 null

三、举几个栗子:实战演练

为了更好地理解 get_post_block_type() 的工作方式,咱们来模拟几种不同的文章内容,看看函数会返回什么。

文章内容 get_post_block_type() 的返回值 说明
<!-- wp:core/paragraph --><p>这是一个段落。</p><!-- /wp:core/paragraph --> core/paragraph 文章开头是一个段落区块。
<!-- wp:core/image {"id":123,"url":"example.com/image.jpg"} --><img src="example.com/image.jpg" alt=""/> <!-- /wp:core/image --><!-- wp:core/paragraph --> core/image 文章开头是一个图片区块。
这是一段普通的文本,不是区块。 null 文章内容不是标准的区块格式,parse_blocks() 无法解析出任何区块。
` |null` 文章内容为空。
<!-- wp:core/paragraph --><p>这是一个段落。</p><!-- /wp:core/paragraph --><!-- wp:core/heading --><h2>这是一个标题</h2><!-- /wp:core/heading --> core/paragraph 文章开头是段落,即使后面有标题,也只返回第一个区块的类型。
<!-- wp:acf/my-custom-block {"data":{"field_1":"value_1"}} /--> acf/my-custom-block 文章开头是一个自定义区块(使用 ACF 创建的)。
<!-- wp:core/paragraph --><p>这是一个段落。</p><!-- /wp:core/paragraph --><!-- wp:missing/block --> core/paragraph 即使有缺失的区块,仍然会提取第一个有效的区块。

四、parse_blocks():区块解析的核心

正如前面提到的,parse_blocks()get_post_block_type() 的核心。 它负责把文章内容分解成区块数组。 虽然我们不会深入研究 parse_blocks() 的源码(因为它比较复杂),但了解它的基本原理非常重要。

parse_blocks() 主要做了以下几件事:

  1. 正则表达式匹配: 使用正则表达式找到文章内容中所有符合区块格式的字符串。 这些字符串通常以 <!-- wp: 开头,以 <!-- /wp: 结尾。

  2. 提取区块名称: 从匹配到的字符串中提取区块的名称(例如 core/paragraphcore/image)。

  3. 提取区块属性: 有些区块有属性(例如图片的 URL、段落的对齐方式)。 parse_blocks() 会尝试从区块的开始标记中提取这些属性。

  4. 提取区块内容: 区块的内容是指位于开始标记和结束标记之间的 HTML 代码。 parse_blocks() 会把这些 HTML 代码提取出来,作为区块的内容。

  5. 创建区块对象: 把提取到的区块名称、属性和内容组合成一个区块对象,并添加到区块数组中。

五、使用场景:get_post_block_type() 能帮我们做什么?

get_post_block_type() 虽然简单,但在某些情况下非常有用。

  1. 判断文章是否使用了区块编辑器:

    如果 get_post_block_type() 返回 null,说明文章内容可能不是用区块编辑器创建的,而是用经典编辑器或者其他方式创建的。

    $block_type = get_post_block_type();
    
    if ( $block_type === null ) {
        echo '这篇文章可能不是用区块编辑器创建的。';
    } else {
        echo '这篇文章是用区块编辑器创建的。';
    }
  2. 根据第一个区块的类型执行不同的操作:

    例如,如果文章的第一个区块是图片,你可以显示一个特殊的图片样式。

    $block_type = get_post_block_type();
    
    if ( $block_type === 'core/image' ) {
        echo '<div class="featured-image">';
        the_post_thumbnail();
        echo '</div>';
    } else {
        the_content();
    }
  3. 主题兼容性判断:

    在主题开发中,可以根据文章的第一个区块类型来加载不同的样式表或者 JavaScript 文件,以确保主题与各种类型的区块兼容。

六、注意事项:get_post_block_type() 的局限性

get_post_block_type() 只是一个简单的函数,它有一些局限性。

  1. 只返回第一个区块的类型:

    它不会告诉你文章里有多少个区块,也不会告诉你其他区块的类型。 如果你需要获取文章中所有区块的信息,你需要直接使用 parse_blocks() 函数,并遍历整个区块数组。

  2. 依赖于标准的区块格式:

    如果文章内容不是标准的区块格式,get_post_block_type() 可能无法正确解析。 例如,如果文章内容包含错误的 HTML 标签,或者区块的开始标记和结束标记不匹配,parse_blocks() 可能会返回错误的结果。

  3. 性能问题:

    虽然 get_post_block_type() 本身很快,但 parse_blocks() 函数可能会比较慢,特别是对于包含大量内容的文章。 如果你需要在循环中多次调用 get_post_block_type(),可能会影响网站的性能。 可以考虑使用缓存来优化性能。

七、高级技巧:自定义区块的识别

get_post_block_type() 可以识别 WordPress 内置的区块,也可以识别自定义的区块。 自定义区块通常使用 acf/ 或者其他命名空间作为前缀。

例如,如果你使用 ACF(Advanced Custom Fields)创建了一个名为 my-custom-block 的区块,get_post_block_type() 会返回 acf/my-custom-block

你可以根据自定义区块的类型来执行不同的操作。

$block_type = get_post_block_type();

if ( $block_type === 'acf/my-custom-block' ) {
    // 显示自定义区块的特殊样式
    echo '<div class="my-custom-block-wrapper">';
    // ...
    echo '</div>';
}

八、总结:get_post_block_type() 的价值

get_post_block_type() 函数虽然简单,但它提供了一种快速判断文章是否使用区块编辑器,以及获取文章第一个区块类型的方式。 在主题开发、插件开发和自定义 WordPress 功能时,它可以帮助你更好地处理不同类型的文章内容。

记住,get_post_block_type() 只是一个工具,你需要根据具体的需求来选择合适的工具。 如果你需要更详细的区块信息,你应该直接使用 parse_blocks() 函数。

希望这次的讲座能帮助你更好地理解 get_post_block_type() 函数的工作原理和使用场景。 祝大家编程愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注