分析 WordPress `WP_Block_Patterns_Registry` 类的源码:如何管理所有注册的区块模式。

大家好,欢迎来到今天的“WordPress区块模式管理揭秘”讲座。我是你们今天的向导,带大家一起扒一扒WordPress WP_Block_Patterns_Registry 类的裤子,看看它到底是如何管理那些花里胡哨的区块模式的。

准备好了吗?咱们这就开始!

开场白:区块模式,不再是“熟悉的陌生人”

话说,自从Gutenberg编辑器横空出世,WordPress就变得越来越“积木化”了。区块成了构建页面的基本单元,而区块模式,则是预先设计好的区块组合,可以让你快速构建各种常见的页面布局。

想想以前,要实现一个复杂的布局,得写多少HTML、CSS,甚至还要折腾PHP。现在呢?轻轻一点,一个漂亮的“关于我们”区块模式就出现在你的页面上了。简直不要太爽!

但是,你有没有想过,这些区块模式是从哪里来的?又是如何被WordPress管理的呢?答案就在WP_Block_Patterns_Registry这个类里面。

WP_Block_Patterns_Registry: 区块模式的“户籍管理中心”

你可以把WP_Block_Patterns_Registry 类想象成一个“户籍管理中心”,专门负责管理所有注册的区块模式。它提供了一系列方法,让你能够注册、注销、获取区块模式,以及查询特定区块模式的信息。

咱们先来简单看看这个类的结构:

<?php

/**
 * Class WP_Block_Patterns_Registry
 *
 * @since 5.5.0
 */
class WP_Block_Patterns_Registry {

    /**
     * Registered block patterns.
     *
     * @since 5.5.0
     * @var array
     */
    private $registered_block_patterns = array();

    /**
     * Registers a block pattern.
     *
     * @since 5.5.0
     *
     * @param string $pattern_name Block pattern name including namespace.
     * @param array  $pattern_properties Array containing the properties for the block pattern.
     * @return bool True if the block pattern was registered successfully, false otherwise.
     */
    public function register( $pattern_name, $pattern_properties ) {
        // ... (具体代码稍后讲解)
    }

    /**
     * Unregisters a block pattern.
     *
     * @since 5.5.0
     *
     * @param string $pattern_name Block pattern name including namespace.
     * @return bool True if the block pattern was unregistered successfully, false otherwise.
     */
    public function unregister( $pattern_name ) {
        // ... (具体代码稍后讲解)
    }

    /**
     * Retrieves a registered block pattern.
     *
     * @since 5.5.0
     *
     * @param string $pattern_name Block pattern name including namespace.
     * @return array|null Array containing the properties for the block pattern, or null if the
     *                    block pattern is not registered.
     */
    public function get( $pattern_name ) {
        // ... (具体代码稍后讲解)
    }

    /**
     * Retrieves all registered block patterns.
     *
     * @since 5.5.0
     *
     * @return array An array of registered block patterns.
     */
    public function get_all_registered() {
        // ... (具体代码稍后讲解)
    }

    /**
     * Determines if a block pattern is registered.
     *
     * @since 5.5.0
     *
     * @param string $pattern_name Block pattern name including namespace.
     * @return bool True if the block pattern is registered, false otherwise.
     */
    public function is_registered( $pattern_name ) {
        // ... (具体代码稍后讲解)
    }
}

可以看到,这个类主要包含一个私有属性 $registered_block_patterns 和五个公有方法 register(), unregister(), get(), get_all_registered(), is_registered()

接下来,咱们逐一分析这些方法,看看它们是如何工作的。

1. register(): 区块模式“入户”登记

