158 |
158 |
159 $errors = array(); |
159 $errors = array(); |
160 |
160 |
161 foreach ( (array) $error->errors as $code => $messages ) { |
161 foreach ( (array) $error->errors as $code => $messages ) { |
162 foreach ( (array) $messages as $message ) { |
162 foreach ( (array) $messages as $message ) { |
163 $errors[] = array( 'code' => $code, 'message' => $message, 'data' => $error->get_error_data( $code ) ); |
163 $errors[] = array( |
|
164 'code' => $code, |
|
165 'message' => $message, |
|
166 'data' => $error->get_error_data( $code ), |
|
167 ); |
164 } |
168 } |
165 } |
169 } |
166 |
170 |
167 $data = $errors[0]; |
171 $data = $errors[0]; |
168 if ( count( $errors ) > 1 ) { |
172 if ( count( $errors ) > 1 ) { |
258 * @since 4.4.0 |
262 * @since 4.4.0 |
259 * @deprecated 4.7.0 Use the rest_authentication_errors filter to restrict access to the API |
263 * @deprecated 4.7.0 Use the rest_authentication_errors filter to restrict access to the API |
260 * |
264 * |
261 * @param bool $rest_enabled Whether the REST API is enabled. Default true. |
265 * @param bool $rest_enabled Whether the REST API is enabled. Default true. |
262 */ |
266 */ |
263 apply_filters_deprecated( 'rest_enabled', array( true ), '4.7.0', 'rest_authentication_errors', |
267 apply_filters_deprecated( |
|
268 'rest_enabled', |
|
269 array( true ), |
|
270 '4.7.0', |
|
271 'rest_authentication_errors', |
264 __( 'The REST API can no longer be completely disabled, the rest_authentication_errors filter can be used to restrict access to the API, instead.' ) |
272 __( 'The REST API can no longer be completely disabled, the rest_authentication_errors filter can be used to restrict access to the API, instead.' ) |
265 ); |
273 ); |
266 |
274 |
267 /** |
275 /** |
268 * Filters whether jsonp is enabled. |
276 * Filters whether jsonp is enabled. |
396 $result = wp_json_encode( $result ); |
404 $result = wp_json_encode( $result ); |
397 |
405 |
398 $json_error_message = $this->get_json_last_error(); |
406 $json_error_message = $this->get_json_last_error(); |
399 if ( $json_error_message ) { |
407 if ( $json_error_message ) { |
400 $json_error_obj = new WP_Error( 'rest_encode_error', $json_error_message, array( 'status' => 500 ) ); |
408 $json_error_obj = new WP_Error( 'rest_encode_error', $json_error_message, array( 'status' => 500 ) ); |
401 $result = $this->error_to_response( $json_error_obj ); |
409 $result = $this->error_to_response( $json_error_obj ); |
402 $result = wp_json_encode( $result->data[0] ); |
410 $result = wp_json_encode( $result->data[0] ); |
403 } |
411 } |
404 |
412 |
405 if ( $jsonp_callback ) { |
413 if ( $jsonp_callback ) { |
406 // Prepend '/**/' to mitigate possible JSONP Flash attacks. |
414 // Prepend '/**/' to mitigate possible JSONP Flash attacks. |
407 // https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ |
415 // https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ |
452 * |
460 * |
453 * Extracts the links from a response into a structured hash, suitable for |
461 * Extracts the links from a response into a structured hash, suitable for |
454 * direct output. |
462 * direct output. |
455 * |
463 * |
456 * @since 4.4.0 |
464 * @since 4.4.0 |
457 * @static |
|
458 * |
465 * |
459 * @param WP_REST_Response $response Response to extract links from. |
466 * @param WP_REST_Response $response Response to extract links from. |
460 * @return array Map of link relation to list of link hashes. |
467 * @return array Map of link relation to list of link hashes. |
461 */ |
468 */ |
462 public static function get_response_links( $response ) { |
469 public static function get_response_links( $response ) { |
469 $data = array(); |
476 $data = array(); |
470 foreach ( $links as $rel => $items ) { |
477 foreach ( $links as $rel => $items ) { |
471 $data[ $rel ] = array(); |
478 $data[ $rel ] = array(); |
472 |
479 |
473 foreach ( $items as $item ) { |
480 foreach ( $items as $item ) { |
474 $attributes = $item['attributes']; |
481 $attributes = $item['attributes']; |
475 $attributes['href'] = $item['href']; |
482 $attributes['href'] = $item['href']; |
476 $data[ $rel ][] = $attributes; |
483 $data[ $rel ][] = $attributes; |
477 } |
484 } |
478 } |
485 } |
479 |
486 |
480 return $data; |
487 return $data; |
481 } |
488 } |
485 * |
492 * |
486 * Extracts the links from a response into a structured hash, suitable for |
493 * Extracts the links from a response into a structured hash, suitable for |
487 * direct output. |
494 * direct output. |
488 * |
495 * |
489 * @since 4.5.0 |
496 * @since 4.5.0 |
490 * @static |
|
491 * |
497 * |
492 * @param WP_REST_Response $response Response to extract links from. |
498 * @param WP_REST_Response $response Response to extract links from. |
493 * @return array Map of link relation to list of link hashes. |
499 * @return array Map of link relation to list of link hashes. |
494 */ |
500 */ |
495 public static function get_compact_response_links( $response ) { |
501 public static function get_compact_response_links( $response ) { |
497 |
503 |
498 if ( empty( $links ) ) { |
504 if ( empty( $links ) ) { |
499 return array(); |
505 return array(); |
500 } |
506 } |
501 |
507 |
502 $curies = $response->get_curies(); |
508 $curies = $response->get_curies(); |
503 $used_curies = array(); |
509 $used_curies = array(); |
504 |
510 |
505 foreach ( $links as $rel => $items ) { |
511 foreach ( $links as $rel => $items ) { |
506 |
512 |
507 // Convert $rel URIs to their compact versions if they exist. |
513 // Convert $rel URIs to their compact versions if they exist. |
513 |
519 |
514 // Relation now changes from '$uri' to '$curie:$relation'. |
520 // Relation now changes from '$uri' to '$curie:$relation'. |
515 $rel_regex = str_replace( '\{rel\}', '(.+)', preg_quote( $curie['href'], '!' ) ); |
521 $rel_regex = str_replace( '\{rel\}', '(.+)', preg_quote( $curie['href'], '!' ) ); |
516 preg_match( '!' . $rel_regex . '!', $rel, $matches ); |
522 preg_match( '!' . $rel_regex . '!', $rel, $matches ); |
517 if ( $matches ) { |
523 if ( $matches ) { |
518 $new_rel = $curie['name'] . ':' . $matches[1]; |
524 $new_rel = $curie['name'] . ':' . $matches[1]; |
519 $used_curies[ $curie['name'] ] = $curie; |
525 $used_curies[ $curie['name'] ] = $curie; |
520 $links[ $new_rel ] = $items; |
526 $links[ $new_rel ] = $items; |
521 unset( $links[ $rel ] ); |
527 unset( $links[ $rel ] ); |
522 break; |
528 break; |
523 } |
529 } |
524 } |
530 } |
525 } |
531 } |
650 */ |
656 */ |
651 public function register_route( $namespace, $route, $route_args, $override = false ) { |
657 public function register_route( $namespace, $route, $route_args, $override = false ) { |
652 if ( ! isset( $this->namespaces[ $namespace ] ) ) { |
658 if ( ! isset( $this->namespaces[ $namespace ] ) ) { |
653 $this->namespaces[ $namespace ] = array(); |
659 $this->namespaces[ $namespace ] = array(); |
654 |
660 |
655 $this->register_route( $namespace, '/' . $namespace, array( |
661 $this->register_route( |
|
662 $namespace, |
|
663 '/' . $namespace, |
656 array( |
664 array( |
657 'methods' => self::READABLE, |
665 array( |
658 'callback' => array( $this, 'get_namespace_index' ), |
666 'methods' => self::READABLE, |
659 'args' => array( |
667 'callback' => array( $this, 'get_namespace_index' ), |
660 'namespace' => array( |
668 'args' => array( |
661 'default' => $namespace, |
669 'namespace' => array( |
662 ), |
670 'default' => $namespace, |
663 'context' => array( |
671 ), |
664 'default' => 'view', |
672 'context' => array( |
|
673 'default' => 'view', |
|
674 ), |
665 ), |
675 ), |
666 ), |
676 ), |
667 ), |
677 ) |
668 ) ); |
678 ); |
669 } |
679 } |
670 |
680 |
671 // Associative to avoid double-registration. |
681 // Associative to avoid double-registration. |
672 $this->namespaces[ $namespace ][ $route ] = true; |
682 $this->namespaces[ $namespace ][ $route ] = true; |
673 $route_args['namespace'] = $namespace; |
683 $route_args['namespace'] = $namespace; |
674 |
684 |
675 if ( $override || empty( $this->endpoints[ $route ] ) ) { |
685 if ( $override || empty( $this->endpoints[ $route ] ) ) { |
676 $this->endpoints[ $route ] = $route_args; |
686 $this->endpoints[ $route ] = $route_args; |
677 } else { |
687 } else { |
678 $this->endpoints[ $route ] = array_merge( $this->endpoints[ $route ], $route_args ); |
688 $this->endpoints[ $route ] = array_merge( $this->endpoints[ $route ], $route_args ); |
836 $args[ $param ] = $value; |
846 $args[ $param ] = $value; |
837 } |
847 } |
838 } |
848 } |
839 |
849 |
840 foreach ( $handlers as $handler ) { |
850 foreach ( $handlers as $handler ) { |
841 $callback = $handler['callback']; |
851 $callback = $handler['callback']; |
842 $response = null; |
852 $response = null; |
843 |
853 |
844 // Fallback to GET method if no HEAD method is registered. |
854 // Fallback to GET method if no HEAD method is registered. |
845 $checked_method = $method; |
855 $checked_method = $method; |
846 if ( 'HEAD' === $method && empty( $handler['methods']['HEAD'] ) ) { |
856 if ( 'HEAD' === $method && empty( $handler['methods']['HEAD'] ) ) { |
892 * Note that this filter will not be called for requests that |
902 * Note that this filter will not be called for requests that |
893 * fail to authenticate or match to a registered route. |
903 * fail to authenticate or match to a registered route. |
894 * |
904 * |
895 * @since 4.7.0 |
905 * @since 4.7.0 |
896 * |
906 * |
897 * @param WP_HTTP_Response $response Result to send to the client. Usually a WP_REST_Response. |
907 * @param WP_HTTP_Response|WP_Error $response Result to send to the client. Usually a WP_REST_Response or WP_Error. |
898 * @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server). |
908 * @param array $handler Route handler used for the request. |
899 * @param WP_REST_Request $request Request used to generate the response. |
909 * @param WP_REST_Request $request Request used to generate the response. |
900 */ |
910 */ |
901 $response = apply_filters( 'rest_request_before_callbacks', $response, $handler, $request ); |
911 $response = apply_filters( 'rest_request_before_callbacks', $response, $handler, $request ); |
902 |
912 |
903 if ( ! is_wp_error( $response ) ) { |
913 if ( ! is_wp_error( $response ) ) { |
904 // Check permission specified on the route. |
914 // Check permission specified on the route. |
920 * Allow plugins to override dispatching the request. |
930 * Allow plugins to override dispatching the request. |
921 * |
931 * |
922 * @since 4.4.0 |
932 * @since 4.4.0 |
923 * @since 4.5.0 Added `$route` and `$handler` parameters. |
933 * @since 4.5.0 Added `$route` and `$handler` parameters. |
924 * |
934 * |
925 * @param bool $dispatch_result Dispatch result, will be used if not empty. |
935 * @param mixed $dispatch_result Dispatch result, will be used if not empty. |
926 * @param WP_REST_Request $request Request used to generate the response. |
936 * @param WP_REST_Request $request Request used to generate the response. |
927 * @param string $route Route matched for the request. |
937 * @param string $route Route matched for the request. |
928 * @param array $handler Route handler used for the request. |
938 * @param array $handler Route handler used for the request. |
929 */ |
939 */ |
930 $dispatch_result = apply_filters( 'rest_dispatch_request', null, $request, $route, $handler ); |
940 $dispatch_result = apply_filters( 'rest_dispatch_request', null, $request, $route, $handler ); |
951 * Note that an endpoint's `permission_callback` can still be |
961 * Note that an endpoint's `permission_callback` can still be |
952 * called after this filter - see `rest_send_allow_header()`. |
962 * called after this filter - see `rest_send_allow_header()`. |
953 * |
963 * |
954 * @since 4.7.0 |
964 * @since 4.7.0 |
955 * |
965 * |
956 * @param WP_HTTP_Response $response Result to send to the client. Usually a WP_REST_Response. |
966 * @param WP_HTTP_Response|WP_Error $response Result to send to the client. Usually a WP_REST_Response or WP_Error. |
957 * @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server). |
967 * @param array $handler Route handler used for the request. |
958 * @param WP_REST_Request $request Request used to generate the response. |
968 * @param WP_REST_Request $request Request used to generate the response. |
959 */ |
969 */ |
960 $response = apply_filters( 'rest_request_after_callbacks', $response, $handler, $request ); |
970 $response = apply_filters( 'rest_request_after_callbacks', $response, $handler, $request ); |
961 |
971 |
962 if ( is_wp_error( $response ) ) { |
972 if ( is_wp_error( $response ) ) { |
963 $response = $this->error_to_response( $response ); |
973 $response = $this->error_to_response( $response ); |
1060 |
1070 |
1061 if ( ! isset( $this->namespaces[ $namespace ] ) ) { |
1071 if ( ! isset( $this->namespaces[ $namespace ] ) ) { |
1062 return new WP_Error( 'rest_invalid_namespace', __( 'The specified namespace could not be found.' ), array( 'status' => 404 ) ); |
1072 return new WP_Error( 'rest_invalid_namespace', __( 'The specified namespace could not be found.' ), array( 'status' => 404 ) ); |
1063 } |
1073 } |
1064 |
1074 |
1065 $routes = $this->namespaces[ $namespace ]; |
1075 $routes = $this->namespaces[ $namespace ]; |
1066 $endpoints = array_intersect_key( $this->get_routes(), $routes ); |
1076 $endpoints = array_intersect_key( $this->get_routes(), $routes ); |
1067 |
1077 |
1068 $data = array( |
1078 $data = array( |
1069 'namespace' => $namespace, |
1079 'namespace' => $namespace, |
1070 'routes' => $this->get_data_for_routes( $endpoints, $request['context'] ), |
1080 'routes' => $this->get_data_for_routes( $endpoints, $request['context'] ), |
1071 ); |
1081 ); |
1072 $response = rest_ensure_response( $data ); |
1082 $response = rest_ensure_response( $data ); |
1073 |
1083 |
1074 // Link to the root index. |
1084 // Link to the root index. |
1075 $response->add_link( 'up', rest_url( '/' ) ); |
1085 $response->add_link( 'up', rest_url( '/' ) ); |
1143 * @return array|null Data for the route, or null if no publicly-visible data. |
1153 * @return array|null Data for the route, or null if no publicly-visible data. |
1144 */ |
1154 */ |
1145 public function get_data_for_route( $route, $callbacks, $context = 'view' ) { |
1155 public function get_data_for_route( $route, $callbacks, $context = 'view' ) { |
1146 $data = array( |
1156 $data = array( |
1147 'namespace' => '', |
1157 'namespace' => '', |
1148 'methods' => array(), |
1158 'methods' => array(), |
1149 'endpoints' => array(), |
1159 'endpoints' => array(), |
1150 ); |
1160 ); |
1151 |
1161 |
1152 if ( isset( $this->route_options[ $route ] ) ) { |
1162 if ( isset( $this->route_options[ $route ] ) ) { |
1153 $options = $this->route_options[ $route ]; |
1163 $options = $this->route_options[ $route ]; |
1168 if ( empty( $callback['show_in_index'] ) ) { |
1178 if ( empty( $callback['show_in_index'] ) ) { |
1169 continue; |
1179 continue; |
1170 } |
1180 } |
1171 |
1181 |
1172 $data['methods'] = array_merge( $data['methods'], array_keys( $callback['methods'] ) ); |
1182 $data['methods'] = array_merge( $data['methods'], array_keys( $callback['methods'] ) ); |
1173 $endpoint_data = array( |
1183 $endpoint_data = array( |
1174 'methods' => array_keys( $callback['methods'] ), |
1184 'methods' => array_keys( $callback['methods'] ), |
1175 ); |
1185 ); |
1176 |
1186 |
1177 if ( isset( $callback['args'] ) ) { |
1187 if ( isset( $callback['args'] ) ) { |
1178 $endpoint_data['args'] = array(); |
1188 $endpoint_data['args'] = array(); |
1317 */ |
1327 */ |
1318 public function get_headers( $server ) { |
1328 public function get_headers( $server ) { |
1319 $headers = array(); |
1329 $headers = array(); |
1320 |
1330 |
1321 // CONTENT_* headers are not prefixed with HTTP_. |
1331 // CONTENT_* headers are not prefixed with HTTP_. |
1322 $additional = array( 'CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true ); |
1332 $additional = array( |
|
1333 'CONTENT_LENGTH' => true, |
|
1334 'CONTENT_MD5' => true, |
|
1335 'CONTENT_TYPE' => true, |
|
1336 ); |
1323 |
1337 |
1324 foreach ( $server as $key => $value ) { |
1338 foreach ( $server as $key => $value ) { |
1325 if ( strpos( $key, 'HTTP_' ) === 0 ) { |
1339 if ( strpos( $key, 'HTTP_' ) === 0 ) { |
1326 $headers[ substr( $key, 5 ) ] = $value; |
1340 $headers[ substr( $key, 5 ) ] = $value; |
1327 } elseif ( isset( $additional[ $key ] ) ) { |
1341 } elseif ( isset( $additional[ $key ] ) ) { |