Suppose I have a custom Wordpress REST API route and I throw an unhandled exception in the callback:
register_rest_route( $namespace, "/test", [
"methods" => "get",
"permission_callback" => "__return_true",
"callback" => function( $req ) {
throw new \Exception( "Error!!" );
}
]);
If I query the route, Wordpress returns an HTML page that shows an error message, which is fine for themes or the admin area, but for the REST API I would rather return a WP_Error
.
I guess I could put a try/catch block around the callback code, like this:
register_rest_route( $namespace, "/test", [
"methods" => "get",
"permission_callback" => "__return_true",
"callback" => function( $req ) {
try {
throw new \Exception( "Error!!" );
} catch( \Throwable $e ) {
return new \WP_Error( "rest_error", $e->get_error_message() );
}
}
]);
But then I would have to do that for all my custom routes, right?
Is there any way that I can set a "global" default response for uncaught exceptions thrown in any custom endpoint?
CodePudding user response:
I've found a way to do it with set_exception_handler
. Not sure if this is the best way, but it seems to work:
set_exception_handler( array( $this, "handle_uncaught_exceptions" ) );
public function handle_uncaught_exceptions( \Throwable $e ) {
// First of all, log the exception
log_from_exception( "errors", "alert", $e );
// Now we have to return a response. By default, when an uncaught exception is thrown (fatal error) Wordpress returns
// an HTML page with an error message. That is fine eg. for a theme or the admin area, but for REST requests we'd rather
// return a response that looks like a \WP_REST_Response
if( is_rest_request() ) {
// Set the response code to 500
http_response_code(500);
// Set the cross-domain headers
header( "Access-Control-Allow-Origin: " . $_ENV["FRONTEND_URL"];
header( "Access-Control-Allow-Credentials: true" );
// Send the response
$response = [
"code" => "rest_fatal_error",
"message" => "A fatal error occurred"
];
wp_send_json( $response );
} else {
// For non-REST requests, we want to reset the default behavior, ie. sending an HTML page with an error message
wp_die( $e->getMessage() );
}
}
is_rest_request
is a custom function:
function is_rest_request() {
$uri = $_SERVER["REQUEST_URI"];
if ( empty( $uri ) ) {
return false;
}
$restPrefix = trailingslashit( rest_get_url_prefix() ); // Resolves to "wp-json/"
$isRestApiRequest = strpos( $uri, $restPrefix ) !== false;
return $isRestApiRequest;
}