解析 WordPress `gutenberg_post_has_blocks()` 函数源码:如何判断一篇文章是否包含 Gutenberg 区块。

大家好,我是你们今天的区块解剖师!今天咱们来聊聊 WordPress 里一个非常实用的函数:gutenberg_post_has_blocks()。它就像一个区块雷达,专门用来探测你的文章里有没有 Gutenberg 区块的痕迹。

准备好了吗?咱们这就开始解剖它,看看它是怎么运作的!

一、为什么要判断有没有 Gutenberg 区块?

想象一下,你是一个网站的开发者,需要根据文章内容的不同,来加载不同的样式或者脚本。比如,如果文章里有 Gutenberg 区块,你可能需要加载 Gutenberg 相关的 CSS 和 JavaScript 文件,如果没有,就可以省掉这部分资源,提高页面加载速度。

又或者,你需要对老的经典编辑器文章和新的 Gutenberg 文章做一些兼容性处理,这时,判断文章里有没有 Gutenberg 区块就显得至关重要了。

二、gutenberg_post_has_blocks() 函数的源码

先让我们来看看这个函数的真面目(这是 WordPress 官方提供的代码,我们主要分析其逻辑):

<?php

/**
 * Checks if the content contains block(s).
 *
 * @since 5.0.0
 *
 * @param mixed $content Content to test.  May be post content or string.
 * @return bool Whether the content contains block(s).
 */
function gutenberg_post_has_blocks( $content ) {
    if ( ! is_string( $content ) ) {
        return false;
    }

    return false !== strpos( $content, '<!-- wp:' );
}

是不是很简单?简单到让你觉得是不是被骗了?别急,简单背后蕴藏着巧妙的逻辑。

三、源码解读:一行代码的奥秘

让我们逐行解读这段代码:

  1. function gutenberg_post_has_blocks( $content ): 定义了一个名为 gutenberg_post_has_blocks 的函数,它接受一个参数 $content,这个参数就是我们要检查的文章内容。

  2. if ( ! is_string( $content ) ) { return false; }: 这是一个类型检查。如果传入的 $content 不是字符串,那直接返回 false。毕竟,我们也没法从一个数字或者数组里找到区块。

  3. return false !== strpos( $content, '<!-- wp:' );: 这才是核心的一行代码!它使用了 PHP 的 strpos() 函数,在 $content 中查找 '<!-- wp:' 这个字符串。

    • strpos( $content, '<!-- wp:' ): strpos() 函数的作用是在字符串 $content 中查找 '<!-- wp:' 第一次出现的位置。如果找到了,就返回该位置的索引(从 0 开始);如果没找到,就返回 false
    • false !== ...: 这里使用了严格不等于运算符 !==,来判断 strpos() 的返回值是否不等于 false。 为什么要用 !== 而不是 != 呢? 因为 strpos() 返回的位置索引可能是 0,而 0 != false 的结果是 false, 这会导致误判。 使用 !== 可以确保只有当 strpos() 确实返回 false 时,才返回 false

四、 '<!-- wp:' 是什么? 为什么用它来判断区块?

'<!-- wp:' 是 Gutenberg 区块的起始标记。每一个 Gutenberg 区块在文章内容中,都会以这个标记开头。例如:

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

所以,只要文章内容中包含 '<!-- wp:',就说明这篇文章使用了 Gutenberg 区块。

五、实例演示:代码实战

让我们来写一段代码,演示一下 gutenberg_post_has_blocks() 函数的用法:

<?php

// 假设这是从数据库里取出来的文章内容
$content_with_blocks = '<h1>文章标题</h1><!-- wp:paragraph --><p>这是一个段落区块。</p><!-- /wp:paragraph -->';
$content_without_blocks = '<h1>文章标题</h1><p>这是一个普通的 HTML 段落。</p>';

// 使用 gutenberg_post_has_blocks() 函数判断文章内容是否包含 Gutenberg 区块
if ( gutenberg_post_has_blocks( $content_with_blocks ) ) {
    echo "这篇文章使用了 Gutenberg 区块。n";
} else {
    echo "这篇文章没有使用 Gutenberg 区块。n";
}

if ( gutenberg_post_has_blocks( $content_without_blocks ) ) {
    echo "这篇文章使用了 Gutenberg 区块。n";
} else {
    echo "这篇文章没有使用 Gutenberg 区块。n";
}

?>

这段代码的输出结果应该是:

这篇文章使用了 Gutenberg 区块。
这篇文章没有使用 Gutenberg 区块。

