各位观众,各位朋友,大家好! 今天咱们聊点有意思的,就是如何像搭积木一样,用 WordPress 的 WP_REST_Controller
类来构建你自己的 REST API 端点。 放心,这玩意儿没想象中那么难,只要掌握了套路,你也能轻松驾驭它。
开场白:REST API 界的葵花宝典
话说江湖上,武功门派林立,想在 WordPress 这片地盘上混,不会点 REST API 的功夫,那可不行。 WordPress 早就为你准备好了秘籍,就是 WP_REST_Controller
类。 掌握了它,你就能在 WordPress 的 REST API 世界里横着走,想怎么玩就怎么玩。
WP_REST_Controller
:你的专属 API 建造师
WP_REST_Controller
是个什么东西? 简单来说,它就是一个基类,你继承它,就能快速搭建出符合 WordPress REST API 规范的端点。 它帮你处理了很多底层细节,比如路由注册、权限验证、参数校验等等,让你专注于业务逻辑。
第一步:创建你的 API 类
首先,你要创建一个类,继承 WP_REST_Controller
。 就像盖房子一样,先打好地基。
<?php
/**
* 我的自定义 API 控制器
*/
class My_Custom_API_Controller extends WP_REST_Controller {
/**
* 命名空间和版本
*
* @var string
*/
protected $namespace = 'my-plugin/v1';
/**
* 路由基地址
*
* @var string
*/
protected $rest_base = 'my-data';
/**
* 构造函数
*/
public function __construct() {
// 可选:在这里设置一些初始值,比如权限回调函数
}
/**
* 注册路由
*/
public function register_routes() {
// 稍后填充
}
}
$namespace
: 你的 API 的命名空间,就像你的地盘一样,要独一无二。 通常是插件名/版本号
的形式。$rest_base
: API 的基地址,比如my-data
,那么你的 API 地址就是/wp-json/my-plugin/v1/my-data
。__construct()
: 构造函数,可以在这里做一些初始化工作,比如设置权限回调函数。register_routes()
: 注册路由的地方,这是最关键的,告诉 WordPress 你的 API 有哪些端点,以及它们对应的处理函数。
第二步:注册你的路由
接下来,你要在 register_routes()
方法里注册你的 API 端点。 这就像给你的房子安装门牌号一样,让别人知道怎么找到你。
/**
* 注册路由
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE, // GET
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ), //权限验证
'args' => array(), // 参数校验
),
array(
'methods' => WP_REST_Server::CREATABLE, // POST
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => array(
'title' => array(
'required' => true,
'type' => 'string',
'description' => 'The title of the item.',
),
'content' => array(
'required' => false,
'type' => 'string',
'description' => 'The content of the item.',
),
),
),
)
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/(?P<id>[d]+)',
array(
array(
'methods' => WP_REST_Server::READABLE, // GET
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'id' => array(
'description' => 'The ID of the item.',
'type' => 'integer',
'required' => true,
),
),
),
array(
'methods' => WP_REST_Server::EDITABLE, // PUT/PATCH
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => array(
'id' => array(
'description' => 'The ID of the item.',
'type' => 'integer',
'required' => true,
),
'title' => array(
'required' => false,
'type' => 'string',
'description' => 'The title of the item.',
),
'content' => array(
'required' => false,
'type' => 'string',
'description' => 'The content of the item.',
),
),
),
array(
'methods' => WP_REST_Server::DELETABLE, // DELETE
'callback' => array( $this, 'delete_item' ),
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
'args' => array(
'id' => array(
'description' => 'The ID of the item.',
'type' => 'integer',
'required' => true,
),
'force' => array(
'default' => false,
'type' => 'boolean',
'description' => 'Whether to bypass trash and force deletion.',
),
),
),
)
);
}
register_rest_route()
函数接收三个参数:
$namespace
: 命名空间。$route
: 路由规则,可以是字符串或正则表达式。(?P<id>[d]+)
表示一个名为id
的参数,它必须是数字。$args
: 一个数组,定义了该路由支持的 HTTP 方法、回调函数、权限验证函数和参数校验规则。
$args
数组详解:
methods
: HTTP 方法,可以是WP_REST_Server::READABLE
(GET),WP_REST_Server::CREATABLE
(POST),WP_REST_Server::EDITABLE
(PUT/PATCH),WP_REST_Server::DELETABLE
(DELETE)。callback
: 处理请求的回调函数,也就是你写的业务逻辑。permission_callback
: 权限验证回调函数,决定谁可以访问这个端点。args
: 参数校验规则,定义了哪些参数是必须的,它们的类型是什么,等等。
参数校验(args
)的细节:
属性 | 描述 |
---|---|
required |
布尔值,表示参数是否必须。 true 表示必须,false 表示可选。 |
type |
参数类型,可以是 string ,integer ,boolean ,array ,object ,number 。 |
description |
参数描述,用于 API 文档。 |
default |
参数默认值,如果用户没有传递该参数,则使用默认值。 |
validate_callback |
一个回调函数,用于自定义参数验证。 你可以编写自己的函数来验证参数是否符合你的要求。 如果验证失败,则返回一个 WP_Error 对象。 |
sanitize_callback |
一个回调函数,用于对参数进行清理和过滤。 你可以编写自己的函数来清理参数,比如去除空格、HTML 标签等。 |
enum |
一个数组,列出了参数允许的值。 例如,'enum' => array( 'pending', 'publish', 'draft' ) 表示参数只能是 pending 、publish 或 draft 中的一个。 |
第三步:编写你的业务逻辑
现在,你可以编写你的业务逻辑了,也就是 callback
对应的函数。 这些函数负责处理请求,从数据库中读取数据,或者将数据写入数据库,等等。
/**
* 获取多个数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response
*/
public function get_items( $request ) {
// 获取参数
$args = array(
'posts_per_page' => $request['per_page'] ?? 10, // 使用空合并运算符设置默认值
'paged' => $request['page'] ?? 1,
);
$query = new WP_Query( $args );
$data = array();
foreach ( $query->posts as $post ) {
$item = $this->prepare_item_for_response( $post, $request );
$data[] = $this->prepare_response_for_collection( $item ); // 确保以集合形式返回
}
$response = rest_ensure_response( $data );
// 添加分页信息到响应头
$total_posts = $query->found_posts;
$max_pages = ceil( $total_posts / $args['posts_per_page'] );
$response->header( 'X-WP-Total', (int) $total_posts );
$response->header( 'X-WP-TotalPages', (int) $max_pages );
return $response;
}
/**
* 获取单个数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response
*/
public function get_item( $request ) {
$id = (int) $request['id'];
// 验证 ID 是否有效
if ( ! get_post( $id ) ) {
return new WP_Error( 'rest_not_found', '资源不存在', array( 'status' => 404 ) );
}
$post = get_post( $id );
$data = $this->prepare_item_for_response( $post, $request );
return rest_ensure_response( $data );
}
/**
* 创建一个数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response
*/
public function create_item( $request ) {
$title = sanitize_text_field( $request['title'] );
$content = wp_kses_post( $request['content'] ); // 允许一些 HTML 标签
$post_id = wp_insert_post( array(
'post_title' => $title,
'post_content' => $content,
'post_status' => 'publish',
) );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
$post = get_post( $post_id );
$data = $this->prepare_item_for_response( $post, $request );
return rest_ensure_response( $data );
}
/**
* 更新一个数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response
*/
public function update_item( $request ) {
$id = (int) $request['id'];
$title = isset( $request['title'] ) ? sanitize_text_field( $request['title'] ) : null;
$content = isset( $request['content'] ) ? wp_kses_post( $request['content'] ) : null;
// 验证 ID 是否有效
if ( ! get_post( $id ) ) {
return new WP_Error( 'rest_not_found', '资源不存在', array( 'status' => 404 ) );
}
$update_data = array(
'ID' => $id,
);
if ( ! is_null( $title ) ) {
$update_data['post_title'] = $title;
}
if ( ! is_null( $content ) ) {
$update_data['post_content'] = $content;
}
$post_id = wp_update_post( $update_data );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
$post = get_post( $post_id );
$data = $this->prepare_item_for_response( $post, $request );
return rest_ensure_response( $data );
}
/**
* 删除一个数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response
*/
public function delete_item( $request ) {
$id = (int) $request['id'];
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
// 验证 ID 是否有效
if ( ! get_post( $id ) ) {
return new WP_Error( 'rest_not_found', '资源不存在', array( 'status' => 404 ) );
}
$result = wp_delete_post( $id, $force );
if ( ! $result ) {
return new WP_Error( 'rest_cannot_delete', '无法删除资源', array( 'status' => 500 ) );
}
return rest_ensure_response( array( 'deleted' => true ) );
}
这些函数都接收一个 $request
参数,它是一个 WP_REST_Request
对象,包含了请求的所有信息,比如 URL 参数、请求体、请求头等等。
get_items()
: 获取多个数据项的列表。get_item()
: 获取单个数据项。create_item()
: 创建一个新的数据项。update_item()
: 更新一个已有的数据项。delete_item()
: 删除一个数据项。
prepare_item_for_response()
和 prepare_response_for_collection()
:
prepare_item_for_response()
: 这个函数负责将你的数据转换为 REST API 响应的格式。 你可以自定义这个函数来控制响应的结构和内容。prepare_response_for_collection()
: 这个函数将单个项目准备为集合的一部分。 这对于确保响应格式的一致性至关重要,特别是对于列表端点。
/**
* 准备数据项以进行响应
*
* @param mixed $item 数据项.
* @param WP_REST_Request $request 请求对象.
*
* @return WP_REST_Response WordPress 数据项实例数据.
*/
public function prepare_item_for_response( $item, $request ) {
$data = array(
'id' => $item->ID,
'title' => $item->post_title,
'content' => $item->post_content,
'link' => get_permalink( $item->ID ),
);
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );
// 创建响应对象
$response = rest_ensure_response( $data );
// 添加链接
$response->add_link( 'self', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $item->ID ) ) );
return $response;
}
第四步:处理权限验证
权限验证非常重要,可以防止未经授权的访问。 你需要在 permission_callback
对应的函数里编写权限验证逻辑。
/**
* 检查是否允许获取数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function get_items_permissions_check( $request ) {
// 只有登录用户才能访问
if ( ! is_user_logged_in() ) {
return new WP_Error( 'rest_forbidden', '您没有权限查看资源', array( 'status' => 401 ) );
}
return true; // 允许访问
}
/**
* 检查是否允许获取单个数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function get_item_permissions_check( $request ) {
return $this->get_items_permissions_check( $request ); // 使用相同的权限检查
}
/**
* 检查是否允许创建数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function create_item_permissions_check( $request ) {
// 只有管理员才能创建
if ( ! current_user_can( 'manage_options' ) ) {
return new WP_Error( 'rest_forbidden', '您没有权限创建资源', array( 'status' => 403 ) );
}
return true; // 允许访问
}
/**
* 检查是否允许更新数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function update_item_permissions_check( $request ) {
return $this->create_item_permissions_check( $request ); // 使用相同的权限检查
}
/**
* 检查是否允许删除数据项
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function delete_item_permissions_check( $request ) {
return $this->create_item_permissions_check( $request ); // 使用相同的权限检查
}
is_user_logged_in()
: 检查用户是否登录。current_user_can( 'manage_options' )
: 检查当前用户是否具有manage_options
权限,也就是管理员权限。
第五步:注册你的 API 类
最后,你需要注册你的 API 类,让 WordPress 知道它的存在。 你可以使用 add_action()
函数,在 rest_api_init
钩子上注册。
add_action( 'rest_api_init', function () {
$controller = new My_Custom_API_Controller();
$controller->register_routes();
} );
错误处理:你的 API 的急救箱
在编写 API 的时候,错误处理非常重要。 你可以使用 WP_Error
类来返回错误信息。
return new WP_Error( 'my_error_code', '错误信息', array( 'status' => 400 ) );
my_error_code
: 错误代码,用于标识错误类型。错误信息
: 错误信息,用于向用户解释错误原因。status
: HTTP 状态码,用于表示错误的严重程度。
总结:REST API 的乐高世界
WP_REST_Controller
类就像一个乐高积木盒,里面有很多积木块,你可以根据自己的需要,自由组合,搭建出各种各样的 REST API 端点。 只要你掌握了这些积木块的用法,就能在 WordPress 的 REST API 世界里玩得转。
一些额外的提示:
- 使用版本控制: 在你的 API 中使用版本控制,可以让你在不破坏现有 API 的情况下,添加新的功能。
- 编写 API 文档: 好的 API 文档可以帮助开发者更好地使用你的 API。
- 测试你的 API: 在发布你的 API 之前,一定要进行充分的测试,确保它能够正常工作。
- 遵循 RESTful 规范: 尽量遵循 RESTful 规范,让你的 API 更加易于理解和使用。
好了,今天的讲座就到这里。 希望大家能够通过 WP_REST_Controller
类,构建出强大而优雅的 WordPress REST API。 谢谢大家!