PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.3
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.3
6.0.3 6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 5.6.1 All 34 releases
← All changes | libraries/cmb2/includes/shim/WP_REST_Controller.php +541 -0 5.8.4 → 6.0.3 View file →
@@ -1,0 +1,541 @@
1 +<?php
2 +
3 +
4 +abstract class WP_REST_Controller {
5 +
6 + /**
7 + * The namespace of this controller's route.
8 + *
9 + * @var string
10 + */
11 + protected $namespace;
12 +
13 + /**
14 + * The base of this controller's route.
15 + *
16 + * @var string
17 + */
18 + protected $rest_base;
19 +
20 + /**
21 + * Register the routes for the objects of the controller.
22 + */
23 + public function register_routes() {
24 + /* translators: %s: register_routes() */
25 + _doing_it_wrong( 'WP_REST_Controller::register_routes', sprintf( __( "Method '%s' must be overridden." ), __METHOD__ ), '4.7' );
26 + }
27 +
28 + /**
29 + * Check if a given request has access to get items.
30 + *
31 + * @param WP_REST_Request $request Full data about the request.
32 + * @return WP_Error|boolean
33 + */
34 + public function get_items_permissions_check( $request ) {
35 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
36 + 'status' => 405,
37 + ) );
38 + }
39 +
40 + /**
41 + * Get a collection of items.
42 + *
43 + * @param WP_REST_Request $request Full data about the request.
44 + * @return WP_Error|WP_REST_Response
45 + */
46 + public function get_items( $request ) {
47 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
48 + 'status' => 405,
49 + ) );
50 + }
51 +
52 + /**
53 + * Check if a given request has access to get a specific item.
54 + *
55 + * @param WP_REST_Request $request Full data about the request.
56 + * @return WP_Error|boolean
57 + */
58 + public function get_item_permissions_check( $request ) {
59 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
60 + 'status' => 405,
61 + ) );
62 + }
63 +
64 + /**
65 + * Get one item from the collection.
66 + *
67 + * @param WP_REST_Request $request Full data about the request.
68 + * @return WP_Error|WP_REST_Response
69 + */
70 + public function get_item( $request ) {
71 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
72 + 'status' => 405,
73 + ) );
74 + }
75 +
76 + /**
77 + * Check if a given request has access to create items.
78 + *
79 + * @param WP_REST_Request $request Full data about the request.
80 + * @return WP_Error|boolean
81 + */
82 + public function create_item_permissions_check( $request ) {
83 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
84 + 'status' => 405,
85 + ) );
86 + }
87 +
88 + /**
89 + * Create one item from the collection.
90 + *
91 + * @param WP_REST_Request $request Full data about the request.
92 + * @return WP_Error|WP_REST_Response
93 + */
94 + public function create_item( $request ) {
95 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
96 + 'status' => 405,
97 + ) );
98 + }
99 +
100 + /**
101 + * Check if a given request has access to update a specific item.
102 + *
103 + * @param WP_REST_Request $request Full data about the request.
104 + * @return WP_Error|boolean
105 + */
106 + public function update_item_permissions_check( $request ) {
107 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
108 + 'status' => 405,
109 + ) );
110 + }
111 +
112 + /**
113 + * Update one item from the collection.
114 + *
115 + * @param WP_REST_Request $request Full data about the request.
116 + * @return WP_Error|WP_REST_Response
117 + */
118 + public function update_item( $request ) {
119 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
120 + 'status' => 405,
121 + ) );
122 + }
123 +
124 + /**
125 + * Check if a given request has access to delete a specific item.
126 + *
127 + * @param WP_REST_Request $request Full data about the request.
128 + * @return WP_Error|boolean
129 + */
130 + public function delete_item_permissions_check( $request ) {
131 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
132 + 'status' => 405,
133 + ) );
134 + }
135 +
136 + /**
137 + * Delete one item from the collection.
138 + *
139 + * @param WP_REST_Request $request Full data about the request.
140 + * @return WP_Error|WP_REST_Response
141 + */
142 + public function delete_item( $request ) {
143 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
144 + 'status' => 405,
145 + ) );
146 + }
147 +
148 + /**
149 + * Prepare the item for create or update operation.
150 + *
151 + * @param WP_REST_Request $request Request object.
152 + * @return WP_Error|object $prepared_item
153 + */
154 + protected function prepare_item_for_database( $request ) {
155 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
156 + 'status' => 405,
157 + ) );
158 + }
159 +
160 + /**
161 + * Prepare the item for the REST response.
162 + *
163 + * @param mixed $item WordPress representation of the item.
164 + * @param WP_REST_Request $request Request object.
165 + * @return WP_REST_Response $response
166 + */
167 + public function prepare_item_for_response( $item, $request ) {
168 + return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array(
169 + 'status' => 405,
170 + ) );
171 + }
172 +
173 + /**
174 + * Prepare a response for inserting into a collection.
175 + *
176 + * @param WP_REST_Response $response Response object.
177 + * @return array Response data, ready for insertion into collection data.
178 + */
179 + public function prepare_response_for_collection( $response ) {
180 + if ( ! ( $response instanceof WP_REST_Response ) ) {
181 + return $response;
182 + }
183 +
184 + $data = (array) $response->get_data();
185 + $server = rest_get_server();
186 +
187 + if ( method_exists( $server, 'get_compact_response_links' ) ) {
188 + $links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
189 + } else {
190 + $links = call_user_func( array( $server, 'get_response_links' ), $response );
191 + }
192 +
193 + if ( ! empty( $links ) ) {
194 + $data['_links'] = $links;
195 + }
196 +
197 + return $data;
198 + }
199 +
200 + /**
201 + * Filter a response based on the context defined in the schema.
202 + *
203 + * @param array $data
204 + * @param string $context
205 + * @return array
206 + */
207 + public function filter_response_by_context( $data, $context ) {
208 +
209 + $schema = $this->get_item_schema();
210 + foreach ( $data as $key => $value ) {
211 + if ( empty( $schema['properties'][ $key ] ) || empty( $schema['properties'][ $key ]['context'] ) ) {
212 + continue;
213 + }
214 +
215 + if ( ! in_array( $context, $schema['properties'][ $key ]['context'] ) ) {
216 + unset( $data[ $key ] );
217 + continue;
218 + }
219 +
220 + if ( 'object' === $schema['properties'][ $key ]['type'] && ! empty( $schema['properties'][ $key ]['properties'] ) ) {
221 + foreach ( $schema['properties'][ $key ]['properties'] as $attribute => $details ) {
222 + if ( empty( $details['context'] ) ) {
223 + continue;
224 + }
225 + if ( ! in_array( $context, $details['context'] ) ) {
226 + if ( isset( $data[ $key ][ $attribute ] ) ) {
227 + unset( $data[ $key ][ $attribute ] );
228 + }
229 + }
230 + }
231 + }
232 + }
233 +
234 + return $data;
235 + }
236 +
237 + /**
238 + * Get the item's schema, conforming to JSON Schema.
239 + *
240 + * @return array
241 + */
242 + public function get_item_schema() {
243 + return $this->add_additional_fields_schema( array() );
244 + }
245 +
246 + /**
247 + * Get the item's schema for display / public consumption purposes.
248 + *
249 + * @return array
250 + */
251 + public function get_public_item_schema() {
252 +
253 + $schema = $this->get_item_schema();
254 +
255 + foreach ( $schema['properties'] as &$property ) {
256 + if ( isset( $property['arg_options'] ) ) {
257 + unset( $property['arg_options'] );
258 + }
259 + }
260 +
261 + return $schema;
262 + }
263 +
264 + /**
265 + * Get the query params for collections.
266 + *
267 + * @return array
268 + */
269 + public function get_collection_params() {
270 + return array(
271 + 'context' => $this->get_context_param(),
272 + 'page' => array(
273 + 'description' => __( 'Current page of the collection.' ),
274 + 'type' => 'integer',
275 + 'default' => 1,
276 + 'sanitize_callback' => 'absint',
277 + 'validate_callback' => 'rest_validate_request_arg',
278 + 'minimum' => 1,
279 + ),
280 + 'per_page' => array(
281 + 'description' => __( 'Maximum number of items to be returned in result set.' ),
282 + 'type' => 'integer',
283 + 'default' => 10,
284 + 'minimum' => 1,
285 + 'maximum' => 100,
286 + 'sanitize_callback' => 'absint',
287 + 'validate_callback' => 'rest_validate_request_arg',
288 + ),
289 + 'search' => array(
290 + 'description' => __( 'Limit results to those matching a string.' ),
291 + 'type' => 'string',
292 + 'sanitize_callback' => 'sanitize_text_field',
293 + 'validate_callback' => 'rest_validate_request_arg',
294 + ),
295 + );
296 + }
297 +
298 + /**
299 + * Get the magical context param.
300 + *
301 + * Ensures consistent description between endpoints, and populates enum from schema.
302 + *
303 + * @param array $args
304 + * @return array
305 + */
306 + public function get_context_param( $args = array() ) {
307 + $param_details = array(
308 + 'description' => __( 'Scope under which the request is made; determines fields present in response.' ),
309 + 'type' => 'string',
310 + 'sanitize_callback' => 'sanitize_key',
311 + 'validate_callback' => 'rest_validate_request_arg',
312 + );
313 + $schema = $this->get_item_schema();
314 + if ( empty( $schema['properties'] ) ) {
315 + return array_merge( $param_details, $args );
316 + }
317 + $contexts = array();
318 + foreach ( $schema['properties'] as $attributes ) {
319 + if ( ! empty( $attributes['context'] ) ) {
320 + $contexts = array_merge( $contexts, $attributes['context'] );
321 + }
322 + }
323 + if ( ! empty( $contexts ) ) {
324 + $param_details['enum'] = array_unique( $contexts );
325 + rsort( $param_details['enum'] );
326 + }
327 + return array_merge( $param_details, $args );
328 + }
329 +
330 + /**
331 + * Add the values from additional fields to a data object.
332 + *
333 + * @param array $object
334 + * @param WP_REST_Request $request
335 + * @return array modified object with additional fields.
336 + */
337 + protected function add_additional_fields_to_object( $object, $request ) {
338 +
339 + $additional_fields = $this->get_additional_fields();
340 +
341 + foreach ( $additional_fields as $field_name => $field_options ) {
342 +
343 + if ( ! $field_options['get_callback'] ) {
344 + continue;
345 + }
346 +
347 + $object[ $field_name ] = call_user_func( $field_options['get_callback'], $object, $field_name, $request, $this->get_object_type() );
348 + }
349 +
350 + return $object;
351 + }
352 +
353 + /**
354 + * Update the values of additional fields added to a data object.
355 + *
356 + * @param array $object
357 + * @param WP_REST_Request $request
358 + */
359 + protected function update_additional_fields_for_object( $object, $request ) {
360 +
361 + $additional_fields = $this->get_additional_fields();
362 +
363 + foreach ( $additional_fields as $field_name => $field_options ) {
364 +
365 + if ( ! $field_options['update_callback'] ) {
366 + continue;
367 + }
368 +
369 + // Don't run the update callbacks if the data wasn't passed in the request.
370 + if ( ! isset( $request[ $field_name ] ) ) {
371 + continue;
372 + }
373 +
374 + call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() );
375 + }
376 + }
377 +
378 + /**
379 + * Add the schema from additional fields to an schema array.
380 + *
381 + * The type of object is inferred from the passed schema.
382 + *
383 + * @param array $schema Schema array.
384 + */
385 + protected function add_additional_fields_schema( $schema ) {
386 + if ( empty( $schema['title'] ) ) {
387 + return $schema;
388 + }
389 +
390 + /**
391 + * Can't use $this->get_object_type otherwise we cause an inf loop.
392 + */
393 + $object_type = $schema['title'];
394 +
395 + $additional_fields = $this->get_additional_fields( $object_type );
396 +
397 + foreach ( $additional_fields as $field_name => $field_options ) {
398 + if ( ! $field_options['schema'] ) {
399 + continue;
400 + }
401 +
402 + $schema['properties'][ $field_name ] = $field_options['schema'];
403 + }
404 +
405 + return $schema;
406 + }
407 +
408 + /**
409 + * Get all the registered additional fields for a given object-type.
410 + *
411 + * @param string $object_type
412 + * @return array
413 + */
414 + protected function get_additional_fields( $object_type = null ) {
415 +
416 + if ( ! $object_type ) {
417 + $object_type = $this->get_object_type();
418 + }
419 +
420 + if ( ! $object_type ) {
421 + return array();
422 + }
423 +
424 + global $wp_rest_additional_fields;
425 +
426 + if ( ! $wp_rest_additional_fields || ! isset( $wp_rest_additional_fields[ $object_type ] ) ) {
427 + return array();
428 + }
429 +
430 + return $wp_rest_additional_fields[ $object_type ];
431 + }
432 +
433 + /**
434 + * Get the object type this controller is responsible for managing.
435 + *
436 + * @return string
437 + */
438 + protected function get_object_type() {
439 + $schema = $this->get_item_schema();
440 +
441 + if ( ! $schema || ! isset( $schema['title'] ) ) {
442 + return null;
443 + }
444 +
445 + return $schema['title'];
446 + }
447 +
448 + /**
449 + * Get an array of endpoint arguments from the item schema for the controller.
450 + *
451 + * @param string $method HTTP method of the request. The arguments
452 + * for `CREATABLE` requests are checked for required
453 + * values and may fall-back to a given default, this
454 + * is not done on `EDITABLE` requests. Default is
455 + * WP_REST_Server::CREATABLE.
456 + * @return array $endpoint_args
457 + */
458 + public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
459 +
460 + $schema = $this->get_item_schema();
461 + $schema_properties = ! empty( $schema['properties'] ) ? $schema['properties'] : array();
462 + $endpoint_args = array();
463 +
464 + foreach ( $schema_properties as $field_id => $params ) {
465 +
466 + // Arguments specified as `readonly` are not allowed to be set.
467 + if ( ! empty( $params['readonly'] ) ) {
468 + continue;
469 + }
470 +
471 + $endpoint_args[ $field_id ] = array(
472 + 'validate_callback' => 'rest_validate_request_arg',
473 + 'sanitize_callback' => 'rest_sanitize_request_arg',
474 + );
475 +
476 + if ( isset( $params['description'] ) ) {
477 + $endpoint_args[ $field_id ]['description'] = $params['description'];
478 + }
479 +
480 + if ( WP_REST_Server::CREATABLE === $method && isset( $params['default'] ) ) {
481 + $endpoint_args[ $field_id ]['default'] = $params['default'];
482 + }
483 +
484 + if ( WP_REST_Server::CREATABLE === $method && ! empty( $params['required'] ) ) {
485 + $endpoint_args[ $field_id ]['required'] = true;
486 + }
487 +
488 + foreach ( array( 'type', 'format', 'enum' ) as $schema_prop ) {
489 + if ( isset( $params[ $schema_prop ] ) ) {
490 + $endpoint_args[ $field_id ][ $schema_prop ] = $params[ $schema_prop ];
491 + }
492 + }
493 +
494 + // Merge in any options provided by the schema property.
495 + if ( isset( $params['arg_options'] ) ) {
496 +
497 + // Only use required / default from arg_options on CREATABLE endpoints.
498 + if ( WP_REST_Server::CREATABLE !== $method ) {
499 + $params['arg_options'] = array_diff_key( $params['arg_options'], array(
500 + 'required' => '',
501 + 'default' => '',
502 + ) );
503 + }
504 +
505 + $endpoint_args[ $field_id ] = array_merge( $endpoint_args[ $field_id ], $params['arg_options'] );
506 + }
507 + }// End foreach().
508 +
509 + return $endpoint_args;
510 + }
511 +
512 + /**
513 + * Retrieves post data given a post ID or post object.
514 + *
515 + * This is a subset of the functionality of the `get_post()` function, with
516 + * the additional functionality of having `the_post` action done on the
517 + * resultant post object. This is done so that plugins may manipulate the
518 + * post that is used in the REST API.
519 + *
520 + * @see get_post()
521 + * @global WP_Query $wp_query
522 + *
523 + * @param int|WP_Post $post Post ID or post object. Defaults to global $post.
524 + * @return WP_Post|null A `WP_Post` object when successful.
525 + */
526 + public function get_post( $post ) {
527 + $post_obj = get_post( $post );
528 +
529 + /**
530 + * Filter the post.
531 + *
532 + * Allows plugins to filter the post object as returned by `\WP_REST_Controller::get_post()`.
533 + *
534 + * @param WP_Post|null $post_obj The post object as returned by `get_post()`.
535 + * @param int|WP_Post $post The original value used to obtain the post object.
536 + */
537 + $post = apply_filters( 'rest_the_post', $post_obj, $post );
538 +
539 + return $post;
540 + }
541 +}