WordPress源码深度解析之:`WordPress`的`Metabox API`:`add_meta_box()`函数的底层实现。

各位观众老爷们,晚上好!今天咱们来聊聊WordPress里一个神奇的玩意儿,叫做Meta Box API。具体来说,咱们要深入扒一扒add_meta_box()这个函数的底裤,看看它到底是怎么运作的。

一、Meta Box是啥?好吃吗?

首先,咱得搞清楚Meta Box是啥。如果你用过WordPress后台,一定见过文章编辑页面里那些花花绿绿的小框框,比如“作者”、“摘要”、“自定义字段”等等。这些小框框,就叫做Meta Box,中文名叫“元数据框”。

Meta Box的作用是让你添加、编辑和展示与文章、页面、自定义文章类型等内容相关的额外信息,也就是元数据。它可以让你在标准的内容编辑区域之外,提供更丰富、更灵活的输入和展示方式。

二、add_meta_box():一切的起点

add_meta_box()函数是Meta Box API的核心,是咱们添加Meta Box的入口。它的原型是这样的:

add_meta_box(
    string   $id,
    string   $title,
    callable $callback,
    string|array|WP_Screen $screen = null,
    string   $context = 'advanced',
    string   $priority = 'default',
    array    $callback_args = null
);

参数解释:

| 参数名 | 类型 | 描述 |
| id | string | Meta Box的唯一ID,用于区分不同的Meta Box。 beibi的,今天咱们就来干点正事,扒一扒add_meta_box()这个函数的底裤。

三、add_meta_box()都干了啥?

add_meta_box(),顾名思义,就是添加Meta Box的嘛。但是它到底干了啥呢?我们来一步一步分析。

  1. 参数处理

    首先,add_meta_box()会对我们传入的参数进行一些处理,比如检查参数类型、设置默认值等等。最重要的是,它会把$screen参数统一成数组。如果$screen是字符串,就把它放到一个数组里;如果是WP_Screen对象,就通过get_id()方法获取其ID,然后放到数组里。

  2. 全局变量$wp_meta_boxes

    add_meta_box()的核心是将Meta Box的信息存储到一个全局变量$wp_meta_boxes中。这个变量是一个多维数组,它的结构大致如下:

    $wp_meta_boxes[ $screen ][ $context ][ $priority ][ $id ] = array(
        'id'       => $id,
        'title'    => $title,
        'callback' => $callback,
        'args'     => $callback_args,
    );
    • $screen:屏幕ID,比如postpageedit-post等,表示Meta Box显示在哪个页面。
    • $context:Meta Box的上下文,也就是在页面的哪个区域显示,比如normal(正常区域)、advanced(高级区域)、side(侧边栏)。
    • $priority:Meta Box的优先级,决定了在同一区域内的显示顺序,比如highcoredefaultlow
    • $id:Meta Box的唯一ID。
    • 'id', 'title', 'callback', 'args':存储了我们传入的Meta Box的各种信息。
  3. 钩子函数add_action('add_meta_boxes', 'add_meta_boxes')

    add_meta_box()本身并没有直接渲染Meta Box的功能,它只是将Meta Box的信息存储起来。真正渲染Meta Box的工作,是在add_meta_boxes这个钩子函数里完成的。add_meta_box()会触发add_meta_boxes这个action,然后由其他函数来处理这个action,最终将Meta Box渲染到页面上。

四、add_meta_boxes:渲染Meta Box的大功臣

add_meta_boxes这个钩子函数非常重要,它是Meta Box渲染的入口。WordPress会根据当前页面,触发相应的add_meta_boxes钩子,然后执行绑在这个钩子上的函数。

通常,我们会在add_meta_boxes钩子上绑定一个自定义的函数,在这个函数里调用add_meta_box()来添加Meta Box。例如:

add_action( 'add_meta_boxes', 'my_add_meta_boxes' );
function my_add_meta_boxes( $post ) {
    add_meta_box(
        'my_meta_box',
        '我的Meta Box',
        'my_meta_box_callback',
        'post',
        'normal',
        'default'
    );
}

function my_meta_box_callback( $post ) {
    echo '<label for="my_meta_box_field">字段:</label>';
    echo '<input type="text" id="my_meta_box_field" name="my_meta_box_field" value="' . esc_attr( get_post_meta( $post->ID, 'my_meta_box_field', true ) ) . '" />';
}

在这个例子中,my_add_meta_boxes函数会在add_meta_boxes钩子被触发时执行。它调用add_meta_box()添加了一个ID为my_meta_box的Meta Box,显示在post类型的文章编辑页面的normal区域,优先级为defaultmy_meta_box_callback函数负责渲染Meta Box的内容,这里只是简单地显示一个文本输入框。

五、do_meta_boxes():最终的渲染

edit-form-advanced.phpedit-form-page.php等模板文件中,会调用do_meta_boxes()函数来真正地渲染Meta Box。do_meta_boxes()函数的原型如下:

