详解 WordPress `register_meta()` 函数的源码:如何将自定义字段暴露给区块和 REST API。

各位攻城狮、程序媛,大家好!我是你们今天的段子手兼技术导师,老码农一枚。今天咱们不聊风花雪月,就来扒一扒 WordPress 里一个非常重要但又容易被忽略的函数:register_meta()

今天的主题是:register_meta() 详解:让你的自定义字段在区块和 REST API 里浪起来!”

别看 register_meta() 名字平淡无奇,它可是 WordPress 里自定义字段的“身份证”。有了它,你的自定义字段才能光明正大地被 WordPress 识别,才能顺利地在区块编辑器(Gutenberg)和 REST API 里抛头露面。否则,你的字段只能默默地躺在数据库里,变成一个孤芳自赏的“隐士”。

第一部分:register_meta() 是什么?为什么我们需要它?

简单来说,register_meta() 的作用就是注册自定义字段的元数据。它告诉 WordPress:“嘿,我这里有个自定义字段,它的类型是啥,权限是啥,要不要暴露给 REST API 啊?”,就像你去派出所登记户口一样。

那么,为什么我们需要注册元数据呢?

  • 类型安全: 注册了类型,WordPress 就能对数据进行验证,防止你把字符串存到数字字段里,导致程序崩溃。
  • 权限控制: 可以控制谁能读写这些字段,确保数据安全。
  • REST API 和区块编辑器集成: 这是最重要的!只有注册了元数据,WordPress 才能知道你的字段可以被 REST API 访问,才能在区块编辑器里显示出来,让用户可以方便地编辑这些字段。

第二部分:register_meta() 的基本语法

register_meta() 函数接受以下参数:

register_meta(
    string   $object_type,
    string   $meta_key,
    array    $args = array()
);
  • $object_type: 对象类型,比如 ‘post’、’term’、’user’ 等,告诉 WordPress 这个字段属于哪个对象。
  • $meta_key: 自定义字段的键名,也就是你存在数据库里的字段名。
  • $args: 一个关联数组,包含了元数据的各种属性,比如类型、权限、是否暴露给 REST API 等。

$args 数组里常用的参数包括:

参数 类型 描述
type string 数据类型,可以是 ‘string’、’integer’、’number’、’boolean’、’object’ 或 ‘array’。WordPress 会根据这个类型进行数据验证。
description string 字段的描述,用于文档和 UI 提示。
single boolean 是否是单值字段。如果是 true,表示这个字段只有一个值;如果是 false,表示这个字段可以有多个值(数组)。
sanitize_callback callable 一个回调函数,用于在保存数据之前对数据进行清理和过滤。
auth_callback callable 一个回调函数,用于验证用户是否有权限读取或写入这个字段。
show_in_rest boolean 是否暴露给 REST API。如果是 true,表示这个字段可以通过 REST API 访问;如果是 false,表示这个字段不会出现在 REST API 的响应中。可以是一个布尔值,也可以是一个数组,用于更精细地控制 REST API 的显示。
default mixed 字段的默认值。

第三部分:实战演练:注册一个文章的自定义字段

假设我们要给文章添加一个自定义字段,用于存储文章的“作者推荐指数”,类型是数字,范围是 1-10,并且要暴露给 REST API。

首先,我们需要在主题的 functions.php 文件或者插件里添加以下代码:

add_action( 'init', 'register_author_rating_meta' );

function register_author_rating_meta() {
    register_meta(
        'post',
        'author_rating',
        array(
            'type'          => 'integer',
            'description'   => '作者推荐指数 (1-10)',
            'single'        => true,
            'sanitize_callback' => 'sanitize_author_rating',
            'auth_callback'   => 'can_edit_author_rating',
            'show_in_rest'  => true,
            'default'       => 5,
        )
    );
}

// 数据清理函数
function sanitize_author_rating( $value ) {
    $value = intval( $value ); // 确保是整数
    if ( $value < 1 ) {
        return 1;
    }
    if ( $value > 10 ) {
        return 10;
    }
    return $value;
}

