diff -r 48c4eec2b7e6 -r 8c2e4d02f4ef wp/wp-includes/rest-api.php --- a/wp/wp-includes/rest-api.php Fri Sep 05 18:40:08 2025 +0200 +++ b/wp/wp-includes/rest-api.php Fri Sep 05 18:52:52 2025 +0200 @@ -38,26 +38,55 @@ * and namespace indexes. If you really need to register a * non-namespaced route, call `WP_REST_Server::register_route` directly. */ - _doing_it_wrong( 'register_rest_route', __( 'Routes must be namespaced with plugin or theme name and version.' ), '4.4.0' ); + _doing_it_wrong( + __FUNCTION__, + sprintf( + /* translators: 1: string value of the namespace, 2: string value of the route. */ + __( 'Routes must be namespaced with plugin or theme name and version. Instead there seems to be an empty namespace \'%1$s\' for route \'%2$s\'.' ), + '' . $route_namespace . '', + '' . $route . '' + ), + '4.4.0' + ); return false; } elseif ( empty( $route ) ) { - _doing_it_wrong( 'register_rest_route', __( 'Route must be specified.' ), '4.4.0' ); + _doing_it_wrong( + __FUNCTION__, + sprintf( + /* translators: 1: string value of the namespace, 2: string value of the route. */ + __( 'Route must be specified. Instead within the namespace \'%1$s\', there seems to be an empty route \'%2$s\'.' ), + '' . $route_namespace . '', + '' . $route . '' + ), + '4.4.0' + ); return false; } $clean_namespace = trim( $route_namespace, '/' ); if ( $clean_namespace !== $route_namespace ) { - _doing_it_wrong( __FUNCTION__, __( 'Namespace must not start or end with a slash.' ), '5.4.2' ); + _doing_it_wrong( + __FUNCTION__, + sprintf( + /* translators: 1: string value of the namespace, 2: string value of the route. */ + __( 'Namespace must not start or end with a slash. Instead namespace \'%1$s\' for route \'%2$s\' seems to contain a slash.' ), + '' . $route_namespace . '', + '' . $route . '' + ), + '5.4.2' + ); } if ( ! did_action( 'rest_api_init' ) ) { _doing_it_wrong( - 'register_rest_route', + __FUNCTION__, sprintf( - /* translators: %s: rest_api_init */ - __( 'REST API routes must be registered on the %s action.' ), - 'rest_api_init' + /* translators: 1: rest_api_init, 2: string value of the route, 3: string value of the namespace. */ + __( 'REST API routes must be registered on the %1$s action. Instead route \'%2$s\' with namespace \'%3$s\' was not registered on this action.' ), + 'rest_api_init', + '' . $route . '', + '' . $route_namespace . '' ), '5.1.0' ); @@ -401,6 +430,16 @@ return; } + // Return an error message if query_var is not a string. + if ( ! is_string( $GLOBALS['wp']->query_vars['rest_route'] ) ) { + $rest_type_error = new WP_Error( + 'rest_path_invalid_type', + __( 'The REST route parameter must be a string.' ), + array( 'status' => 400 ) + ); + wp_die( $rest_type_error ); + } + /** * Whether this is a REST Request. * @@ -789,9 +828,6 @@ } foreach ( $endpoints as $endpoint ) { - // Remove the redundant preg_match() argument. - unset( $args[0] ); - $request->set_url_params( $args ); $request->set_attributes( $endpoint ); } @@ -1275,6 +1311,9 @@ /** * Parses an RFC3339 time into a Unix timestamp. * + * Explicitly check for `false` to detect failure, as zero is a valid return + * value on success. + * * @since 4.4.0 * * @param string $date RFC3339 timestamp. @@ -1340,7 +1379,7 @@ $date = rest_parse_date( $date ); - if ( empty( $date ) ) { + if ( false === $date ) { return null; } @@ -2230,7 +2269,7 @@ break; case 'date-time': - if ( ! rest_parse_date( $value ) ) { + if ( false === rest_parse_date( $value ) ) { return new WP_Error( 'rest_invalid_date', __( 'Invalid date.' ) ); } break; @@ -2906,6 +2945,7 @@ } } + // Remove trailing slashes at the end of the REST API path (query part). $path = untrailingslashit( $path ); if ( empty( $path ) ) { $path = '/'; @@ -2916,6 +2956,14 @@ return $memo; } + if ( isset( $path_parts['path'] ) && '/' !== $path_parts['path'] ) { + // Remove trailing slashes from the "path" part of the REST API path. + $path_parts['path'] = untrailingslashit( $path_parts['path'] ); + $path = str_contains( $path, '?' ) ? + $path_parts['path'] . '?' . ( $path_parts['query'] ?? '' ) : + $path_parts['path']; + } + $request = new WP_REST_Request( $method, $path_parts['path'] ); if ( ! empty( $path_parts['query'] ) ) { parse_str( $path_parts['query'], $query_params );