W3cubDocs

/WordPress

WP_REST_Server::dispatch( WP_REST_Request $request )

Matches the request to a callback and call it.

Parameters

$request

(WP_REST_Request) (Required) Request to attempt dispatching.

Return

(WP_REST_Response) Response returned by the callback.

Source

File: wp-includes/rest-api/class-wp-rest-server.php

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();

		$with_namespace = array();

		foreach ( $this->get_namespaces() as $namespace ) {
			if ( 0 === strpos( trailingslashit( ltrim( $path, '/' ) ), $namespace ) ) {
				$with_namespace[] = $this->get_routes( $namespace );
			}
		}

		if ( $with_namespace ) {
			$routes = array_merge( ...$with_namespace );
		} else {
			$routes = $this->get_routes();
		}

		foreach ( $routes as $route => $handlers ) {
			$match = preg_match( '@^' . $route . '$@i', $path, $matches );

			if ( ! $match ) {
				continue;
			}

			$args = array();

			foreach ( $matches as $param => $value ) {
				if ( ! is_int( $param ) ) {
					$args[ $param ] = $value;
				}
			}

			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_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client. Usually a WP_REST_Response or WP_Error.
				 * @param array                                            $handler  Route handler used for the request.
				 * @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' => rest_authorization_required_code() )
							);
						}
					}
				}

				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 mixed           $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_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client. Usually a WP_REST_Response or WP_Error.
				 * @param array                                            $handler  Route handler used for the request.
				 * @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 )
			)
		);
	}

Changelog

Version Description
4.4.0 Introduced.

© 2003–2019 WordPress Foundation
Licensed under the GNU GPLv2+ License.
https://developer.wordpress.org/reference/classes/wp_rest_server/dispatch