// 权限验证函数
function can_edit_author_rating( $allowed, $meta_key, $post_id, $user_id, $cap, $caps ) {
    // 只有管理员才能编辑
    return current_user_can( 'manage_options' );
}

这段代码做了以下几件事:

  1. 注册元数据: 使用 register_meta() 函数注册了一个名为 author_rating 的自定义字段,对象类型是 post(文章)。
  2. 定义数据类型: 设置 typeinteger,表示这个字段存储的是整数。
  3. 添加描述: 设置 description 为 ‘作者推荐指数 (1-10)’,方便用户理解这个字段的含义。
  4. 设置单值: 设置 singletrue,表示每篇文章只有一个作者推荐指数。
  5. 数据清理: 使用 sanitize_callback 指定 sanitize_author_rating 函数,用于在保存数据之前对数据进行清理和过滤,确保数据的有效性(1-10 之间的整数)。
  6. 权限验证: 使用 auth_callback 指定 can_edit_author_rating 函数,用于验证用户是否有权限编辑这个字段。这里我们简单地设置为只有管理员才能编辑。
  7. 暴露给 REST API: 设置 show_in_resttrue,表示这个字段可以通过 REST API 访问。
  8. 设置默认值: 设置 default5,表示这个字段的默认值是 5。

第四部分:show_in_rest 的高级用法

show_in_rest 参数除了可以设置为 truefalse 之外,还可以设置为一个数组,用于更精细地控制 REST API 的显示。

'show_in_rest' => array(
    'schema' => array(
        'type'        => 'integer',
        'description' => '作者推荐指数 (1-10)',
        'minimum'     => 1,
        'maximum'     => 10,
    ),
)

在这个例子中,我们使用 schema 数组来定义 REST API 返回数据的结构。我们可以设置 typedescriptionminimummaximum 等属性,用于生成 REST API 的文档和进行数据验证。

你甚至可以指定自定义的序列化和反序列化函数:

'show_in_rest' => array(
    'schema' => array(
        'type'        => 'string', // 假设存储的是字符串
        'description' => '作者推荐指数 (1-10)',
    ),
    'get_callback'    => 'get_author_rating_for_rest',
    'update_callback' => 'update_author_rating_for_rest',
)

function get_author_rating_for_rest( $object, $field_name, $request ) {
    $rating = get_post_meta( $object['id'], 'author_rating', true );
    // 可以对数据进行格式化
    return "Rating: " . $rating;
}

function update_author_rating_for_rest( $value, $object, $field_name ) {
    // 在更新之前进行验证和清理
    $value = intval( $value );
    if ( $value < 1 || $value > 10 ) {
        return new WP_Error( 'invalid_rating', '作者推荐指数必须在 1-10 之间', array( 'status' => 400 ) );
    }
    return update_post_meta( $object->ID, 'author_rating', $value );
}

get_callback 用于在 REST API 返回数据之前对数据进行格式化,update_callback 用于在更新数据之前进行验证和清理。

第五部分:在区块编辑器中使用自定义字段

注册了元数据之后,你的自定义字段就可以在区块编辑器里使用了。

有两种方式可以在区块编辑器中使用自定义字段:

  1. 使用 register_block_type 注册区块: 这是最常见的方式。你可以在 register_block_type 函数的 attributes 属性里定义你的自定义字段,然后在区块的编辑界面里显示这些字段。
// JavaScript (block.js)
registerBlockType( 'my-plugin/my-block', {
    title: '我的区块',
    icon: 'smiley',
    category: 'common',
    attributes: {
        authorRating: {
            type: 'number',
            default: 5,
        },
    },
    edit: ( props ) => {
        const { attributes, setAttributes } = props;
        const { authorRating } = attributes;

        return (
            <div>
                <label>作者推荐指数:</label>
                <input
                    type="number"
                    value={ authorRating }
                    onChange={ ( event ) => setAttributes( { authorRating: parseInt(event.target.value) } ) }
                />
            </div>
        );
    },
    save: ( props ) => {
        return null; // 数据已经保存在文章元数据里了,这里不需要再保存
    },
} );