register() 方法用于注册一个新的区块模式。它的作用就像是给一个新生的宝宝办理“入户”手续。

    public function register( $pattern_name, $pattern_properties ) {
        if ( ! is_string( $pattern_name ) ) {
            _doing_it_wrong(
                __METHOD__,
                sprintf(
                    /* translators: %s: Pattern name. */
                    __( 'Block pattern name must be a string. "%s" was passed.' ),
                    gettype( $pattern_name )
                ),
                '5.5.0'
            );
            return false;
        }

        if ( ! is_array( $pattern_properties ) ) {
            _doing_it_wrong(
                __METHOD__,
                sprintf(
                    /* translators: %s: Pattern properties. */
                    __( 'Block pattern properties must be an array. "%s" was passed.' ),
                    gettype( $pattern_properties )
                ),
                '5.5.0'
            );
            return false;
        }

        if ( empty( $pattern_name ) ) {
            _doing_it_wrong( __METHOD__, __( 'Block pattern name cannot be empty.' ), '5.5.0' );
            return false;
        }

        if ( isset( $this->registered_block_patterns[ $pattern_name ] ) ) {
            /* translators: %s: Pattern name. */
            _doing_it_wrong( __METHOD__, sprintf( __( 'Block pattern "%s" is already registered.' ), $pattern_name ), '5.5.0' );
            return false;
        }

        if ( ! isset( $pattern_properties['content'] ) || ! is_string( $pattern_properties['content'] ) ) {
            _doing_it_wrong( __METHOD__, __( 'Block pattern content must be a string.' ), '5.5.0' );
            return false;
        }

        $this->registered_block_patterns[ $pattern_name ] = $pattern_properties;

        return true;
    }

这个方法接收两个参数:

  • $pattern_name: 区块模式的名称,必须是一个字符串,并且要包含命名空间,例如 'my-plugin/my-pattern'
  • $pattern_properties: 一个数组,包含区块模式的各种属性,例如标题、内容、类别等。

注册流程详解:

  1. 参数类型校验: 首先,register() 方法会检查 $pattern_name$pattern_properties 的类型,确保它们分别是字符串和数组。如果类型不正确,会触发一个 _doing_it_wrong() 函数,并返回 false_doing_it_wrong() 函数是WordPress用来提示开发者代码中存在潜在问题的工具,它会在调试模式下显示警告信息。

  2. 名称非空校验: 接着,它会检查 $pattern_name 是否为空字符串。如果是,也会触发一个 _doing_it_wrong() 函数,并返回 false

  3. 重复注册校验: 然后,它会检查 $pattern_name 是否已经存在于 $registered_block_patterns 数组中。如果已经存在,说明该区块模式已经被注册过了,会触发一个 _doing_it_wrong() 函数,并返回 false

  4. 内容校验: 接下来,它会检查 $pattern_properties 数组中是否包含 content 键,并且 content 键的值是否是一个字符串。content 属性是区块模式的核心,它包含了区块模式的HTML代码。如果 content 不存在或者不是字符串,也会触发一个 _doing_it_wrong() 函数,并返回 false

  5. 注册: 最后,如果所有校验都通过了,register() 方法会将 $pattern_name 作为键,$pattern_properties 作为值,存储到 $registered_block_patterns 数组中。然后返回 true,表示注册成功。

$pattern_properties 数组的结构:

$pattern_properties 数组可以包含以下键:

类型 描述 是否必须
title string 区块模式的标题,用于在区块插入器中显示。 必须
content string 区块模式的HTML代码,用于渲染区块模式。 必须
categories array 一个字符串数组,包含区块模式所属的类别。这些类别用于在区块插入器中过滤区块模式。 可选
description string 区块模式的描述,用于在区块插入器中显示。 可选
keywords array 一个字符串数组,包含区块模式的关键词。这些关键词用于在区块插入器中搜索区块模式。 可选
viewportWidth int 区块模式在区块插入器中的预览宽度。 可选
blockTypes array 一个字符串数组,包含可以插入此区块模式的区块类型。 可选

注册示例:

add_action( 'init', 'my_plugin_register_block_patterns' );