do_meta_boxes( string|WP_Screen $screen, string $context, WP_Post|null $post );

参数解释:

  • $screen:屏幕ID,比如postpage
  • $context:Meta Box的上下文,比如normaladvancedside
  • $post:当前文章对象。

do_meta_boxes()函数会根据传入的$screen$context,从全局变量$wp_meta_boxes中取出相应的Meta Box信息,然后循环遍历这些Meta Box,调用它们的callback函数来渲染内容。

六、add_meta_box()的源码剖析(简化版)

为了更深入地理解add_meta_box()的运作方式,我们来看一个简化版的源码实现:

function my_add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
    global $wp_meta_boxes;

    // 1. 参数处理
    if ( is_string( $screen ) ) {
        $screen = array( $screen );
    } elseif ( is_object( $screen ) && method_exists( $screen, 'get_id' ) ) {
        $screen = array( $screen->get_id() );
    }

    // 2. 默认值处理
    if ( empty( $screen ) ) {
        $screen = get_current_screen()->id;
    }

    // 3. 循环处理screen
    foreach ( (array) $screen as $single_screen ) {
        $single_screen = sanitize_key( $single_screen );

        // 4. 构建meta box信息
        $wp_meta_boxes[ $single_screen ][ $context ][ $priority ][ $id ] = array(
            'id'       => $id,
            'title'    => $title,
            'callback' => $callback,
            'args'     => $callback_args,
        );
    }

    return;
}

这个简化版的my_add_meta_box()函数,主要做了以下几件事情:

  1. 参数处理:将$screen参数统一转换成数组。
  2. 默认值处理:如果$screen为空,则使用当前屏幕的ID。
  3. 循环处理screen:循环遍历$screen数组,确保每个屏幕都添加了Meta Box。
  4. 构建meta box信息:将Meta Box的信息存储到全局变量$wp_meta_boxes中。

七、do_meta_boxes()的源码剖析(简化版)

同样,我们也来看一个简化版的do_meta_boxes()函数:

function my_do_meta_boxes( $screen, $context, $post ) {
    global $wp_meta_boxes;

    // 1. 检查是否存在对应的meta boxes
    if ( ! isset( $wp_meta_boxes[ $screen ][ $context ] ) ) {
        return;
    }

    // 2. 遍历优先级
    foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
        if ( isset( $wp_meta_boxes[ $screen ][ $context ][ $priority ] ) ) {

            // 3. 遍历meta boxes
            foreach ( (array) $wp_meta_boxes[ $screen ][ $context ][ $priority ] as $id => $meta_box ) {

                // 4. 调用callback函数渲染meta box内容
                call_user_func( $meta_box['callback'], $post, $meta_box['args'] );
            }
        }
    }

    return;
}

这个简化版的my_do_meta_boxes()函数,主要做了以下几件事情:

  1. 检查是否存在对应的meta boxes:检查全局变量$wp_meta_boxes中是否存在当前屏幕和上下文对应的Meta Box。
  2. 遍历优先级:按照优先级顺序遍历Meta Box。
  3. 遍历meta boxes:循环遍历当前优先级下的所有Meta Box。
  4. 调用callback函数渲染meta box内容:调用Meta Box的callback函数,并将当前文章对象和callback_args作为参数传递给callback函数。

八、Meta Box的保存

光显示Meta Box还不行,我们还需要保存Meta Box里的数据。通常,我们会使用save_post这个钩子函数来保存Meta Box的数据。例如:

add_action( 'save_post', 'my_save_meta_box_data' );
function my_save_meta_box_data( $post_id ) {

    // 1. 检查是否需要保存
    if ( ! isset( $_POST['my_meta_box_field'] ) ) {
        return;
    }

    // 2. 验证权限和安全
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    // 3. 数据清洗和保存
    $my_data = sanitize_text_field( $_POST['my_meta_box_field'] );
    update_post_meta( $post_id, 'my_meta_box_field', $my_data );
}

在这个例子中,my_save_meta_box_data函数会在文章保存时执行。它首先检查$_POST中是否存在my_meta_box_field字段,然后验证用户权限和安全,最后对数据进行清洗,并使用update_post_meta()函数将数据保存到文章的元数据中。

九、总结

总而言之,add_meta_box()函数只是将Meta Box的信息存储到全局变量$wp_meta_boxes中,真正渲染Meta Box的工作是由do_meta_boxes()函数完成的。而保存Meta Box的数据,则需要使用save_post钩子函数。

add_meta_box()do_meta_boxes()save_post这三个函数和钩子,共同构成了WordPress Meta Box API的核心。掌握了它们,你就可以轻松地创建自定义的Meta Box,为你的WordPress站点添加更丰富、更灵活的功能。

希望今天的讲解对大家有所帮助!如果有什么问题,欢迎提问。

发表回复

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