剖析 WordPress `register_rest_field()` 函数的源码:如何为 REST API 响应添加自定义字段。

大家好,今天咱们来聊聊 WordPress REST API 的“私人订制”:register_rest_field() 函数源码剖析

嗨,各位!今天咱们不开玩笑,直接上干货。咱们来扒一扒 WordPress REST API 里的一个关键函数—— register_rest_field()。它就像个魔法棒,能让你在 API 响应里添加自己想要的字段,想加啥加啥,简直不要太爽!

一、REST API 的“缺憾”与 register_rest_field() 的登场

话说 WordPress REST API 提供了各种各样的数据接口,方便我们获取文章、页面、用户等等信息。但是,有时候自带的字段可能不够用,比如:

  • 你想在文章里加个“阅读次数”字段。
  • 你想在用户里加个“个人简介”字段(假设这个简介不是标准的用户元数据)。
  • 你想根据某些条件计算出一个新的字段值。

这时候,光靠 WordPress 默认的 API 就没辙了,得自己动手丰衣足食。register_rest_field() 就是为此而生的,它允许我们注册自定义的 REST 字段,让 API 响应带上我们想要的额外信息。

二、register_rest_field() 的基本用法:手把手教你“私人订制”

register_rest_field() 函数的原型是这样的:

register_rest_field(
    string   $object_type,
    string   $attribute,
    array    $args
);
  • $object_type:指定你要往哪个对象类型里添加字段,比如 'post'(文章)、'page'(页面)、'user'(用户)等等。
  • $attribute:指定你自定义字段的名称,这个名称会出现在 API 响应里。
  • $args:一个数组,包含字段的获取、更新、权限控制等信息。

咱们先来个简单的例子,往文章里加个“阅读次数”字段,让 API 响应里显示每篇文章的阅读次数。

function my_register_rest_fields() {
    register_rest_field(
        'post', // 对象类型:文章
        'reading_count', // 字段名称:阅读次数
        array(
            'get_callback'    => 'my_get_post_reading_count', // 获取字段值的回调函数
            'update_callback' => null, // 更新字段值的回调函数,如果不需要更新,设为 null
            'schema'          => null, // 字段的 Schema,用于描述字段的数据类型和格式
        )
    );
}
add_action( 'rest_api_init', 'my_register_rest_fields' );

function my_get_post_reading_count( $object, $field_name, $request ) {
    // 获取文章的阅读次数(假设你已经有了一个获取阅读次数的函数)
    $reading_count = get_post_meta( $object['id'], 'reading_count', true );
    return intval( $reading_count ); // 确保返回的是整数
}

这段代码做了什么?

  1. my_register_rest_fields() 函数:
    • 调用 register_rest_field() 注册一个自定义字段。
    • 'post':指定了文章对象。
    • 'reading_count':指定了字段名称为 reading_count
    • 'get_callback':指定了获取字段值的回调函数为 my_get_post_reading_count()
    • 'update_callback':设置为 null,表示这个字段不能通过 API 更新。
    • 'schema':设置为 null,表示没有定义 Schema。
  2. my_get_post_reading_count() 函数:
    • 接收三个参数:$object(当前对象,比如文章)、$field_name(字段名称)、$request(请求对象)。
    • 通过 $object['id'] 获取文章 ID。
    • 调用 get_post_meta() 获取文章的 reading_count 元数据值。
    • 将值转换为整数并返回。
  3. add_action( 'rest_api_init', 'my_register_rest_fields' )
    • rest_api_init 钩子上注册 my_register_rest_fields() 函数,确保在 REST API 初始化时注册自定义字段。

现在,当你访问文章的 REST API 接口时(比如 /wp-json/wp/v2/posts/123),响应里就会多出一个 reading_count 字段,显示文章的阅读次数。

三、$args 数组详解:控制字段的方方面面

$args 数组是 register_rest_field() 函数的核心,它决定了字段的各种行为。咱们来详细看看 args 数组里可以包含哪些参数:

参数名 类型 描述
get_callback callable 必须。用于获取字段值的回调函数。接收三个参数:$object(当前对象)、$field_name(字段名称)、$request(请求对象)。必须返回字段的值。
update_callback callable 用于更新字段值的回调函数。接收三个参数:$value(要更新的值)、$object(当前对象)、$field_name(字段名称)。如果不需要更新,可以设为 null
schema array 用于描述字段的 Schema,包括字段的数据类型、格式、描述等信息。Schema 可以让 API 客户端更好地了解字段的含义和用法。
permission_callback callable 用于控制字段的访问权限的回调函数。接收一个参数:$request(请求对象)。必须返回 true(允许访问)或 false(禁止访问)。如果没有指定,默认情况下所有用户都可以访问该字段。
sanitize_callback callable 用于对要更新的值进行清理和验证的回调函数。接收一个参数:$value(要更新的值)。必须返回清理后的值。

1. get_callback:获取字段值

这个回调函数是必须要指定的,它决定了字段的值怎么来的。 咱们刚才的例子里已经用过了。再来个例子,获取文章的作者姓名:

function my_get_post_author_name( $object, $field_name, $request ) {
    $author_id = $object['author'];
    $author = get_user_by( 'id', $author_id );
    return $author->display_name;
}

register_rest_field(
    'post',
    'author_name',
    array(
        'get_callback'    => 'my_get_post_author_name',
        'update_callback' => null,
        'schema'          => null,
    )
);

2. update_callback:更新字段值

如果你希望可以通过 API 更新这个字段的值,就需要指定 update_callback。 比如,允许通过 API 修改文章的阅读次数:

function my_update_post_reading_count( $value, $object, $field_name ) {
    // 验证 $value 是否为整数
    if ( ! is_numeric( $value ) ) {
        return new WP_Error( 'invalid_reading_count', '阅读次数必须是数字', array( 'status' => 400 ) );
    }

    // 更新文章的阅读次数
    update_post_meta( $object->ID, 'reading_count', intval( $value ) );

    return true; // 必须返回 true,表示更新成功
}

register_rest_field(
    'post',
    'reading_count',
    array(
        'get_callback'    => 'my_get_post_reading_count',
        'update_callback' => 'my_update_post_reading_count',
        'schema'          => array(
            'type'        => 'integer',
            'description' => '文章的阅读次数',
            'context'     => array( 'view', 'edit' ), // 表示在 view 和 edit 上下文中都显示
            'arg_options' => array(
                'sanitize_callback' => 'absint', // 对输入的值进行清理,确保是正整数
            ),
        ),
    )
);

注意:

  • update_callback 的返回值必须是 true(表示更新成功)或者一个 WP_Error 对象(表示更新失败)。
  • schema 里定义了 arg_options,指定了 sanitize_callback,用于对输入的值进行清理,确保是正整数。

3. schema:描述字段的数据类型和格式

schema 用于描述字段的数据类型、格式、描述等信息,可以让 API 客户端更好地了解字段的含义和用法。

schema 数组可以包含以下参数:

参数名 类型 描述
type string 字段的数据类型,比如 'string''integer''boolean''array''object'
description string 字段的描述信息。
enum array 字段的可选值列表。
format string 字段的格式,比如 'date''date-time''email''url'
context array 字段在哪些上下文中显示,比如 ['view', 'edit'] 表示在查看和编辑上下文中都显示。
readonly boolean 是否只读,如果是 true,则不能通过 API 更新该字段。
arg_options array 用于定义字段的参数选项,比如 sanitize_callback(清理回调函数)、validate_callback(验证回调函数)。
properties array 如果字段是一个对象,可以用 properties 定义对象的属性。
items array 如果字段是一个数组,可以用 items 定义数组的元素类型。

例如,定义一个包含作者姓名和邮箱的对象:

register_rest_field(
    'post',
    'author_info',
    array(
        'get_callback'    => 'my_get_post_author_info',
        'update_callback' => null,
        'schema'          => array(
            'type'        => 'object',
            'description' => '文章作者的信息',
            'properties'  => array(
                'name'  => array(
                    'type'        => 'string',
                    'description' => '作者姓名',
                ),
                'email' => array(
                    'type'        => 'string',
                    'description' => '作者邮箱',
                    'format'      => 'email',
                ),
            ),
        ),
    )
);

function my_get_post_author_info( $object, $field_name, $request ) {
    $author_id = $object['author'];
    $author = get_user_by( 'id', $author_id );
    return array(
        'name'  => $author->display_name,
        'email' => $author->user_email,
    );
}

4. permission_callback:控制字段的访问权限

permission_callback 用于控制字段的访问权限,只有通过权限验证的用户才能访问该字段。

例如,只有管理员才能查看文章的阅读次数:

function my_check_reading_count_permission( $request ) {
    return current_user_can( 'manage_options' ); // 只有管理员才能查看
}

register_rest_field(
    'post',
    'reading_count',
    array(
        'get_callback'    => 'my_get_post_reading_count',
        'update_callback' => null,
        'schema'          => null,
        'permission_callback' => 'my_check_reading_count_permission',
    )
);

5. sanitize_callback:清理和验证要更新的值

sanitize_callback 用于对要更新的值进行清理和验证,确保数据的安全性和准确性。

例如,确保阅读次数是正整数:

function my_sanitize_reading_count( $value ) {
    return absint( $value ); // 将值转换为正整数
}

register_rest_field(
    'post',
    'reading_count',
    array(
        'get_callback'    => 'my_get_post_reading_count',
        'update_callback' => 'my_update_post_reading_count',
        'schema'          => array(
            'type'        => 'integer',
            'description' => '文章的阅读次数',
            'context'     => array( 'view', 'edit' ),
            'arg_options' => array(
                'sanitize_callback' => 'my_sanitize_reading_count',
            ),
        ),
    )
);

四、register_rest_field() 源码浅析:看看幕后英雄

register_rest_field() 函数的源码并不复杂,主要就是把我们注册的字段信息保存起来,然后在 API 响应的时候调用 get_callback 获取字段值。

function register_rest_field( $object_type, $attribute, $args ) {
    global $wp_rest_additional_fields;

    if ( ! isset( $wp_rest_additional_fields ) || ! is_array( $wp_rest_additional_fields ) ) {
        $wp_rest_additional_fields = array();
    }

    $object_types = (array) $object_type;

    foreach ( $object_types as $type ) {
        if ( ! isset( $wp_rest_additional_fields[ $type ] ) || ! is_array( $wp_rest_additional_fields[ $type ] ) ) {
            $wp_rest_additional_fields[ $type ] = array();
        }

        $wp_rest_additional_fields[ $type ][ $attribute ] = $args;
    }

    return true;
}

这段代码做了什么?

  1. 获取全局变量 $wp_rest_additional_fields,这是一个数组,用于存储注册的自定义字段信息。
  2. $object_type 转换为数组,允许同时注册多个对象类型。
  3. 遍历 $object_types 数组,将字段信息存储到 $wp_rest_additional_fields 数组中。

关键在于,WordPress 会在生成 REST API 响应的时候,遍历 $wp_rest_additional_fields 数组,调用对应的 get_callback 函数,获取字段值,然后添加到响应中。

五、总结:register_rest_field() 的强大之处

register_rest_field() 函数是 WordPress REST API 的一个强大工具,它可以让我们:

  • 自定义 API 响应,添加我们需要的额外信息。
  • 控制字段的访问权限,保护敏感数据。
  • 清理和验证要更新的值,确保数据的安全性和准确性。
  • 使用 Schema 描述字段的数据类型和格式,方便 API 客户端使用。

掌握了 register_rest_field() 函数,你就可以像定制西装一样,为 WordPress REST API “私人订制”各种各样的字段,满足你的各种需求。

好了,今天的讲座就到这里。希望大家都能灵活运用 register_rest_field() 函数,打造更加强大的 WordPress REST API! 下次有机会再跟大家聊聊 REST API 的其他骚操作!

发表回复

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