function my_plugin_register_block_patterns() {
    if ( function_exists( 'register_block_pattern' ) ) {
        register_block_pattern(
            'my-plugin/my-awesome-pattern',
            array(
                'title'       => __( 'My Awesome Pattern', 'my-plugin' ),
                'categories'  => array( 'buttons' ),
                'description' => _x( 'A pattern featuring a cool button.', 'Block pattern description', 'my-plugin' ),
                'content'     => '<!-- wp:buttons --><div class="wp-block-buttons"><!-- wp:button {"backgroundColor":"primary"} --><div class="wp-block-button"><a href="#" class="wp-block-button__link has-primary-background-color wp-element-button">Click Me</a></div><!-- /wp:button --></div><!-- /wp:buttons -->',
            )
        );
    }
}

在这个例子中,我们使用 register_block_pattern() 函数来注册一个名为 'my-plugin/my-awesome-pattern' 的区块模式。这个区块模式包含一个标题、一个类别、一个描述和一个包含一个按钮的HTML代码。

register_block_pattern() 函数的幕后英雄:

你可能会好奇,上面的例子中用到的 register_block_pattern() 函数是从哪里来的?其实,它只是一个简单的封装函数,用于获取 WP_Block_Patterns_Registry 类的实例,并调用其 register() 方法。

if ( ! function_exists( 'register_block_pattern' ) ) {
    /**
     * Registers a block pattern.
     *
     * @since 5.5.0
     *
     * @param string $pattern_name Block pattern name including namespace.
     * @param array  $pattern_properties Array containing the properties for the block pattern.
     * @return bool True if the block pattern was registered successfully, false otherwise.
     */
    function register_block_pattern( $pattern_name, $pattern_properties ) {
        return WP_Block_Patterns_Registry::get_instance()->register( $pattern_name, $pattern_properties );
    }
}

可以看到,register_block_pattern() 函数首先通过 WP_Block_Patterns_Registry::get_instance() 获取 WP_Block_Patterns_Registry 类的单例实例,然后调用该实例的 register() 方法来注册区块模式。

2. unregister(): 区块模式“注销户口”

unregister() 方法用于注销一个已经注册的区块模式。它的作用就像是给一个去世的人办理“户口注销”手续。

    public function unregister( $pattern_name ) {
        if ( ! is_string( $pattern_name ) ) {
            _doing_it_wrong(
                __METHOD__,
                sprintf(
                    /* translators: %s: Pattern name. */
                    __( 'Block pattern name must be a string. "%s" was passed.' ),
                    gettype( $pattern_name )
                ),
                '5.5.0'
            );
            return false;
        }

        if ( empty( $pattern_name ) ) {
            _doing_it_wrong( __METHOD__, __( 'Block pattern name cannot be empty.' ), '5.5.0' );
            return false;
        }

        if ( ! isset( $this->registered_block_patterns[ $pattern_name ] ) ) {
            /* translators: %s: Pattern name. */
            _doing_it_wrong( __METHOD__, sprintf( __( 'Block pattern "%s" is not registered.' ), $pattern_name ), '5.5.0' );
            return false;
        }

        unset( $this->registered_block_patterns[ $pattern_name ] );

        return true;
    }

这个方法接收一个参数:

  • $pattern_name: 要注销的区块模式的名称,必须是一个字符串,并且要包含命名空间。

注销流程详解:

  1. 参数类型校验: 首先,unregister() 方法会检查 $pattern_name 的类型,确保它是一个字符串。如果类型不正确,会触发一个 _doing_it_wrong() 函数,并返回 false

  2. 名称非空校验: 接着,它会检查 $pattern_name 是否为空字符串。如果是,也会触发一个 _doing_it_wrong() 函数,并返回 false

  3. 存在校验: 然后,它会检查 $pattern_name 是否存在于 $registered_block_patterns 数组中。如果不存在,说明该区块模式没有被注册过,会触发一个 _doing_it_wrong() 函数,并返回 false

  4. 注销: 最后,如果所有校验都通过了,unregister() 方法会使用 unset() 函数从 $registered_block_patterns 数组中删除 $pattern_name 对应的元素。然后返回 true,表示注销成功。

注销示例:

add_action( 'init', 'my_plugin_unregister_block_patterns' );

function my_plugin_unregister_block_patterns() {
    if ( function_exists( 'unregister_block_pattern' ) ) {
        unregister_block_pattern( 'my-plugin/my-awesome-pattern' );
    }
}

