--- a/wp/wp-includes/rest-api.php Mon Oct 14 18:06:33 2019 +0200
+++ b/wp/wp-includes/rest-api.php Mon Oct 14 18:28:13 2019 +0200
@@ -17,7 +17,10 @@
/**
* Registers a REST API route.
*
+ * Note: Do not use before the {@see 'rest_api_init'} hook.
+ *
* @since 4.4.0
+ * @since 5.1.0 Added a _doing_it_wrong() notice when not called on or after the rest_api_init hook.
*
* @param string $namespace The first URL segment after core prefix. Should be unique to your package/plugin.
* @param string $route The base URL for route you are adding.
@@ -36,11 +39,23 @@
*/
_doing_it_wrong( 'register_rest_route', __( 'Routes must be namespaced with plugin or theme name and version.' ), '4.4.0' );
return false;
- } else if ( empty( $route ) ) {
+ } elseif ( empty( $route ) ) {
_doing_it_wrong( 'register_rest_route', __( 'Route must be specified.' ), '4.4.0' );
return false;
}
+ if ( ! did_action( 'rest_api_init' ) ) {
+ _doing_it_wrong(
+ 'register_rest_route',
+ sprintf(
+ /* translators: %s: rest_api_init */
+ __( 'REST API routes must be registered on the %s action.' ),
+ '<code>rest_api_init</code>'
+ ),
+ '5.1.0'
+ );
+ }
+
if ( isset( $args['args'] ) ) {
$common_args = $args['args'];
unset( $args['args'] );
@@ -54,9 +69,9 @@
}
$defaults = array(
- 'methods' => 'GET',
- 'callback' => null,
- 'args' => array(),
+ 'methods' => 'GET',
+ 'callback' => null,
+ 'args' => array(),
);
foreach ( $args as $key => &$arg_group ) {
if ( ! is_numeric( $key ) ) {
@@ -64,7 +79,7 @@
continue;
}
- $arg_group = array_merge( $defaults, $arg_group );
+ $arg_group = array_merge( $defaults, $arg_group );
$arg_group['args'] = array_merge( $common_args, $arg_group['args'] );
}
@@ -141,10 +156,10 @@
function rest_api_register_rewrites() {
global $wp_rewrite;
- add_rewrite_rule( '^' . rest_get_url_prefix() . '/?$','index.php?rest_route=/','top' );
- add_rewrite_rule( '^' . rest_get_url_prefix() . '/(.*)?','index.php?rest_route=/$matches[1]','top' );
- add_rewrite_rule( '^' . $wp_rewrite->index . '/' . rest_get_url_prefix() . '/?$','index.php?rest_route=/','top' );
- add_rewrite_rule( '^' . $wp_rewrite->index . '/' . rest_get_url_prefix() . '/(.*)?','index.php?rest_route=/$matches[1]','top' );
+ add_rewrite_rule( '^' . rest_get_url_prefix() . '/?$', 'index.php?rest_route=/', 'top' );
+ add_rewrite_rule( '^' . rest_get_url_prefix() . '/(.*)?', 'index.php?rest_route=/$matches[1]', 'top' );
+ add_rewrite_rule( '^' . $wp_rewrite->index . '/' . rest_get_url_prefix() . '/?$', 'index.php?rest_route=/', 'top' );
+ add_rewrite_rule( '^' . $wp_rewrite->index . '/' . rest_get_url_prefix() . '/(.*)?', 'index.php?rest_route=/$matches[1]', 'top' );
}
/**
@@ -193,6 +208,11 @@
$revisions_controller = new WP_REST_Revisions_Controller( $post_type->name );
$revisions_controller->register_routes();
}
+
+ if ( 'attachment' !== $post_type->name ) {
+ $autosaves_controller = new WP_REST_Autosaves_Controller( $post_type->name );
+ $autosaves_controller->register_routes();
+ }
}
// Post types.
@@ -230,9 +250,32 @@
$controller = new WP_REST_Comments_Controller;
$controller->register_routes();
+ /**
+ * Filters the search handlers to use in the REST search controller.
+ *
+ * @since 5.0.0
+ *
+ * @param array $search_handlers List of search handlers to use in the controller. Each search
+ * handler instance must extend the `WP_REST_Search_Handler` class.
+ * Default is only a handler for posts.
+ */
+ $search_handlers = apply_filters( 'wp_rest_search_handlers', array( new WP_REST_Post_Search_Handler() ) );
+
+ $controller = new WP_REST_Search_Controller( $search_handlers );
+ $controller->register_routes();
+
+ // Block Renderer.
+ $controller = new WP_REST_Block_Renderer_Controller;
+ $controller->register_routes();
+
// Settings.
$controller = new WP_REST_Settings_Controller;
$controller->register_routes();
+
+ // Themes.
+ $controller = new WP_REST_Themes_Controller;
+ $controller->register_routes();
+
}
/**
@@ -307,6 +350,8 @@
$path = '/';
}
+ $path = '/' . ltrim( $path, '/' );
+
if ( is_multisite() && get_blog_option( $blog_id, 'permalink_structure' ) || get_option( 'permalink_structure' ) ) {
global $wp_rewrite;
@@ -316,7 +361,7 @@
$url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
}
- $url .= '/' . ltrim( $path, '/' );
+ $url .= $path;
} else {
$url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
// nginx only allows HTTP/1.0 methods when redirecting from / to /index.php
@@ -325,8 +370,6 @@
$url .= 'index.php';
}
- $path = '/' . ltrim( $path, '/' );
-
$url = add_query_arg( 'rest_route', $path, $url );
}
@@ -417,7 +460,7 @@
* @param string $class_name The name of the server class. Default 'WP_REST_Server'.
*/
$wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
- $wp_rest_server = new $wp_rest_server_class;
+ $wp_rest_server = new $wp_rest_server_class;
/**
* Fires when preparing to serve an API request.
@@ -569,15 +612,30 @@
}
$response = new WP_REST_Response();
- $data = array();
+ $data = array();
foreach ( $handler->get_routes() as $route => $endpoints ) {
- $match = preg_match( '@^' . $route . '$@i', $request->get_route() );
+ $match = preg_match( '@^' . $route . '$@i', $request->get_route(), $matches );
if ( ! $match ) {
continue;
}
+ $args = array();
+ foreach ( $matches as $param => $value ) {
+ if ( ! is_int( $param ) ) {
+ $args[ $param ] = $value;
+ }
+ }
+
+ foreach ( $endpoints as $endpoint ) {
+ // Remove the redundant preg_match argument.
+ unset( $args[0] );
+
+ $request->set_url_params( $args );
+ $request->set_attributes( $endpoint );
+ }
+
$data = $handler->get_data_for_route( $route, $endpoints, 'help' );
$response->set_matched_route( $route );
break;
@@ -651,7 +709,7 @@
$data = $response->get_data();
- $fields = is_array( $request['_fields'] ) ? $request['_fields'] : preg_split( '/[\s,]+/', $request['_fields'] );
+ $fields = wp_parse_list( $request['_fields'] );
if ( 0 === count( $fields ) ) {
return $response;
@@ -867,9 +925,9 @@
// cases.
if ( ! $is_utc && ! $has_timezone ) {
$local = date( 'Y-m-d H:i:s', $date );
- $utc = get_gmt_from_date( $local );
+ $utc = get_gmt_from_date( $local );
} else {
- $utc = date( 'Y-m-d H:i:s', $date );
+ $utc = date( 'Y-m-d H:i:s', $date );
$local = get_date_from_gmt( $utc );
}
@@ -982,7 +1040,7 @@
*/
function rest_sanitize_boolean( $value ) {
// String values are translated to `true`; make sure 'false' is false.
- if ( is_string( $value ) ) {
+ if ( is_string( $value ) ) {
$value = strtolower( $value );
if ( in_array( $value, array( 'false', '0' ), true ) ) {
$value = false;
@@ -990,7 +1048,7 @@
}
// Everything else will map nicely to boolean.
- return (boolean) $value;
+ return (bool) $value;
}
/**
@@ -1081,8 +1139,8 @@
*/
function rest_validate_value_from_schema( $value, $args, $param = '' ) {
if ( 'array' === $args['type'] ) {
- if ( ! is_array( $value ) ) {
- $value = preg_split( '/[\s,]+/', $value );
+ if ( ! is_null( $value ) ) {
+ $value = wp_parse_list( $value );
}
if ( ! wp_is_numeric_array( $value ) ) {
/* translators: 1: parameter, 2: type name */
@@ -1146,18 +1204,18 @@
if ( isset( $args['format'] ) ) {
switch ( $args['format'] ) {
- case 'date-time' :
+ case 'date-time':
if ( ! rest_parse_date( $value ) ) {
return new WP_Error( 'rest_invalid_date', __( 'Invalid date.' ) );
}
break;
- case 'email' :
+ case 'email':
if ( ! is_email( $value ) ) {
return new WP_Error( 'rest_invalid_email', __( 'Invalid email address.' ) );
}
break;
- case 'ip' :
+ case 'ip':
if ( ! rest_is_ip_address( $value ) ) {
/* translators: %s: IP address */
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $value ) );
@@ -1225,9 +1283,7 @@
if ( empty( $args['items'] ) ) {
return (array) $value;
}
- if ( ! is_array( $value ) ) {
- $value = preg_split( '/[\s,]+/', $value );
- }
+ $value = wp_parse_list( $value );
foreach ( $value as $index => $v ) {
$value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'] );
}
@@ -1270,19 +1326,19 @@
if ( isset( $args['format'] ) ) {
switch ( $args['format'] ) {
- case 'date-time' :
+ case 'date-time':
return sanitize_text_field( $value );
- case 'email' :
+ case 'email':
/*
* sanitize_email() validates, which would be unexpected.
*/
return sanitize_text_field( $value );
- case 'uri' :
+ case 'uri':
return esc_url_raw( $value );
- case 'ip' :
+ case 'ip':
return sanitize_text_field( $value );
}
}
@@ -1293,3 +1349,71 @@
return $value;
}
+
+/**
+ * Append result of internal request to REST API for purpose of preloading data to be attached to a page.
+ * Expected to be called in the context of `array_reduce`.
+ *
+ * @since 5.0.0
+ *
+ * @param array $memo Reduce accumulator.
+ * @param string $path REST API path to preload.
+ * @return array Modified reduce accumulator.
+ */
+function rest_preload_api_request( $memo, $path ) {
+ // array_reduce() doesn't support passing an array in PHP 5.2, so we need to make sure we start with one.
+ if ( ! is_array( $memo ) ) {
+ $memo = array();
+ }
+
+ if ( empty( $path ) ) {
+ return $memo;
+ }
+
+ $method = 'GET';
+ if ( is_array( $path ) && 2 === count( $path ) ) {
+ $method = end( $path );
+ $path = reset( $path );
+
+ if ( ! in_array( $method, array( 'GET', 'OPTIONS' ), true ) ) {
+ $method = 'GET';
+ }
+ }
+
+ $path_parts = parse_url( $path );
+ if ( false === $path_parts ) {
+ return $memo;
+ }
+
+ $request = new WP_REST_Request( $method, $path_parts['path'] );
+ if ( ! empty( $path_parts['query'] ) ) {
+ parse_str( $path_parts['query'], $query_params );
+ $request->set_query_params( $query_params );
+ }
+
+ $response = rest_do_request( $request );
+ if ( 200 === $response->status ) {
+ $server = rest_get_server();
+ $data = (array) $response->get_data();
+ $links = $server->get_compact_response_links( $response );
+ if ( ! empty( $links ) ) {
+ $data['_links'] = $links;
+ }
+
+ if ( 'OPTIONS' === $method ) {
+ $response = rest_send_allow_header( $response, $server, $request );
+
+ $memo[ $method ][ $path ] = array(
+ 'body' => $data,
+ 'headers' => $response->headers,
+ );
+ } else {
+ $memo[ $path ] = array(
+ 'body' => $data,
+ 'headers' => $response->headers,
+ );
+ }
+ }
+
+ return $memo;
+}