我需要的正是你所询问的功能,因此我制作了一个自定义端点。它只为多篇文章公开了一个WP_REST_Server :: READABLE
请求,但似乎工作得很好。
大部分特定于文章类型的内容都被简单地转发到每个查询结果实例化的WP_REST_Posts_Controller实例中。我希望这将降低与其他插件或未来api更新的兼容性问题的风险。
请随意使用以下代码:
class WP_REST_MultiplePostType_Controller extends WP_REST_Controller
{
public function __construct()
{
$this->version = '2';
$this->namespace = 'websiteje/v' . $this->version;
$this->rest_base = 'multiple-post-type';
}
public function register_routes()
{
register_rest_route($this->namespace, '/' . $this->rest_base, array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'get_items'),
'permission_callback' => array($this, 'get_items_permissions_check'),
'args' => $this->get_collection_params(),
),
));
}
public function get_items_permissions_check($request)
{
return true;
}
public function get_items($request)
{
$args = array();
$args['author__in'] = $request['author'];
$args['author__not_in'] = $request['author_exclude'];
$args['menu_order'] = $request['menu_order'];
$args['offset'] = $request['offset'];
$args['order'] = $request['order'];
$args['orderby'] = $request['orderby'];
$args['paged'] = $request['page'];
$args['post__in'] = $request['include'];
$args['post__not_in'] = $request['exclude'];
$args['posts_per_page'] = $request['per_page'];
$args['name'] = $request['slug'];
$args['post_type'] = $request['type'];
$args['post_parent__in'] = $request['parent'];
$args['post_parent__not_in'] = $request['parent_exclude'];
$args['post_status'] = $request['status'];
$args['s'] = $request['search'];
$args['date_query'] = array();
if (isset($request['before'])) {
$args['date_query'][0]['before'] = $request['before'];
}
if (isset($request['after'])) {
$args['date_query'][0]['after'] = $request['after'];
}
if (is_array($request['filter'])) {
$args = array_merge($args, $request['filter']);
unset($args['filter']);
}
if (!is_array($args['post_type'])) {
$args['post_type'] = array($args['post_type']);
}
$args = apply_filters("rest_multiple_post_type_query", $args, $request);
$query_args = $this->prepare_items_query($args, $request);
$taxonomies = wp_list_filter(get_object_taxonomies($query_args['post_type'], 'objects'), array('show_in_rest' => true));
foreach ($taxonomies as $taxonomy) {
$base = !empty($taxonomy->rest_base) ? $taxonomy->rest_base : $taxonomy->name;
if (!empty($request[$base])) {
$query_args['tax_query'][] = array(
'taxonomy' => $taxonomy->name,
'field' => 'term_id',
'terms' => $request[$base],
'include_children' => false,
);
}
}
$posts_query = new WP_Query();
$query_result = $posts_query->query($query_args);
$posts = array();
foreach ($query_result as $post) {
$postsController = new WP_REST_Posts_Controller($post->post_type);
if (!$postsController->check_read_permission($post)) {
continue;
}
$data = $postsController->prepare_item_for_response($post, $request);
$posts[] = $postsController->prepare_response_for_collection($data);
}
$page = (int) $query_args['paged'];
$total_posts = $posts_query->found_posts;
if ($total_posts < 1) {
unset($query_args['paged']);
$count_query = new WP_Query();
$count_query->query($query_args);
$total_posts = $count_query->found_posts;
}
$max_pages = ceil($total_posts / (int) $query_args['posts_per_page']);
$response = rest_ensure_response($posts);
$response->header('X-WP-Total', (int) $total_posts);
$response->header('X-WP-TotalPages', (int) $max_pages);
$request_params = $request->get_query_params();
if (!empty($request_params['filter'])) {
unset($request_params['filter']['posts_per_page']);
unset($request_params['filter']['paged']);
}
$base = add_query_arg($request_params, rest_url(sprintf('/%s/%s', $this->namespace, $this->rest_base)));
if ($page > 1) {
$prev_page = $page - 1;
if ($prev_page > $max_pages) {
$prev_page = $max_pages;
}
$prev_link = add_query_arg('page', $prev_page, $base);
$response->link_header('prev', $prev_link);
}
if ($max_pages > $page) {
$next_page = $page + 1;
$next_link = add_query_arg('page', $next_page, $base);
$response->link_header('next', $next_link);
}
return $response;
}
protected function prepare_items_query($prepared_args = array(), $request = null)
{
$valid_vars = array_flip($this->get_allowed_query_vars($request['type']));
$query_args = array();
foreach ($valid_vars as $var => $index) {
if (isset($prepared_args[$var])) {
$query_args[$var] = apply_filters("rest_query_var-{$var}", $prepared_args[$var]);
}
}
if (in_array('post', $query_args['post_type']) || !isset($query_args['ignore_sticky_posts'])) {
$query_args['ignore_sticky_posts'] = true;
}
if ('include' === $query_args['orderby']) {
$query_args['orderby'] = 'post__in';
}
return $query_args;
}
protected function get_allowed_query_vars($post_types)
{
global $wp;
$editPosts = true;
$valid_vars = apply_filters('query_vars', $wp->public_query_vars);
$edit_posts = true;
foreach ($post_types as $post_type) {
$post_type_obj = get_post_type_object($post_type);
if (!current_user_can($post_type_obj->cap->edit_posts)) {
$edit_posts = false;
break;
}
}
if ($edit_posts) {
$private = apply_filters('rest_private_query_vars', $wp->private_query_vars);
$valid_vars = array_merge($valid_vars, $private);
}
$rest_valid = array(
'author__in',
'author__not_in',
'ignore_sticky_posts',
'menu_order',
'offset',
'post__in',
'post__not_in',
'post_parent',
'post_parent__in',
'post_parent__not_in',
'posts_per_page',
'date_query',
);
$valid_vars = array_merge($valid_vars, $rest_valid);
$valid_vars = apply_filters('rest_query_vars', $valid_vars);
return $valid_vars;
}
public function get_collection_params()
{
$params = parent::get_collection_params();
$params['context']['default'] = 'view';
$params['after'] = array(
'description' => __('Limit response to resources published after a given ISO8601 compliant date.'),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['author'] = array(
'description' => __('Limit result set to posts assigned to specific authors.'),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['author_exclude'] = array(
'description' => __('Ensure result set excludes posts assigned to specific authors.'),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['before'] = array(
'description' => __('Limit response to resources published before a given ISO8601 compliant date.'),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['exclude'] = array(
'description' => __('Ensure result set excludes specific ids.'),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['include'] = array(
'description' => __('Limit result set to specific ids.'),
'type' => 'array',
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['menu_order'] = array(
'description' => __('Limit result set to resources with a specific menu_order value.'),
'type' => 'integer',
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['offset'] = array(
'description' => __('Offset the result set by a specific number of items.'),
'type' => 'integer',
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['order'] = array(
'description' => __('Order sort attribute ascending or descending.'),
'type' => 'string',
'default' => 'desc',
'enum' => array('asc', 'desc'),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby'] = array(
'description' => __('Sort collection by object attribute.'),
'type' => 'string',
'default' => 'date',
'enum' => array(
'date',
'id',
'include',
'title',
'slug',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby']['enum'][] = 'menu_order';
$params['parent'] = array(
'description' => __('Limit result set to those of particular parent ids.'),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'default' => array(),
);
$params['parent_exclude'] = array(
'description' => __('Limit result set to all items except those of a particular parent id.'),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'default' => array(),
);
$params['slug'] = array(
'description' => __('Limit result set to posts with a specific slug.'),
'type' => 'string',
'validate_callback' => 'rest_validate_request_arg',
);
$params['status'] = array(
'default' => 'publish',
'description' => __('Limit result set to posts assigned a specific status.'),
'sanitize_callback' => 'sanitize_key',
'type' => 'string',
'validate_callback' => array($this, 'validate_user_can_query_private_statuses'),
);
$params['filter'] = array(
'description' => __('Use WP Query arguments to modify the response; private query vars require appropriate authorization.'),
);
$taxonomies = wp_list_filter(get_object_taxonomies(get_post_types(array(), 'names'), 'objects'), array('show_in_rest' => true));
foreach ($taxonomies as $taxonomy) {
$base = !empty($taxonomy->rest_base) ? $taxonomy->rest_base : $taxonomy->name;
$params[$base] = array(
'description' => sprintf(__('Limit result set to all items that have the specified term assigned in the %s taxonomy.'), $base),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'default' => array(),
);
}
return $params;
}
public function validate_user_can_query_private_statuses($value, $request, $parameter)
{
if ('publish' === $value) {
return true;
}
foreach ($request["type"] as $post_type) {
$post_type_obj = get_post_type_object($post_type);
if (!current_user_can($post_type_obj->cap->edit_posts)) {
return new WP_Error('rest_forbidden_status', __('Status is forbidden'), array(
'status' => rest_authorization_required_code(),
'post_type' => $post_type_obj->name,
));
}
}
return true;
}
}
为了注册端点,您可以使用以下类似的方式:
add_action('rest_api_init', 'init_wp_rest_multiple_post_type_endpoint');
function init_wp_rest_multiple_post_type_endpoint()
{
$controller = new WP_REST_MultiplePostType_Controller();
$controller->register_routes();
}