Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support checking for a REST API request before the query is parsed #916

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions src/wp-includes/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,96 @@ function wp_doing_cron() {
return apply_filters( 'wp_doing_cron', defined( 'DOING_CRON' ) && DOING_CRON );
}

/**
* Determines whether the current request is a REST API request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CS Nit

Suggested change
* Determines whether the current request is a REST API request.
* Determine whether the current request is a REST API request.

*
* This function's accuracy cannot be guaranteed until the {@see 'parse_request'} hook is executing.
* Earlier usage uses an estimation and may not be accurate on highly customized server setups.
*
* @since 5.7.0
*
* @return bool True if it's a REST API request, false otherwise.
*/
function wp_doing_rest() {
if ( defined( 'REST_REQUEST' ) || did_action( 'parse_request' ) ) {
$doing_rest = defined( 'REST_REQUEST' ) && REST_REQUEST;

/** This filter is documented in wp-includes/load.php */
return apply_filters( 'wp_doing_rest', $doing_rest );
}

// This intentionally doesn't use wp_using_themes(). We are trying to check if wp() would be called for this request
// in a front-end context which is typically indicated by the WP_USE_THEMES constant.
Comment on lines +1511 to +1512
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/*
 * CS: multiline
 * comment format
 */

🔢

$doing_rest = defined( 'WP_USE_THEMES' ) && WP_USE_THEMES && isset( $_GET['rest_route'] );

if ( ! get_option( 'permalink_structure' ) || $doing_rest ) {
/** This filter is documented in wp-includes/load.php */
return apply_filters( 'wp_doing_rest', $doing_rest );
}

if ( isset( $GLOBALS['wp_rewrite'] ) ) {
$index = $GLOBALS['wp_rewrite']->index;
} else {
$index = 'index.php';
}

$pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is a mostly a copy-paste from WP but a couple of tiny things could be tidied up along the way.

Suggested change
$pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
$path_info = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';

🔢

list( $pathinfo ) = explode( '?', $pathinfo );
$pathinfo = str_replace( '%', '%25', $pathinfo );

list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core helper if it's defined when this runs.

Suggested change
$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
$home_path = trim( wp_parse_url( home_url(), PHP_URL_PATH ), '/' );

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the return value of home_url() does not contain a path (e.g. "https://example.com") then in PHP 8.1+ this results in a "trim(): Passing null to parameter #1 ($string) of type string is deprecated" warning.

Thus, this should probably be replaced with something like:

$home_url_path   = wp_parse_url( home_url(), PHP_URL_PATH );
$home_path       = $home_url_path ? trim( $home_url_path, '/' ) : '';

$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );

/*
* Trim path info from the end and the leading home path from the front.
* For path info requests, this leaves us with the requesting filename, if any.
* For 404 requests, this leaves us with the requested permalink.
*/
$req_uri = str_replace( $pathinfo, '', $req_uri );
$req_uri = trim( $req_uri, '/' );
$req_uri = preg_replace( $home_path_regex, '', $req_uri );
$req_uri = trim( $req_uri, '/' );
$pathinfo = trim( $pathinfo, '/' );
$pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
$pathinfo = trim( $pathinfo, '/' );

// The requested permalink is in $pathinfo for path info requests and
// $req_uri for other requests.
if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $index . '$|', $pathinfo ) ) {
$requested_path = $pathinfo;
} else {
// If the request uri is the index, blank it out so that we don't try to match it against a rule.
if ( $req_uri === $index ) {
$req_uri = '';
}
$requested_path = $req_uri;
}

$requested_file = $req_uri;
// Look for matches.
$request_match = $requested_path;

// If the requested file is the anchor of the match, prepend it to the path info.
if ( ! empty( $requested_file ) && $requested_file !== $requested_path ) {
$request_match = $requested_file . '/' . $requested_path;
}

$doing_rest = (
0 === strpos( trailingslashit( $request_match ), rest_get_url_prefix() . '/' ) ||
0 === strpos( trailingslashit( $request_match ), 'index.php/' . rest_get_url_prefix() . '/' )
);

/**
* Filters whether the current request is a REST API request.
*
* @since 5.7.0
*
* @param bool $doing_rest Whether the current request is a REST API request.
*/
return apply_filters( 'wp_doing_rest', $doing_rest );
}

/**
* Checks whether the given variable is a WordPress Error.
*
Expand Down