diff --git a/readme.md b/readme.md index 326a6c6..be70fc8 100644 --- a/readme.md +++ b/readme.md @@ -6,11 +6,11 @@ BU Media S3 is a WordPress plugin designed to work with the [Human Made S3 Uploa - **S3 Upload Directory**: The plugin filters the `upload_dir` hook and rewrites the values in a way that is compatible with the S3 Uploads plugin and the BU Protected S3 Object Lambda stack, redirecting all media uploads to the S3 bucket. It also changes the default upload location from `wp-content/uploads` to `files`, which is the convention for BU WordPress sites. -- **Prevent Image Scaling**: By default, WordPress generates a scaled derivative for every image size that is defined for the current site. Because the BU Protected S3 Object Lambda stack handles image resizing automatically, the WordPress media library only needs to handle the full sized original upload. This plugin tells WordPress not to generate any derivative sizes on upload. It preserves the attachment metadata for all of the defined sizes by generating it directly during the upload process. +- **Prevent Image Scaling**: By default, WordPress generates scaled derivatives for every image size defined for the current site. This plugin sets a custom filter flag during the upload process and uses it to interpose a custom Image Editor object. This approach leverages the technique used by the S3 Uploads plugin, ensuring that the core WordPress image size metadata generation remains intact while skipping the actual resizing. This allows the BU Protected S3 Object Lambda stack to handle image resizing automatically, and preserves the attachment metadata for all defined sizes. -- **Suppress Big Image Threshold Resizing**: WordPress 5.3 introduced a new feature that automatically resizes images for "web-ready" dimensions. This plugin suppresses this feature, allowing you to upload images at their full size. +- **Suppress Big Image Threshold Resizing**: WordPress 5.3 introduced a feature that automatically resizes images to "web-ready" dimensions. This plugin suppresses this feature, allowing you to upload images at their full size. -- **DynamoDB Crop Data**: This plugin provides a way to write crop data to DynamoDB. The BU Protected S3 Object Lambda stack can read this crop data and apply it when the image is requested. The site-manager plugin automatically writes crop data to DynamoDB when a sites are moved or cloned. I'm not sure about site creation though, that might be a todo. +- **DynamoDB Crop Data**: This plugin provides a way to write crop data to DynamoDB. The BU Protected S3 Object Lambda stack can read this crop data and apply it when the image is requested. The site-manager plugin automatically writes crop data to DynamoDB when sites are moved or cloned. Site creation might be a todo. - **Handle Site File Deletion**: When a site is deleted, this plugin handles the deletion of files from S3 and the corresponding crop data in DynamoDB. It deletes both the original and derivative images from S3. diff --git a/src/filters.php b/src/filters.php index 9250554..6259b03 100644 --- a/src/filters.php +++ b/src/filters.php @@ -52,75 +52,35 @@ function s3_multisite_upload_dir( $upload ) { } add_filter( 'upload_dir', __NAMESPACE__ . '\s3_multisite_upload_dir' ); -// Conditionally adds a filter only during the upload process, this filter adds a second filter that removes all the image sizes. -// It also adds a filter to preemptively add the sizes to the attachment metadata, otherwise the first filter would prevent the sizes from being added. +// Add a custom filter to indicate that this is an upload request. add_filter( 'wp_handle_upload', function( $file ) { - // This filters the image sizes that are generated during the upload process, removing all of them by returning an empty array. - add_filter( - 'image_resize_dimensions', - function( $orig_w, $orig_h ) { - return array(); - }, - 10, - 6 - ); - - // Preemptively add the sizes to the attachment metadata. - add_filter( - 'wp_generate_attachment_metadata', - __NAMESPACE__ . '\generate_metadata_sizes', - 10, - 2 - ); + // Set a custom flag to indicate that this is an upload request. + add_filter('is_upload_request', '__return_true'); + + // May still want to set a generate_metadata filter here to add the file size, which seems to be getting dropped. // We need to pass along the original prefilter value unaltered; we're not actually changing it, just using it as a hook for the resize filter. return $file; } ); -/** - * Generate metadata for image sizes without creating the actual resized images. - * - * This function gets the registered image sizes and calculates the filename for each size - * using the WordPress convention for size annotation. It then adds this information to the attachment metadata. - * - * This function is designed to be added to the wp_handle_upload_prefilter in order to restore the metadata that - * would have been generated. Becuase the sizes are being suppressed on upload, the actual resized images - * are not being created, but we still need to add the metadata for the sizes to the attachment. This function - * should have the effect of pre-generating the metadata for the sizes that would have been created. - * - * @param array $metadata The attachment metadata. - * @param int $attachment_id The ID of the attachment. - * - * @return array The modified attachment metadata, with added sizes. - */ -function generate_metadata_sizes( $metadata, $attachment_id ) { - // Get the registered image sizes. - $sizes = wp_get_registered_image_subsizes(); - - // Get the pathinfo for the original file. - $pathinfo = pathinfo( $metadata['file'] ); - - // Get the mime type for the original file. - $mime_type = get_post_mime_type( $attachment_id ); - - // Recalculate the sizes that would have been generated and add them to the metadata. - foreach ( $sizes as $size => $size_data ) { - // Calcualte the new filename by adding the size to the original filename using the WordPress convention. - $new_filename = $pathinfo['filename'] . '-' . $size_data['width'] . 'x' . $size_data['height'] . '.' . $pathinfo['extension']; - - // Add the new size to the metadata. - $metadata['sizes'][ $size ] = array( - 'file' => $new_filename, - 'width' => $size_data['width'], - 'height' => $size_data['height'], - 'mime-type' => $mime_type, - ); +// Add a custom filter to suppress resized image generation during the upload process. +add_filter( 'wp_image_editors', function( $editors ) { + // Check if the custom flag indicating an upload request is set. + if ( apply_filters('is_upload_request', false) ) { + // This is an upload request, so we should use the custom image editor that skips saving the image to S3. + // Include the custom image editor that skips saving the image to S3. + require_once dirname( __FILE__ ) . '/s3uploads-plugin/class-skip-save-image-editor.php'; + + // Add the custom image editor to the list of available editors as the first editor, so that's what WordPress uses. + array_unshift( $editors, 'BU\Plugins\MediaS3\Skip_Save_Image_Editor' ); } - return $metadata; -} + + // Return the list of editors. + return $editors; +} ); // Disable the big image threshold, we don't want WordPress to do any resizing at all. add_filter( 'big_image_size_threshold', '__return_false' ); diff --git a/src/s3uploads-plugin/class-skip-save-image-editor.php b/src/s3uploads-plugin/class-skip-save-image-editor.php new file mode 100644 index 0000000..bcef063 --- /dev/null +++ b/src/s3uploads-plugin/class-skip-save-image-editor.php @@ -0,0 +1,52 @@ +get_output_format( $filename, $mime_type ); + + // Crucially, we need to determine the filename so we can return it correctly in the response. + if ( ! $filename ) { + $filename = parent::generate_filename( null, null, $extension ); + } + + // We don't want to save the image to S3, so we don't call the parent::_save method. + + // Return the metadata for the image. + $response = [ + 'path' => $filename, + 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ), + 'width' => $this->size['width'] ?? 0, + 'height' => $this->size['height'] ?? 0, + 'mime-type' => $mime_type, + ]; + + return $response; + } +}