编写端点时,使用控制器类来处理端点的功能是有帮助的。控制器类将提供与API进行交互的标准方式,也是与API进行交互的更可维护的方式。 WordPress目前的最低PHP版本为5.2,如果您正在开发将由WordPress生态系统使用的端点,您应该考虑支持WordPress的最低要求。
PHP 5.2没有内置命名空间。这意味着您声明的每个函数都将在全局范围内。如果您决定使用get_items()等端点的常用函数名称,另一个插件也会注册该函数,则PHP将失败并导致致命错误。这是因为函数get_items()被声明为两次。通过封装我们的端点,我们可以避免这些命名冲突,并具有与API进行交互的一致方式。
##控制器
控制器通常做一件事情;他们接收输入并产生输出。对于WordPress REST API,我们的控制器将处理作为WP_REST_Request对象的请求输入,并将响应输出生成为WP_REST_Response对象。我们来看一个例子的控制器类:
```
class My_REST_Posts_Controller {
// Here initialize our namespace and resource name.
public function __construct() {
$this->namespace = '/my-namespace/v1';
$this->resource_name = 'posts';
}
// Register our routes.
public function register_routes() {
register_rest_route( $this->namespace, '/' . $this->resource_name, array(
// Here we register the readable endpoint for collections.
array(
'methods' => 'GET',
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
// Register our schema callback.
'schema' => array( $this, 'get_item_schema' ),
) );
register_rest_route( $this->namespace, '/' . $this->resource_name . '/(?P<id>[\d]+)', array(
// Notice how we are registering multiple endpoints the 'schema' equates to an OPTIONS request.
array(
'methods' => 'GET',
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
),
// Register our schema callback.
'schema' => array( $this, 'get_item_schema' ),
) );
}
/**
* Check permissions for the posts.
*
* @param WP_REST_Request $request Current request.
*/
public function get_items_permissions_check( $request ) {
if ( ! current_user_can( 'read' ) ) {
return new WP_Error( 'rest_forbidden', esc_html__( 'You cannot view the post resource.' ), array( 'status' => $this->authorization_status_code() ) );
}
return true;
}
/**
* Grabs the five most recent posts and outputs them as a rest response.
*
* @param WP_REST_Request $request Current request.
*/
public function get_items( $request ) {
$args = array(
'post_per_page' => 5,
);
$posts = get_posts( $args );
$data = array();
if ( empty( $posts ) ) {
return rest_ensure_response( $data );
}
foreach ( $posts as $post ) {
$response = $this->prepare_item_for_response( $post, $request );
$data[] = $this->prepare_response_for_collection( $response );
}
// Return all of our comment response data.
return rest_ensure_response( $data );
}
/**
* Check permissions for the posts.
*
* @param WP_REST_Request $request Current request.
*/
public function get_item_permissions_check( $request ) {
if ( ! current_user_can( 'read' ) ) {
return new WP_Error( 'rest_forbidden', esc_html__( 'You cannot view the post resource.' ), array( 'status' => $this->authorization_status_code() ) );
}
return true;
}
/**
* Grabs the five most recent posts and outputs them as a rest response.
*
* @param WP_REST_Request $request Current request.
*/
public function get_item( $request ) {
$id = (int) $request['id'];
$post = get_post( $id );
if ( empty( $post ) ) {
return rest_ensure_response( array() );
}
$response = prepare_item_for_response( $post );
// Return all of our post response data.
return $response;
}
/**
* Matches the post data to the schema we want.
*
* @param WP_Post $post The comment object whose response is being prepared.
*/
public function prepare_item_for_response( $post, $request ) {
$post_data = array();
$schema = $this->get_item_schema( $request );
// We are also renaming the fields to more understandable names.
if ( isset( $schema['properties']['id'] ) ) {
$post_data['id'] = (int) $post->ID;
}
if ( isset( $schema['properties']['content'] ) ) {
$post_data['content'] = apply_filters( 'the_content', $post->post_content, $post );
}
return rest_ensure_response( $post_data );
}
/**
* Prepare a response for inserting into a collection of responses.
*
* This is copied from WP_REST_Controller class in the WP REST API v2 plugin.
*
* @param WP_REST_Response $response Response object.
* @return array Response data, ready for insertion into collection data.
*/
public function prepare_response_for_collection( $response ) {
if ( ! ( $response instanceof WP_REST_Response ) ) {
return $response;
}
$data = (array) $response->get_data();
$server = rest_get_server();
if ( method_exists( $server, 'get_compact_response_links' ) ) {
$links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
} else {
$links = call_user_func( array( $server, 'get_response_links' ), $response );
}
if ( ! empty( $links ) ) {
$data['_links'] = $links;
}
return $data;
}
/**
* Get our sample schema for a post.
*
* @param WP_REST_Request $request Current request.
*/
public function get_item_schema( $request ) {
$schema = array(
// This tells the spec of JSON Schema we are using which is draft 4.
'$schema' => 'http://json-schema.org/draft-04/schema#',
// The title property marks the identity of the resource.
'title' => 'post',
'type' => 'object',
// In JSON Schema you can specify object properties in the properties attribute.
'properties' => array(
'id' => array(
'description' => esc_html__( 'Unique identifier for the object.', 'my-textdomain' ),
'type' => 'integer',
'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true,
),
'content' => array(
'description' => esc_html__( 'The content for the object.', 'my-textdomain' ),
'type' => 'string',
),
),
);
return $schema;
}
// Sets up the proper HTTP status code for authorization.
public function authorization_status_code() {
$status = 401;
if ( is_user_logged_in() ) {
$status = 403;
}
return $status;
}
}
// Function to register our new routes from the controller.
function prefix_register_my_rest_routes() {
$controller = new My_REST_Posts_Controller();
$controller->register_routes();
}
add_action( 'rest_api_init', 'prefix_register_my_rest_routes' );
```
## 概述与未来
控制器类在开发端点时为我们解决两个大问题;缺乏命名空间和一致的结构。重要的是要注意,你不应滥用你的端点的继承。例如:如果您为一个帖子端点编写了一个控制器类,就像上面的例子,并且也希望支持自定义的帖子类型,你不应该这样扩展My_REST_Posts_Controller:class My_CPT_REST_Controller extends My_REST_Posts_Controller。
相反,您应该创建一个完全独立的控制器类,或者使My_REST_Posts_Controller处理所有可用的post类型。当你开始继承遗产的路径时,重要的是要明白,如果父类有必要在任何时候改变,而你的子类依赖于它们,那么你将会很头痛。在大多数情况下,您将要创建基控制器类作为接口或抽象类,每个端点控制器都可以实现或扩展。抽象类方法在核心WordPress REST API端点内使用。
## 扩展内部类
WordPress REST API遵循其内部类的故意设计模式,可以将其分类为基础架构或端点类。
基础架构类支持端点类。他们处理WordPress REST API的逻辑,而不执行任何数据转换。另一方面,端点类封装了对WordPress资源执行CRUD操作所必需的功能逻辑。更具体地说,我们的基础设施类包括WP_REST_Server和WP_REST_Request,我们的端点类包括WP_REST_Posts_Controller和WP_REST_Users_Controller。
让我们深入了解每个基础设施类的功能:
- WP_REST_Server:WordPress REST API的主控制器。路由被注册到WordPress中的服务器。当调用WP_REST_Server服务请求时,它确定要调用哪个路由,并将路由回调传递给WP_REST_Request对象。 WP_REST_Server还处理身份验证,并可执行请求验证和权限检查。
- WP_REST_Request:表示请求性质的对象。该对象包括请求详细信息,如请求头,参数和方法以及路由。它还可以执行请求验证和消毒。
- WP_REST_Response:表示响应性质的对象。此类扩展了WP_HTTP_Response,其中包括头文件,正文和状态,并提供了一些辅助方法,如添加链接媒体的add_link(),以及用于获取查询导航标题的query_navigation_headers()。
所有端点类都扩展WP_REST_Controller。此类旨在表示操纵WordPress资源的一致模式。 WP_REST_Controller实现这些方法:
- register_routes():在第一次实例化类之后,调用register_routes()将资源的路由注册到服务器。
- get_items():获取现有实体的集合。
- get_item():获取现有实体。如果实体不存在,则应返回HTTP错误代码404。如果请求者没有访问实体的权限,则应返回HTTP错误代码403。
- create_item():创建一个新的实体,给定一个有效的WP_REST_Request。如果创建成功,则应返回WP_REST_Response,HTTP status = 201,并将位置头添加到新资源。如果以某种形式出现创建错误,则应返回适当的HTTP错误代码和消息。
- update_item():给一个有效的WP_REST_Request更新现有实体。
- delete_item():删除现有实体,给定一个有效的WP_REST_Request。如果以某种方式删除错误,则应返回适当的HTTP错误代码。
- get_items_permissions_check():在调用回调之前,检查给定的请求是否具有资源集合的权限。
- get_item_permissions_check():在调用回调之前,检查给定的请求是否具有获取单个资源的权限。
- create_item_permissions_check():在调用回调之前,检查给定的请求是否具有创建单个资源的权限。
- update_item_permissions_check():在调用回调之前,检查给定的请求是否具有更新单个资源的权限。
- delete_item_permissions_check():在调用回调之前,检查给定的请求是否具有删除单个资源的权限。
- prepare_item_for_response():格式化一个资源以匹配它应该在响应中显示。
- prepare_response_for_collection():当使用prepare_item_for_response()时,返回一个WP_REST_Response。这个帮助函数将所有这些响应包装到一个集合中。
- filter_response_by_context():根据提供的上下文参数过滤响应形状。
- get_item_schema():获取资源的schema JSON Schema对象。
当与实现WP_REST_Controller的端点进行交互时,HTTP客户端可以期望每个端点以类似的方式运行。
- 简介
- 主题开发
- WordPress许可证
- 什么是主题
- 开发环境
- 主题开发示例
- 主题基础
- 模板文件
- 主样式表(style.css)
- 文章类型
- 规划主题文件
- 模板层级
- 模板标签
- 循环
- 主题函数
- 连接主题文件和目录
- 使用CSS和JavaScript
- 条件标签
- 类别,标签和自定义分类
- 模板文件
- 内容模板文件
- 页面模板文件
- 附件模板文件
- 自定义内容类型
- 部分和其他模板文件
- 评论模板
- 分类模板
- 404页面
- 主题功能
- 核心支持的功能
- 管理菜单
- 自定义Headers
- 自定义Logo
- 文章格式
- 置顶文章
- Sidebars
- Widgets
- 导航菜单
- 分页
- 媒体
- Audio
- Images
- Galleries
- Video
- 精选图片和缩略图
- 国际化
- 本地化
- 辅助功能
- 主题选项 – 自定义API
- 定制对象
- 改进用户体验的工具
- 定制JavaScript API
- JavaScript / Underscore.js渲染的自定义控件
- 高级用法
- 主题安全
- 数据消毒/逃避
- 数据验证
- 使用随机数
- 常见漏洞
- 高级主题
- 子主题
- UI最佳实践
- JavaScript最佳做法
- 主题单元测试
- 验证你的主题
- Plugin API Hooks
- 发布你的主题
- 所需的主题文件
- 测试
- 主题评论指南
- 写文档
- 提交你的主题到WordPress.org
- 参考文献
- 模板标签列表
- 条件标签列表
- 编码标准
- HTML编码标准
- CSS编码标准
- JavaScript编码标准
- PHP编码标准
- 插件开发
- 插件开发简介
- 什么是插件
- 插件基础
- 头部要求
- 包括软件许可证
- 启用 / 停用 Hooks
- 卸载方法
- 最佳做法
- 插件安全
- 检查用户功能
- 数据验证
- 保护输入
- 保护输出
- 随机数
- Hooks
- Actions
- Filters
- 自定义Hooks
- 高级主题
- 管理菜单
- 顶级菜单
- 子菜单
- 短代码
- 基本短码
- 封闭短码
- 带参数的短代码
- TinyMCE增强型短码
- 设置
- 设置API
- 使用设置API
- 选项API
- 自定义设置页面
- 元数据
- 管理帖子元数据
- 自定义元数据
- 渲染元数据
- 自定义文章类型
- 注册自定义文章类型
- 使用自定义文章类型
- 分类
- 使用自定义分类
- 在WP 4.2+中使用“split术语”
- 用户
- 创建和管理用户
- 使用用户元数据
- 角色和功能
- HTTP API
- JavaScript
- jQuery
- Ajax
- 服务器端PHP和入队
- Heartbeat API
- 概要
- 计划任务
- 了解WP-Cron计划
- 安排WP-Cron 事件
- 将WP-Cron挂接到系统任务计划程序中
- WP-Cron简单测试
- 国际化
- 本地化
- 如何国际化您的插件
- 国际化安全
- WordPress.org
- 详细插件指南
- 规划您的插件
- 如何使用Subversion
- 插件开发者常见问题
- 开发工具
- Debug Bar 和附加组件
- 辅助插件
- REST API手册
- 资源
- 文章
- 文章修订
- 文章类型
- 文章状态
- 类别
- 标签
- 页面
- 评论
- 分类
- 媒体
- 用户
- 设置
- 使用REST API
- 全局参数
- 分页
- 链接和嵌入
- 发现
- 认证
- 经常问的问题
- 骨干JavaScript客户端
- 客户端库
- 扩展REST API
- 添加自定义端点
- 自定义内容类型
- 修改回应
- 模式
- 词汇表
- 路由和端点
- 控制器类