// PHP (plugin.php)
function register_my_block() {
    register_block_type( 'my-plugin/my-block', array(
        'attributes' => array(
            'authorRating' => array(
                'type' => 'number',
                'default' => 5,
            ),
        ),
        'render_callback' => 'render_my_block',
    ) );
}
add_action( 'init', 'register_my_block' );

function render_my_block( $attributes ) {
    // 从文章元数据里获取数据
    $rating = get_post_meta( get_the_ID(), 'author_rating', true );
    return '<p>作者推荐指数:' . esc_html( $rating ) . '</p>';
}

在这个例子中,我们在 JavaScript 和 PHP 代码里都定义了 authorRating 属性。在 JavaScript 代码里,我们创建了一个输入框,让用户可以编辑这个字段。在 PHP 代码里,我们从文章元数据里获取数据,并将其显示在区块里。

  1. 使用 useSelectuseDispatch Hook: 这是一种更灵活的方式,可以直接访问和修改文章的元数据。
// JavaScript (block.js)
import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';

registerBlockType( 'my-plugin/my-block', {
    title: '我的区块',
    icon: 'smiley',
    category: 'common',
    edit: ( props ) => {
        const { clientId } = props;

        const authorRating = useSelect( ( select ) => {
            const { getEditedPostAttribute } = select( 'core/editor' );
            return getEditedPostAttribute( 'meta' )['author_rating'];
        }, [ clientId ] );

        const { updateEditedPostAttribute } = useDispatch( 'core/editor' );

        useEffect( () => {
            if ( authorRating === undefined ) {
                // 初始化元数据,防止出现 undefined
                updateEditedPostAttribute( { meta: { author_rating: 5 } } );
            }
        }, [ clientId ] );

        return (
            <div>
                <label>作者推荐指数:</label>
                <input
                    type="number"
                    value={ authorRating === undefined ? 5 : authorRating }
                    onChange={ ( event ) => {
                        updateEditedPostAttribute( { meta: { author_rating: parseInt(event.target.value) } } );
                    } }
                />
            </div>
        );
    },
    save: ( props ) => {
        return null; // 数据已经保存在文章元数据里了,这里不需要再保存
    },
} );

在这个例子中,我们使用 useSelect Hook 从 core/editor store 里获取 author_rating 元数据,使用 useDispatch Hook 更新 author_rating 元数据。这种方式更加灵活,可以访问和修改任何文章的元数据。

第六部分:注意事项和常见问题

  • 确保在 init 钩子上注册元数据: 这样可以确保在 WordPress 初始化完成之后注册元数据。
  • 使用 sanitize_callback 进行数据清理: 防止恶意用户输入非法数据。
  • 使用 auth_callback 进行权限验证: 确保只有授权用户才能读写敏感数据。
  • 测试 REST API: 使用 Postman 或其他 REST API 客户端测试你的自定义字段是否可以正常访问。
  • 区块编辑器数据同步问题: 使用 useSelectuseDispatch Hook 时,需要注意数据同步问题,确保区块编辑器里显示的数据和文章元数据保持一致。
  • 命名冲突: 避免使用与其他插件或主题冲突的元数据键名。

第七部分:总结

register_meta() 函数是 WordPress 自定义字段的关键。通过注册元数据,你可以让你的自定义字段在区块编辑器和 REST API 里自由穿梭,为你的 WordPress 站点添加无限可能。

今天我们从 register_meta() 的基本语法、参数、实战演练、高级用法、注意事项等方面进行了详细讲解。希望通过今天的讲座,大家能够对 register_meta() 函数有更深入的理解,并在实际开发中灵活运用。

记住,register_meta() 就像是自定义字段的“身份证”,有了它,你的字段才能在 WordPress 的世界里畅通无阻。

好了,今天的讲座就到这里。感谢大家的聆听!希望大家在编程的道路上越走越远,bug 越来越少,头发越来越多!下次有机会再跟大家分享其他有趣的 WordPress 技术。 拜拜!

发表回复

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