WordPress 4.7.2
[autoinstalls/wordpress.git] / wp-includes / rest-api / endpoints / class-wp-rest-post-types-controller.php
1 <?php
2 /**
3  * REST API: WP_REST_Post_Types_Controller class
4  *
5  * @package WordPress
6  * @subpackage REST_API
7  * @since 4.7.0
8  */
9
10 /**
11  * Core class to access post types via the REST API.
12  *
13  * @since 4.7.0
14  *
15  * @see WP_REST_Controller
16  */
17 class WP_REST_Post_Types_Controller extends WP_REST_Controller {
18
19         /**
20          * Constructor.
21          *
22          * @since 4.7.0
23          * @access public
24          */
25         public function __construct() {
26                 $this->namespace = 'wp/v2';
27                 $this->rest_base = 'types';
28         }
29
30         /**
31          * Registers the routes for the objects of the controller.
32          *
33          * @since 4.7.0
34          * @access public
35          *
36          * @see register_rest_route()
37          */
38         public function register_routes() {
39
40                 register_rest_route( $this->namespace, '/' . $this->rest_base, array(
41                         array(
42                                 'methods'             => WP_REST_Server::READABLE,
43                                 'callback'            => array( $this, 'get_items' ),
44                                 'permission_callback' => array( $this, 'get_items_permissions_check' ),
45                                 'args'                => $this->get_collection_params(),
46                         ),
47                         'schema' => array( $this, 'get_public_item_schema' ),
48                 ) );
49
50                 register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<type>[\w-]+)', array(
51                         'args' => array(
52                                 'type' => array(
53                                         'description' => __( 'An alphanumeric identifier for the post type.' ),
54                                         'type'        => 'string',
55                                 ),
56                         ),
57                         array(
58                                 'methods'  => WP_REST_Server::READABLE,
59                                 'callback' => array( $this, 'get_item' ),
60                                 'args'     => array(
61                                         'context' => $this->get_context_param( array( 'default' => 'view' ) ),
62                                 ),
63                         ),
64                         'schema' => array( $this, 'get_public_item_schema' ),
65                 ) );
66         }
67
68         /**
69          * Checks whether a given request has permission to read types.
70          *
71          * @since 4.7.0
72          * @access public
73          *
74          * @param WP_REST_Request $request Full details about the request.
75          * @return WP_Error|true True if the request has read access, WP_Error object otherwise.
76          */
77         public function get_items_permissions_check( $request ) {
78                 if ( 'edit' === $request['context'] ) {
79                         foreach ( get_post_types( array(), 'object' ) as $post_type ) {
80                                 if ( ! empty( $post_type->show_in_rest ) && current_user_can( $post_type->cap->edit_posts ) ) {
81                                         return true;
82                                 }
83                         }
84
85                         return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) );
86                 }
87
88                 return true;
89         }
90
91         /**
92          * Retrieves all public post types.
93          *
94          * @since 4.7.0
95          * @access public
96          *
97          * @param WP_REST_Request $request Full details about the request.
98          * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
99          */
100         public function get_items( $request ) {
101                 $data = array();
102
103                 foreach ( get_post_types( array(), 'object' ) as $obj ) {
104                         if ( empty( $obj->show_in_rest ) || ( 'edit' === $request['context'] && ! current_user_can( $obj->cap->edit_posts ) ) ) {
105                                 continue;
106                         }
107
108                         $post_type = $this->prepare_item_for_response( $obj, $request );
109                         $data[ $obj->name ] = $this->prepare_response_for_collection( $post_type );
110                 }
111
112                 return rest_ensure_response( $data );
113         }
114
115         /**
116          * Retrieves a specific post type.
117          *
118          * @since 4.7.0
119          * @access public
120          *
121          * @param WP_REST_Request $request Full details about the request.
122          * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
123          */
124         public function get_item( $request ) {
125                 $obj = get_post_type_object( $request['type'] );
126
127                 if ( empty( $obj ) ) {
128                         return new WP_Error( 'rest_type_invalid', __( 'Invalid post type.' ), array( 'status' => 404 ) );
129                 }
130
131                 if ( empty( $obj->show_in_rest ) ) {
132                         return new WP_Error( 'rest_cannot_read_type', __( 'Cannot view post type.' ), array( 'status' => rest_authorization_required_code() ) );
133                 }
134
135                 if ( 'edit' === $request['context'] && ! current_user_can( $obj->cap->edit_posts ) ) {
136                         return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) );
137                 }
138
139                 $data = $this->prepare_item_for_response( $obj, $request );
140
141                 return rest_ensure_response( $data );
142         }
143
144         /**
145          * Prepares a post type object for serialization.
146          *
147          * @since 4.7.0
148          * @access public
149          *
150          * @param stdClass        $post_type Post type data.
151          * @param WP_REST_Request $request   Full details about the request.
152          * @return WP_REST_Response Response object.
153          */
154         public function prepare_item_for_response( $post_type, $request ) {
155                 $taxonomies = wp_list_filter( get_object_taxonomies( $post_type->name, 'objects' ), array( 'show_in_rest' => true ) );
156                 $taxonomies = wp_list_pluck( $taxonomies, 'name' );
157                 $base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name;
158                 $data = array(
159                         'capabilities' => $post_type->cap,
160                         'description'  => $post_type->description,
161                         'hierarchical' => $post_type->hierarchical,
162                         'labels'       => $post_type->labels,
163                         'name'         => $post_type->label,
164                         'slug'         => $post_type->name,
165                         'taxonomies'   => array_values( $taxonomies ),
166                         'rest_base'    => $base,
167                 );
168                 $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
169                 $data    = $this->add_additional_fields_to_object( $data, $request );
170                 $data    = $this->filter_response_by_context( $data, $context );
171
172                 // Wrap the data in a response object.
173                 $response = rest_ensure_response( $data );
174
175                 $response->add_links( array(
176                         'collection' => array(
177                                 'href'   => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
178                         ),
179                         'https://api.w.org/items' => array(
180                                 'href' => rest_url( sprintf( 'wp/v2/%s', $base ) ),
181                         ),
182                 ) );
183
184                 /**
185                  * Filters a post type returned from the API.
186                  *
187                  * Allows modification of the post type data right before it is returned.
188                  *
189                  * @since 4.7.0
190                  *
191                  * @param WP_REST_Response $response The response object.
192                  * @param object           $item     The original post type object.
193                  * @param WP_REST_Request  $request  Request used to generate the response.
194                  */
195                 return apply_filters( 'rest_prepare_post_type', $response, $post_type, $request );
196         }
197
198         /**
199          * Retrieves the post type's schema, conforming to JSON Schema.
200          *
201          * @since 4.7.0
202          * @access public
203          *
204          * @return array Item schema data.
205          */
206         public function get_item_schema() {
207                 $schema = array(
208                         '$schema'              => 'http://json-schema.org/schema#',
209                         'title'                => 'type',
210                         'type'                 => 'object',
211                         'properties'           => array(
212                                 'capabilities'     => array(
213                                         'description'  => __( 'All capabilities used by the post type.' ),
214                                         'type'         => 'object',
215                                         'context'      => array( 'edit' ),
216                                         'readonly'     => true,
217                                 ),
218                                 'description'      => array(
219                                         'description'  => __( 'A human-readable description of the post type.' ),
220                                         'type'         => 'string',
221                                         'context'      => array( 'view', 'edit' ),
222                                         'readonly'     => true,
223                                 ),
224                                 'hierarchical'     => array(
225                                         'description'  => __( 'Whether or not the post type should have children.' ),
226                                         'type'         => 'boolean',
227                                         'context'      => array( 'view', 'edit' ),
228                                         'readonly'     => true,
229                                 ),
230                                 'labels'           => array(
231                                         'description'  => __( 'Human-readable labels for the post type for various contexts.' ),
232                                         'type'         => 'object',
233                                         'context'      => array( 'edit' ),
234                                         'readonly'     => true,
235                                 ),
236                                 'name'             => array(
237                                         'description'  => __( 'The title for the post type.' ),
238                                         'type'         => 'string',
239                                         'context'      => array( 'view', 'edit', 'embed' ),
240                                         'readonly'     => true,
241                                 ),
242                                 'slug'             => array(
243                                         'description'  => __( 'An alphanumeric identifier for the post type.' ),
244                                         'type'         => 'string',
245                                         'context'      => array( 'view', 'edit', 'embed' ),
246                                         'readonly'     => true,
247                                 ),
248                                 'taxonomies'       => array(
249                                         'description'  => __( 'Taxonomies associated with post type.' ),
250                                         'type'         => 'array',
251                                         'items'        => array(
252                                                 'type' => 'string',
253                                         ),
254                                         'context'      => array( 'view', 'edit' ),
255                                         'readonly'     => true,
256                                 ),
257                                 'rest_base'            => array(
258                                         'description'  => __( 'REST base route for the post type.' ),
259                                         'type'         => 'string',
260                                         'context'      => array( 'view', 'edit', 'embed' ),
261                                         'readonly'     => true,
262                                 ),
263                         ),
264                 );
265                 return $this->add_additional_fields_schema( $schema );
266         }
267
268         /**
269          * Retrieves the query params for collections.
270          *
271          * @since 4.7.0
272          * @access public
273          *
274          * @return array Collection parameters.
275          */
276         public function get_collection_params() {
277                 return array(
278                         'context' => $this->get_context_param( array( 'default' => 'view' ) ),
279                 );
280         }
281
282 }