The current situation
We use the AWS SDK for PHP to store media files on S3 instead of the server's local storage, and use the wp_handle_upload
filter to point the inserted attachment to the S3 file URL instead of the local file path and delete the local file as well.
function upload_to_s3( $upload ) {
// MyS3Client, is a custom class that creates an S3Client object.
$s3client = new MyS3Client();
// myUploadMethod, is a custom method that stores the file on S3 and return its path.
$s3_path = $s3client->myUploadMethod( $upload );
// Delete the local file.
unlink( $upload['file'] );
// Alter the file URL to point to S3.
$upload['url'] = $s3_path;
$upload['file'] = $s3_path;
return $upload;
}
add_filter( 'wp_handle_upload', 'upload_to_s3' );
Something else, we don't generate any resized thumbnails from the original uploaded images; because we utilize the AWS Serverless Image Handler library to generate the needed sizes on the fly and serve them via CDN.
// Disable generating any resized thumbnails for the uploaded image.
add_action( 'intermediate_image_sizes_advanced', '__return_empty_array' );
So we insert these thumbnail sizes into DB manually; because WordPress uses some of them in the backend, like the images' thumbnails in the Media Library page, or the Media uploader form. At this point, we use the on-the-fly URL that will generate the thumbnails and store them on CDN.
function generate_cdn_thumbnails( $metadata, $attachment_id, $context ) {
if ( $context === 'create') {
$attachment_path = parse_url( wp_get_attachment_url( $attachment_id ) )['path'];
$metadata['sizes'] = [
'thumbnail' => [
'file' => 'https://cdn.example.com/fit-in/150x150' . $attachment_path,
'width' => 150,
'height' => 150,
'mime-type' => 'image/jpeg',
],
'medium' => [
'file' => 'https://cdn.example.com/fit-in/300x300' . $attachment_path,
'width' => 300,
'height' => 300,
'mime-type' => 'image/jpeg',
],
'large' => [
'file' => 'https://cdn.example.com/fit-in/1024x1024' . $attachment_path,
'width' => 1024,
'height' => 1024,
'mime-type' => 'image/jpeg',
],
];
}
return $metadata;
}
add_filter( 'wp_generate_attachment_metadata', 'generate_cdn_thumbnails', 10, 3 );
The problems
1. Generate the metadata of the image before unlink
it.
We know that WordPress can generate the metadata (width
, height
, filesize
, image_meta
, ...) of the local images only. So, either to generate them before unlink
the local file, or download the uploaded image from S3 to the server to generate these data.
Currently we unlink
the local file in the wp_handle_upload
hook, so the file will be deleted before generating the metadata in the wp_generate_attachment_metadata
hook.
Is there any better hook to use so we can unlink
the file after generating its metadata? And how to pass the full local path of the file to that hook to use it in the unlink
function?
2. Filter the resized CDN thumbnails URLs
In the generate_cdn_thumbnails
function above, we store the full CDN URL of the thumbnails that will be generated on the fly. But when displaying these thumbnails in the backend (Media Library page, for example), WordPress prepends the folder path of the original image to that full URL.
Suppose we have this URL of the thumbnail
size image:
https://cdn.example.com/fit-in/150x150/2022/07/18/my_image.jpg
The original (unlinked) image folder path https://www.example.com/wp-content/uploads/2022/07/18/
will be prepended to the thumbnail's full CDN URL, so the thumbnail will have this final URL (which is a broken URL) when displaying it on the Media page:
https://www.example.com/wp-content/uploads/2022/07/18/https://cdn.example.com/fit-in/150x150/2022/07/18/my_image.jpg
What is the proper hook to use to filter and fix the thumbnail URL before displaying it on the Media page?
webp
. I think we may of with these plugins if we didn't get a solution. And for the 2 questions, I know you are right, but both are related to each other and have almost the same core reason. Appreciate your understanding and your kind reply! Thank you!