public function dispatch($request)
{
/**
* Filters the pre-calculated result of a REST dispatch request.
*
* Allow hijacking the request before dispatching by returning a non-empty. The returned value
* will be used to serve the request instead.
*
* @since 4.4.0
*
* @param mixed $result Response to replace the requested version with. Can be anything
* a normal endpoint can return, or null to not hijack the request.
* @param WP_REST_Server $this Server instance.
* @param WP_REST_Request $request Request used to generate the response.
*/
$result = apply_filters('rest_pre_dispatch', null, $this, $request);
if (!empty($result)) {
return $result;
}
$method = $request->get_method();
$path = $request->get_route();
foreach ($this->get_routes() as $route => $handlers) {
$match = preg_match('@^' . $route . '$@i', $path, $args);
if (!$match) {
continue;
}
foreach ($handlers as $handler) {
$callback = $handler['callback'];
$response = null;
// Fallback to GET method if no HEAD method is registered.
$checked_method = $method;
if ('HEAD' === $method && empty($handler['methods']['HEAD'])) {
$checked_method = 'GET';
}
if (empty($handler['methods'][$checked_method])) {
continue;
}
if (!is_callable($callback)) {
$response = new WP_Error('rest_invalid_handler', __('The handler for the route is invalid'), array('status' => 500));
}
if (!is_wp_error($response)) {
// Remove the redundant preg_match argument.
unset($args[0]);
$request->set_url_params($args);
$request->set_attributes($handler);
$defaults = array();
foreach ($handler['args'] as $arg => $options) {
if (isset($options['default'])) {
$defaults[$arg] = $options['default'];
}
}
$request->set_default_params($defaults);
$check_required = $request->has_valid_params();
if (is_wp_error($check_required)) {
$response = $check_required;
} else {
$check_sanitized = $request->sanitize_params();
if (is_wp_error($check_sanitized)) {
$response = $check_sanitized;
}
}
}
/**
* Filters the response before executing any REST API callbacks.
*
* Allows plugins to perform additional validation after a
* request is initialized and matched to a registered route,
* but before it is executed.
*
* Note that this filter will not be called for requests that
* fail to authenticate or match to a registered route.
*
* @since 4.7.0
*
* @param WP_HTTP_Response $response Result to send to the client. Usually a WP_REST_Response.
* @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
* @param WP_REST_Request $request Request used to generate the response.
*/
$response = apply_filters('rest_request_before_callbacks', $response, $handler, $request);
if (!is_wp_error($response)) {
// Check permission specified on the route.
if (!empty($handler['permission_callback'])) {
$permission = call_user_func($handler['permission_callback'], $request);
if (is_wp_error($permission)) {
$response = $permission;
} elseif (false === $permission || null === $permission) {
$response = new WP_Error('rest_forbidden', __('Sorry, you are not allowed to do that.'), array('status' => 403));
}
}
}
if (!is_wp_error($response)) {
/**
* Filters the REST dispatch request result.
*
* Allow plugins to override dispatching the request.
*
* @since 4.4.0
* @since 4.5.0 Added `$route` and `$handler` parameters.
*
* @param bool $dispatch_result Dispatch result, will be used if not empty.
* @param WP_REST_Request $request Request used to generate the response.
* @param string $route Route matched for the request.
* @param array $handler Route handler used for the request.
*/
$dispatch_result = apply_filters('rest_dispatch_request', null, $request, $route, $handler);
// Allow plugins to halt the request via this filter.
if (null !== $dispatch_result) {
$response = $dispatch_result;
} else {
$response = call_user_func($callback, $request);
}
}
/**
* Filters the response immediately after executing any REST API
* callbacks.
*
* Allows plugins to perform any needed cleanup, for example,
* to undo changes made during the {@see 'rest_request_before_callbacks'}
* filter.
*
* Note that this filter will not be called for requests that
* fail to authenticate or match to a registered route.
*
* Note that an endpoint's `permission_callback` can still be
* called after this filter - see `rest_send_allow_header()`.
*
* @since 4.7.0
*
* @param WP_HTTP_Response $response Result to send to the client. Usually a WP_REST_Response.
* @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
* @param WP_REST_Request $request Request used to generate the response.
*/
$response = apply_filters('rest_request_after_callbacks', $response, $handler, $request);
if (is_wp_error($response)) {
$response = $this->error_to_response($response);
} else {
$response = rest_ensure_response($response);
}
$response->set_matched_route($route);
$response->set_matched_handler($handler);
return $response;
}
}
return $this->error_to_response(new WP_Error('rest_no_route', __('No route was found matching the URL and request method'), array('status' => 404)));
}