六、更复杂的场景:处理转义字符

有时候,文章内容中的 '<!-- wp:' 可能会被转义成 '&lt;!-- wp:'。 为了更准确地判断,我们可以先对文章内容进行反转义处理:

<?php

$content_with_escaped_blocks = '<h1>文章标题</h1>&lt;!-- wp:paragraph --&gt;<p>这是一个段落区块。</p>&lt;!-- /wp:paragraph --&gt;';

// 先对文章内容进行反转义处理
$content_with_blocks = html_entity_decode( $content_with_escaped_blocks );

// 然后再使用 gutenberg_post_has_blocks() 函数判断
if ( gutenberg_post_has_blocks( $content_with_blocks ) ) {
    echo "这篇文章使用了 Gutenberg 区块。n";
} else {
    echo "这篇文章没有使用 Gutenberg 区块。n";
}

?>

这里使用了 PHP 的 html_entity_decode() 函数,将 HTML 实体(例如 '&lt;')转换成对应的字符(例如 '<')。

七、性能考量:缓存结果

如果需要频繁地判断文章是否包含 Gutenberg 区块,可以考虑缓存 gutenberg_post_has_blocks() 函数的结果,以提高性能。例如:

<?php

function my_post_has_blocks( $post_id ) {
    // 尝试从缓存中获取结果
    $has_blocks = wp_cache_get( 'my_post_has_blocks_' . $post_id, 'my_plugin' );

    // 如果缓存中没有结果,则计算结果并缓存
    if ( false === $has_blocks ) {
        $post = get_post( $post_id );
        if ( $post ) {
            $has_blocks = gutenberg_post_has_blocks( $post->post_content );
        } else {
            $has_blocks = false; // 如果文章不存在,则返回 false
        }

        // 将结果缓存起来,有效期为 1 小时
        wp_cache_set( 'my_post_has_blocks_' . $post_id, $has_blocks, 'my_plugin', 3600 );
    }

    return $has_blocks;
}

// 使用示例
$post_id = get_the_ID();
if ( my_post_has_blocks( $post_id ) ) {
    echo "这篇文章使用了 Gutenberg 区块。n";
} else {
    echo "这篇文章没有使用 Gutenberg 区块。n";
}

?>

这段代码使用了 WordPress 的 wp_cache_get()wp_cache_set() 函数,来实现缓存功能。

八、替代方案:使用 has_blocks() 函数

WordPress 5.0 之后,官方提供了一个更简洁的函数 has_blocks(),可以直接判断文章内容是否包含区块:

<?php

if ( has_blocks() ) {
    echo "这篇文章使用了 Gutenberg 区块。n";
} else {
    echo "这篇文章没有使用 Gutenberg 区块。n";
}

?>

has_blocks() 函数的内部实现和 gutenberg_post_has_blocks() 函数类似,也是通过查找 '<!-- wp:' 标记来判断的。不过,has_blocks() 函数会自动获取当前文章的内容,所以不需要手动传入 $content 参数。

九、总结:小函数,大作用

gutenberg_post_has_blocks() 函数(以及 has_blocks() 函数)虽然代码简单,但却非常实用。 它可以帮助我们判断文章是否使用了 Gutenberg 区块,从而可以根据不同的情况来加载不同的资源,或者进行不同的处理。

让我们用一个表格来总结一下今天的内容:

函数名 作用 参数 返回值 备注
gutenberg_post_has_blocks() 判断文章内容是否包含 Gutenberg 区块 $content true/false 需要手动传入文章内容。
has_blocks() 判断当前文章是否包含 Gutenberg 区块 true/false 自动获取当前文章的内容。WordPress 5.0 之后可用。
strpos() 在字符串中查找指定字符串第一次出现的位置 $haystack, $needle 索引/false $haystack 是要查找的字符串,$needle 是要查找的子字符串。
html_entity_decode() 将 HTML 实体转换为对应的字符 $string 字符串 用于处理文章内容中被转义的 '<!-- wp:' 标记。
wp_cache_get() 从缓存中获取数据 $key, $group 数据/false WordPress 缓存 API。
wp_cache_set() 将数据存储到缓存中 $key, $data, $group, $expire true/false WordPress 缓存 API。

希望今天的讲解能够帮助大家更好地理解 gutenberg_post_has_blocks() 函数的原理和用法。 以后遇到需要判断文章是否包含 Gutenberg 区块的场景,就可以轻松应对啦!

有什么问题吗? 尽管提问! 我会尽力解答!

发表回复

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