在这个例子中,我们使用 unregister_block_pattern() 函数来注销一个名为 'my-plugin/my-awesome-pattern' 的区块模式。

unregister_block_pattern() 函数:

register_block_pattern() 函数类似,unregister_block_pattern() 函数也是一个简单的封装函数,用于获取 WP_Block_Patterns_Registry 类的实例,并调用其 unregister() 方法。

if ( ! function_exists( 'unregister_block_pattern' ) ) {
    /**
     * Unregisters a block pattern.
     *
     * @since 5.5.0
     *
     * @param string $pattern_name Block pattern name including namespace.
     * @return bool True if the block pattern was unregistered successfully, false otherwise.
     */
    function unregister_block_pattern( $pattern_name ) {
        return WP_Block_Patterns_Registry::get_instance()->unregister( $pattern_name );
    }
}

3. get(): 获取区块模式信息

get() 方法用于获取一个已经注册的区块模式的信息。它的作用就像是根据“户口本”上的信息查询某个人的详细资料。

    public function get( $pattern_name ) {
        if ( ! is_string( $pattern_name ) ) {
            _doing_it_wrong(
                __METHOD__,
                sprintf(
                    /* translators: %s: Pattern name. */
                    __( 'Block pattern name must be a string. "%s" was passed.' ),
                    gettype( $pattern_name )
                ),
                '5.5.0'
            );
            return null;
        }

        if ( empty( $pattern_name ) ) {
            _doing_it_wrong( __METHOD__, __( 'Block pattern name cannot be empty.' ), '5.5.0' );
            return null;
        }

        if ( ! isset( $this->registered_block_patterns[ $pattern_name ] ) ) {
            return null;
        }

        return $this->registered_block_patterns[ $pattern_name ];
    }

这个方法接收一个参数:

  • $pattern_name: 要获取信息的区块模式的名称,必须是一个字符串,并且要包含命名空间。

获取流程详解:

  1. 参数类型校验: 首先,get() 方法会检查 $pattern_name 的类型,确保它是一个字符串。如果类型不正确,会触发一个 _doing_it_wrong() 函数,并返回 null

  2. 名称非空校验: 接着,它会检查 $pattern_name 是否为空字符串。如果是,也会触发一个 _doing_it_wrong() 函数,并返回 null

  3. 存在校验: 然后,它会检查 $pattern_name 是否存在于 $registered_block_patterns 数组中。如果不存在,说明该区块模式没有被注册过,返回 null

  4. 获取信息: 最后,如果所有校验都通过了,get() 方法会返回 $registered_block_patterns 数组中 $pattern_name 对应的元素,也就是区块模式的属性数组。

获取示例:

虽然没有直接的函数像get_block_pattern,但是你可以通过WP_Block_Patterns_Registry::get_instance()->get() 来获取。

$pattern = WP_Block_Patterns_Registry::get_instance()->get( 'my-plugin/my-awesome-pattern' );

if ( $pattern ) {
    echo 'Title: ' . esc_html( $pattern['title'] ) . '<br>';
    echo 'Content: ' . esc_html( $pattern['content'] ) . '<br>';
} else {
    echo 'Pattern not found.';
}

4. get_all_registered(): 获取所有区块模式信息

get_all_registered() 方法用于获取所有已经注册的区块模式的信息。它的作用就像是获取整个“户籍管理中心”的所有“户口本”信息。

    public function get_all_registered() {
        return $this->registered_block_patterns;
    }

这个方法非常简单,它直接返回 $registered_block_patterns 数组,也就是包含了所有已注册区块模式的属性数组的数组。

获取示例:

$patterns = WP_Block_Patterns_Registry::get_instance()->get_all_registered();

foreach ( $patterns as $pattern_name => $pattern ) {
    echo 'Pattern Name: ' . esc_html( $pattern_name ) . '<br>';
    echo 'Title: ' . esc_html( $pattern['title'] ) . '<br>';
    // ... 更多信息
}

5. is_registered(): 判断区块模式是否已注册

