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