Is it possibile to return a document (a generated PDF, a CSV) using the WP_REST_Response
in WordPress?
So far I've been registering a custom endpoint using register_rest_resource
but if I try to return a file (e.g. using PHP fpassthru($f)
or readfile($f)
I get the "Headers already sent" error.
Using other words: how you would return a file using Wordpress REST APIs?
Any help is appreciated!
Thanks
By default, all REST responses are passed through json_encode()
to return a JSON string. However, the REST server provides the WP hook rest_pre_serve_request
that we can use to return binary data instead.
Code sample:
<?php
/**
* Serves an image via the REST endpoint.
*
* By default, every REST response is passed through json_encode(), as the
* typical REST response contains JSON data.
*
* This method hooks into the REST server to return a binary image.
*
* @param string $path Absolute path to the image to serve.
* @param string $type The image mime type [png|jpg|gif]. Default is 'png'.
*
* @return WP_REST_Response The REST response object to serve an image.
*/
function my_serve_image( $path, $type = 'png' ) {
$response = new WP_REST_Response;
if ( file_exists( $path ) ) {
// Image exists, prepare a binary-data response.
$response->set_data( file_get_contents( $path ) );
$response->set_headers( [
'Content-Type' => "image/$type",
'Content-Length' => filesize( $path ),
] );
// HERE → This filter will return our binary image!
add_filter( 'rest_pre_serve_request', 'my_do_serve_image', 0, 2 );
} else {
// Return a simple "not-found" JSON response.
$response->set_data( 'not-found' );
$response->set_status( 404 );
}
return $response;
}
/**
* Action handler that is used by `serve_image()` to serve a binary image
* instead of a JSON string.
*
* @return bool Returns true, if the image was served; this will skip the
* default REST response logic.
*/
function my_do_serve_image( $served, $result ) {
$is_image = false;
$image_data = null;
// Check the "Content-Type" header to confirm that we really want to return
// binary image data.
foreach ( $result->get_headers() as $header => $value ) {
if ( 'content-type' === strtolower( $header ) ) {
$is_image = 0 === strpos( $value, 'image/' );
$image_data = $result->get_data();
break;
}
}
// Output the binary data and tell the REST server to not send any other
// details (via "return true").
if ( $is_image && is_string( $image_data ) ) {
echo $image_data;
return true;
}
return $served;
}
Sample usage:
<?php
// Register the REST endpoint.
register_rest_route( 'my_sample/v1', 'image', [
'method' => 'GET',
'callback' => 'my_rest_get_image'
] );
// Return the image data using our function above.
function my_rest_get_image() {
return my_serve_image( 'path/to/image.jpeg', 'jpg' );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With