is_registered() 方法用于判断一个区块模式是否已经被注册。它的作用就像是查询“户籍管理中心”是否存在某个人的“户口”。

    public function is_registered( $pattern_name ) {
        if ( ! is_string( $pattern_name ) ) {
            _doing_it_wrong(
                __METHOD__,
                sprintf(
                    /* translators: %s: Pattern name. */
                    __( 'Block pattern name must be a string. "%s" was passed.' ),
                    gettype( $pattern_name )
                ),
                '5.5.0'
            );
            return false;
        }

        if ( empty( $pattern_name ) ) {
            _doing_it_wrong( __METHOD__, __( 'Block pattern name cannot be empty.' ), '5.5.0' );
            return false;
        }

        return isset( $this->registered_block_patterns[ $pattern_name ] );
    }

这个方法接收一个参数:

  • $pattern_name: 要判断的区块模式的名称,必须是一个字符串,并且要包含命名空间。

判断流程详解:

  1. 参数类型校验: 首先,is_registered() 方法会检查 $pattern_name 的类型,确保它是一个字符串。如果类型不正确,会触发一个 _doing_it_wrong() 函数,并返回 false

  2. 名称非空校验: 接着,它会检查 $pattern_name 是否为空字符串。如果是,也会触发一个 _doing_it_wrong() 函数,并返回 false

  3. 判断是否存在: 最后,is_registered() 方法会使用 isset() 函数检查 $pattern_name 是否存在于 $registered_block_patterns 数组中。如果存在,返回 true,否则返回 false

判断示例:

if ( WP_Block_Patterns_Registry::get_instance()->is_registered( 'my-plugin/my-awesome-pattern' ) ) {
    echo 'Pattern is registered.';
} else {
    echo 'Pattern is not registered.';
}

WP_Block_Patterns_Registry::get_instance(): 单例模式的妙用

细心的你可能已经发现了,在上面的所有示例中,我们都是通过 WP_Block_Patterns_Registry::get_instance() 来获取 WP_Block_Patterns_Registry 类的实例的。

这是因为 WP_Block_Patterns_Registry 类使用了单例模式。单例模式保证了在整个应用程序中,WP_Block_Patterns_Registry 类只有一个实例存在。这可以避免重复创建实例,节省内存,并且方便管理所有的区块模式。

WP_Block_Patterns_Registry 类的 get_instance() 方法如下:

    /**
     * Gets the instance of the class.
     *
     * @since 5.5.0
     *
     * @return WP_Block_Patterns_Registry The instance of the class.
     */
    public static function get_instance() {
        static $instance = null;

        if ( is_null( $instance ) ) {
            $instance = new self();
        }

        return $instance;
    }

可以看到,get_instance() 方法使用了一个静态变量 $instance 来保存类的实例。如果 $instancenull,则创建一个新的实例,并将其赋值给 $instance。否则,直接返回 $instance

总结:WP_Block_Patterns_Registry 类的核心作用

WP_Block_Patterns_Registry 类是WordPress区块模式管理的核心。它提供了一套完整的API,让你能够方便地注册、注销、获取区块模式,以及查询特定区块模式的信息。

通过理解 WP_Block_Patterns_Registry 类的源码,你可以更好地理解WordPress是如何管理区块模式的,并且可以更灵活地使用区块模式来构建你的网站。

一些额外的思考:

  • 区块模式的存储方式: WP_Block_Patterns_Registry 类只是负责管理区块模式的注册信息,并没有负责存储区块模式的HTML代码。区块模式的HTML代码通常存储在主题或插件的文件中。

  • 区块模式的类别: 区块模式的类别可以用于在区块插入器中过滤区块模式。WordPress提供了一些默认的区块模式类别,你也可以自定义区块模式类别。

  • 区块模式的动态生成: 你可以使用PHP代码动态生成区块模式的HTML代码,这可以让你创建更灵活的区块模式。

好了,今天的讲座就到这里。希望大家通过今天的学习,对WordPress WP_Block_Patterns_Registry 类有了更深入的了解。下次再见!

发表回复

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