From 51a3bb5c5a64704422aa8a96314fc4513c8a5e35 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 13:05:00 -0600 Subject: [PATCH 01/16] Prevent to execute the logic when the sizes does not exists. --- modules/images/webp-uploads/load.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index c0b0098eb2..ad898615cc 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -26,6 +26,10 @@ * @return array An array with the updated structure for the metadata before is stored in the database. */ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) { + // Make sure we have some sizes to work with, otherwise avoid any work. + if ( empty( $metadata['sizes'] ) || ! is_array( $metadata['sizes'] ) ) { + return $metadata; + } // This should take place only on the JPEG image. $valid_mime_transforms = webp_uploads_get_supported_image_mime_transforms(); From 50b642e563b690a7cc5ad59f0ad08813fda52506 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 13:06:28 -0600 Subject: [PATCH 02/16] Remove non required variables and replace values in place. Replace the values in place without the need of extra variables, in order to update the metadta as soon as an image was uploaded. This `in place` mechanism allow us to remove the need for additional variables. --- modules/images/webp-uploads/load.php | 57 +++++++++++++--------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index ad898615cc..7b2272f99a 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -46,60 +46,55 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) return $metadata; } - $dirname = pathinfo( $file, PATHINFO_DIRNAME ); - $image_sizes = array(); - if ( array_key_exists( 'sizes', $metadata ) && is_array( $metadata['sizes'] ) ) { - $image_sizes = $metadata['sizes']; - } - - foreach ( wp_get_registered_image_subsizes() as $size_name => $properties ) { - // This image size does not exist on the defined sizes. - if ( ! isset( $image_sizes[ $size_name ] ) || ! is_array( $image_sizes[ $size_name ] ) ) { + $dirname = pathinfo( $file, PATHINFO_DIRNAME ); + foreach ( $metadata['sizes'] as $size_name => $properties ) { + // This image size is not defined or not an array. + if ( ! isset( $metadata['sizes'][ $size_name ] ) || ! is_array( $metadata['sizes'][ $size_name ] ) ) { continue; } - $current_size = $image_sizes[ $size_name ]; - $sources = array(); - if ( isset( $current_size['sources'] ) && is_array( $current_size['sources'] ) ) { - $sources = $current_size['sources']; + // Ensure a `sources` property exists on the existing size. + if ( empty( $metadata['sizes'][ $size_name ]['sources'] ) || ! is_array( $metadata['sizes'][ $size_name ]['sources'] ) ) { + $metadata['sizes'][ $size_name ]['sources'] = array(); } // Try to find the mime type of the image size. $current_mime = ''; - if ( isset( $current_size['mime-type'] ) ) { - $current_mime = $current_size['mime-type']; - } elseif ( isset( $current_size['file'] ) ) { - $current_mime = wp_check_filetype( $current_size['file'] )['type']; + if ( isset( $properties['mime-type'] ) ) { + $current_mime = $properties['mime-type']; + } elseif ( isset( $properties['file'] ) ) { + $current_mime = wp_check_filetype( $properties['file'] )['type']; } + // The mime type can't be determined. if ( empty( $current_mime ) ) { continue; } - $sources[ $current_mime ] = array( - 'file' => array_key_exists( 'file', $current_size ) ? $current_size['file'] : '', - 'filesize' => 0, - ); - - // Set the filesize from the current mime image. - $file_location = path_join( $dirname, $sources[ $current_mime ]['file'] ); - if ( file_exists( $file_location ) ) { - $sources[ $current_mime ]['filesize'] = filesize( $file_location ); + if ( empty( $metadata['sizes'][ $size_name ]['sources'][ $current_mime ] ) ) { + $metadata['sizes'][ $size_name ]['sources'][ $current_mime ] = array( + 'file' => array_key_exists( 'file', $properties ) ? $properties['file'] : '', + 'filesize' => 0, + ); + // Set the filesize from the current mime image. + $file_location = path_join( $dirname, $properties['file'] ); + if ( file_exists( $file_location ) ) { + $metadata['sizes'][ $size_name ]['sources'][ $current_mime ]['filesize'] = filesize( $file_location ); + } + wp_update_attachment_metadata( $attachment_id, $metadata ); } $formats = isset( $valid_mime_transforms[ $current_mime ] ) ? $valid_mime_transforms[ $current_mime ] : array(); foreach ( $formats as $mime ) { - if ( empty( $sources[ $mime ] ) ) { + if ( empty( $metadata['sizes'][ $size_name ]['sources'][ $mime ] ) ) { $source = webp_uploads_generate_image_size( $attachment_id, $size_name, $mime ); if ( is_array( $source ) ) { - $sources[ $mime ] = $source; + $metadata['sizes'][ $size_name ]['sources'][ $mime ] = $source; + wp_update_attachment_metadata( $attachment_id, $metadata ); } } } - - $current_size['sources'] = $sources; - $metadata['sizes'][ $size_name ] = $current_size; } return $metadata; From 22bfc4349d47894bdf6b7943c9d8e3a8c43c6987 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 13:07:15 -0600 Subject: [PATCH 03/16] Introduce retry mechanism when image fails to upload. In constrained environments when the image fails to upload a retry process would be trigger, this process only should be executed on Ajax or REST endpoint. --- modules/images/webp-uploads/load.php | 50 +++++ .../images/webp-uploads/webp-uploads-test.php | 180 ++++++++++++++++++ 2 files changed, 230 insertions(+) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 7b2272f99a..e5fc2d50d6 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -284,3 +284,53 @@ function webp_uploads_remove_sources_files( $attachment_id ) { } add_action( 'delete_attachment', 'webp_uploads_remove_sources_files', 10, 1 ); + +/** + * Filter on `wp_get_missing_image_subsizes` acting as an action for the logic of the plugin + * to determine if additional mime types still need to be created. + * + * @since n.e.x.t + * + * @see wp_get_missing_image_subsizes() + * + * @param array[] $missing_sizes Associative array of arrays of image sub-size. + * @param array $image_meta The metadata from the image. + * @param int $attachment_id The ID of the attachment. + * + * @return array[] $missing_sizes Associative array of arrays of image sub-size. + */ +function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta, $attachment_id ) { + if ( _webp_uploads_is_valid_ajax_for_image_sizes() || _webp_uploads_is_valid_rest_for_post_process( file_get_contents( 'php://input' ) ) ) { + webp_uploads_create_sources_property( $image_meta, $attachment_id ); + } + + return $missing_sizes; +} + +/** + * Determine if the current request is a valid request to process missing image sizes, executed + * via ajax. + * + * @return bool `true` if the current request is a valid ajax request to recreate missing image sizes. + */ +function _webp_uploads_is_valid_ajax_for_image_sizes() { + return wp_doing_ajax() && isset( $_REQUEST['action'], $_REQUEST['attachment_id'] ) && 'media-create-image-subsizes' === $_REQUEST['action'] && $_REQUEST['attachment_id'] > 0; +} + +/** + * Determine if the provided REST request goes to the appropriate endpoint with the right action. + * + * @param string $body The body from the request. + * + * @return bool `true` if the current request is a valid REST request to process + */ +function _webp_uploads_is_valid_rest_for_post_process( $body = '' ) { + $matches = array(); + $body = json_decode( $body, true ); + $valid_rest = defined( 'REST_REQUEST' ) && REST_REQUEST; + $valid_route = $valid_rest && isset( $GLOBALS['wp'], $GLOBALS['wp']->query_vars['rest_route'] ) && preg_match( '/media\/\d+\/post-process/', $GLOBALS['wp']->query_vars['rest_route'], $matches ); + + return $valid_route && ! empty( $matches ) && ! empty( $body['action'] ) && $body['action'] === 'create-image-subsizes'; +} + +add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 ); diff --git a/tests/modules/images/webp-uploads/webp-uploads-test.php b/tests/modules/images/webp-uploads/webp-uploads-test.php index 6f631e21dd..03bc223e10 100644 --- a/tests/modules/images/webp-uploads/webp-uploads-test.php +++ b/tests/modules/images/webp-uploads/webp-uploads-test.php @@ -385,4 +385,184 @@ public function it_should_remove_the_webp_version_of_the_image_if_the_image_is_f path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) ); } + + /** + * Process a request where ajax is not defined + * + * @test + */ + public function it_should_process_a_request_where_ajax_is_not_defined() { + add_filter( 'wp_doing_ajax', '__return_false' ); + $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); + } + + /** + * Process an ajax request with no additional parameters + * + * @test + */ + public function it_should_process_an_ajax_request_with_no_additional_parameters() { + // Simulate ajax request. + add_filter( 'wp_doing_ajax', '__return_true' ); + $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); + } + + /** + * Process an ajax request with invalid action + * + * @test + */ + public function it_should_process_an_ajax_request_with_invalid_action() { + // Simulate ajax request. + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'invalid-action'; + $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); + } + + /** + * Process an ajax request with only the attachment id is included in the request + * + * @test + */ + public function it_should_process_an_ajax_request_with_only_the_attachment_id_is_included_in_the_request() { + // Simulate ajax request. + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['attachment_id'] = 1; + $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); + } + + /** + * Process an ajax request with invalid attachment id + * + * @test + */ + public function it_should_process_an_ajax_request_with_invalid_attachment_id() { + // Simulate ajax request. + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'media-create-image-subsizes'; + $_REQUEST['attachment_id'] = 0; + $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); + } + + /** + * Process an ajax request with valid request parameters + * + * @test + */ + public function it_should_process_an_ajax_request_with_valid_request_parameters() { + // Simulate ajax request. + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'media-create-image-subsizes'; + $_REQUEST['attachment_id'] = 1; + $this->assertTrue( _webp_uploads_is_valid_ajax_for_image_sizes() ); + } + + /** + * Process a rest request when rest is not defined + * + * @test + */ + public function it_should_process_a_rest_request_when_rest_is_not_defined() { + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); + } + + /** + * Process a REST request when the global wp is not defined + * + * @test + */ + public function it_should_process_a_rest_request_when_the_global_wp_is_not_defined() { + define('REST_REQUEST', true); + rest_get_server()->dispatch(new WP_REST_Request()); + unset( $GLOBALS['wp'] ); + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); + } + + /** + * should process a REST request when the rest route query variable is not set + * + * @test + */ + public function it_should_should_process_a_rest_request_when_the_rest_route_query_variable_is_not_set() { + define('REST_REQUEST', true); + $GLOBALS['wp'] = new WP(); + + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); + } + + /** + * process a REST request when the query vars is set to a different route + * + * @dataProvider provider_rest_route + * + * @test + */ + public function it_should_process_a_rest_request_when_the_query_vars_is_set_to_a_different_route( $route ) { + define('REST_REQUEST', true); + $GLOBALS['wp'] = new WP(); + $GLOBALS['wp']->query_vars['rest_route'] = $route; + + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); + } + + public function provider_rest_route() { + yield 'media route' => array( '/wp/v2/media' ); + yield 'single attachment route' => array( '/wp/v2/media/1' ); + yield 'edit attachment route' => array( '/wp/v2/media/1/edit' ); + } + + /** + * Process a REST request when dispatched to the right endpoint + * + * @test + */ + public function it_should_process_a_rest_request_when_dispatched_to_the_right_endpoint() { + define('REST_REQUEST', true); + $GLOBALS['wp'] = new WP(); + $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; + + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); + } + + /** + * Process a REST request when an action is provided + * + * @test + */ + public function it_should_process_a_rest_request_when_an_action_is_provided() { + define('REST_REQUEST', true); + $GLOBALS['wp'] = new WP(); + $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; + $body = wp_json_encode( array( 'action' => 'subsizes' ) ); + + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process( $body ) ); + } + + /** + * Process a REST request with invalid JSON payload + * + * @test + */ + public function it_should_process_a_rest_request_with_invalid_json_payload() { + define('REST_REQUEST', true); + $GLOBALS['wp'] = new WP(); + $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; + $body = ']]]]]][[][][]'; + + $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process( $body ) ); + } + + /** + * Process a REST request when the right action is provided + * + * @test + */ + public function it_should_process_a_rest_request_when_the_right_action_is_provided() { + define('REST_REQUEST', true); + $GLOBALS['wp'] = new WP(); + $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; + $body = wp_json_encode( array( 'action' => 'create-image-subsizes' ) ); + + $this->assertTrue( _webp_uploads_is_valid_rest_for_post_process( $body ) ); + } } From fd0e1e352a9ff0405a83040832613d376725156d Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 13:08:16 -0600 Subject: [PATCH 04/16] Fix PHP linting error --- modules/images/webp-uploads/load.php | 2 +- .../images/webp-uploads/webp-uploads-test.php | 42 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index e5fc2d50d6..25930790bc 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -330,7 +330,7 @@ function _webp_uploads_is_valid_rest_for_post_process( $body = '' ) { $valid_rest = defined( 'REST_REQUEST' ) && REST_REQUEST; $valid_route = $valid_rest && isset( $GLOBALS['wp'], $GLOBALS['wp']->query_vars['rest_route'] ) && preg_match( '/media\/\d+\/post-process/', $GLOBALS['wp']->query_vars['rest_route'], $matches ); - return $valid_route && ! empty( $matches ) && ! empty( $body['action'] ) && $body['action'] === 'create-image-subsizes'; + return $valid_route && ! empty( $matches ) && ! empty( $body['action'] ) && 'create-image-subsizes' === $body['action']; } add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 ); diff --git a/tests/modules/images/webp-uploads/webp-uploads-test.php b/tests/modules/images/webp-uploads/webp-uploads-test.php index 03bc223e10..dab8bd2c81 100644 --- a/tests/modules/images/webp-uploads/webp-uploads-test.php +++ b/tests/modules/images/webp-uploads/webp-uploads-test.php @@ -439,7 +439,7 @@ public function it_should_process_an_ajax_request_with_only_the_attachment_id_is public function it_should_process_an_ajax_request_with_invalid_attachment_id() { // Simulate ajax request. add_filter( 'wp_doing_ajax', '__return_true' ); - $_REQUEST['action'] = 'media-create-image-subsizes'; + $_REQUEST['action'] = 'media-create-image-subsizes'; $_REQUEST['attachment_id'] = 0; $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); } @@ -452,7 +452,7 @@ public function it_should_process_an_ajax_request_with_invalid_attachment_id() { public function it_should_process_an_ajax_request_with_valid_request_parameters() { // Simulate ajax request. add_filter( 'wp_doing_ajax', '__return_true' ); - $_REQUEST['action'] = 'media-create-image-subsizes'; + $_REQUEST['action'] = 'media-create-image-subsizes'; $_REQUEST['attachment_id'] = 1; $this->assertTrue( _webp_uploads_is_valid_ajax_for_image_sizes() ); } @@ -472,34 +472,34 @@ public function it_should_process_a_rest_request_when_rest_is_not_defined() { * @test */ public function it_should_process_a_rest_request_when_the_global_wp_is_not_defined() { - define('REST_REQUEST', true); - rest_get_server()->dispatch(new WP_REST_Request()); + define( 'REST_REQUEST', true ); + rest_get_server()->dispatch( new WP_REST_Request() ); unset( $GLOBALS['wp'] ); $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); } /** - * should process a REST request when the rest route query variable is not set + * Process a REST request when the rest route query variable is not set * * @test */ - public function it_should_should_process_a_rest_request_when_the_rest_route_query_variable_is_not_set() { - define('REST_REQUEST', true); + public function it_should_process_a_rest_request_when_the_rest_route_query_variable_is_not_set() { + define( 'REST_REQUEST', true ); $GLOBALS['wp'] = new WP(); $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); } /** - * process a REST request when the query vars is set to a different route + * Process a REST request when the query vars is set to a different route * * @dataProvider provider_rest_route * * @test */ public function it_should_process_a_rest_request_when_the_query_vars_is_set_to_a_different_route( $route ) { - define('REST_REQUEST', true); - $GLOBALS['wp'] = new WP(); + define( 'REST_REQUEST', true ); + $GLOBALS['wp'] = new WP(); $GLOBALS['wp']->query_vars['rest_route'] = $route; $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); @@ -517,8 +517,8 @@ public function provider_rest_route() { * @test */ public function it_should_process_a_rest_request_when_dispatched_to_the_right_endpoint() { - define('REST_REQUEST', true); - $GLOBALS['wp'] = new WP(); + define( 'REST_REQUEST', true ); + $GLOBALS['wp'] = new WP(); $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); @@ -530,10 +530,10 @@ public function it_should_process_a_rest_request_when_dispatched_to_the_right_en * @test */ public function it_should_process_a_rest_request_when_an_action_is_provided() { - define('REST_REQUEST', true); - $GLOBALS['wp'] = new WP(); + define( 'REST_REQUEST', true ); + $GLOBALS['wp'] = new WP(); $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - $body = wp_json_encode( array( 'action' => 'subsizes' ) ); + $body = wp_json_encode( array( 'action' => 'subsizes' ) ); $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process( $body ) ); } @@ -544,10 +544,10 @@ public function it_should_process_a_rest_request_when_an_action_is_provided() { * @test */ public function it_should_process_a_rest_request_with_invalid_json_payload() { - define('REST_REQUEST', true); - $GLOBALS['wp'] = new WP(); + define( 'REST_REQUEST', true ); + $GLOBALS['wp'] = new WP(); $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - $body = ']]]]]][[][][]'; + $body = ']]]]]][[][][]'; $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process( $body ) ); } @@ -558,10 +558,10 @@ public function it_should_process_a_rest_request_with_invalid_json_payload() { * @test */ public function it_should_process_a_rest_request_when_the_right_action_is_provided() { - define('REST_REQUEST', true); - $GLOBALS['wp'] = new WP(); + define( 'REST_REQUEST', true ); + $GLOBALS['wp'] = new WP(); $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - $body = wp_json_encode( array( 'action' => 'create-image-subsizes' ) ); + $body = wp_json_encode( array( 'action' => 'create-image-subsizes' ) ); $this->assertTrue( _webp_uploads_is_valid_rest_for_post_process( $body ) ); } From b94ef68de65a65f2b095b12b975abb99d47bec49 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 13:58:26 -0600 Subject: [PATCH 05/16] Replace `array_key_exists` with `isset` In order to be consistent with the rest of the code and format to detect key presence. --- modules/images/webp-uploads/load.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 05f68afb08..bf6f68434d 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -73,7 +73,7 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) if ( empty( $metadata['sizes'][ $size_name ]['sources'][ $current_mime ] ) ) { $metadata['sizes'][ $size_name ]['sources'][ $current_mime ] = array( - 'file' => array_key_exists( 'file', $properties ) ? $properties['file'] : '', + 'file' => isset( $properties['file'] ) ? $properties['file'] : '', 'filesize' => 0, ); // Set the filesize from the current mime image. From f292fda478340d47643a2e63356dee6f52fbe8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crisoforo=20Gaspar=20Hern=C3=A1ndez?= Date: Thu, 24 Feb 2022 18:05:18 -0600 Subject: [PATCH 06/16] Replace keys access to `properties` instead. Co-authored-by: Felix Arntz --- modules/images/webp-uploads/load.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index bf6f68434d..d4cd8eed68 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -49,7 +49,7 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) $dirname = pathinfo( $file, PATHINFO_DIRNAME ); foreach ( $metadata['sizes'] as $size_name => $properties ) { // This image size is not defined or not an array. - if ( ! isset( $metadata['sizes'][ $size_name ] ) || ! is_array( $metadata['sizes'][ $size_name ] ) ) { + if ( ! is_array( $properties ) ) { continue; } From f9cdbd8a9fe6eb473e4a98be594e95482b6ea5e0 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 18:15:58 -0600 Subject: [PATCH 07/16] Prevent to run the logic when sizes are available --- modules/images/webp-uploads/load.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index d4cd8eed68..0ebe76c3cc 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -300,6 +300,10 @@ function webp_uploads_remove_sources_files( $attachment_id ) { * @return array[] $missing_sizes Associative array of arrays of image sub-size. */ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta, $attachment_id ) { + if ( ! empty( $missing_sizes ) ) { + return $missing_sizes; + } + if ( _webp_uploads_is_valid_ajax_for_image_sizes() || _webp_uploads_is_valid_rest_for_post_process( file_get_contents( 'php://input' ) ) ) { webp_uploads_create_sources_property( $image_meta, $attachment_id ); } From f80c3f65e845b1d08e54f678eb6d83b0a3bc123c Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 18:26:15 -0600 Subject: [PATCH 08/16] Update references to read & write on the metadata. Make sure the same variable is used across when referencing the data from the sources. --- modules/images/webp-uploads/load.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 0ebe76c3cc..2bf9abe9d7 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -53,11 +53,6 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) continue; } - // Ensure a `sources` property exists on the existing size. - if ( empty( $metadata['sizes'][ $size_name ]['sources'] ) || ! is_array( $metadata['sizes'][ $size_name ]['sources'] ) ) { - $metadata['sizes'][ $size_name ]['sources'] = array(); - } - // Try to find the mime type of the image size. $current_mime = ''; if ( isset( $properties['mime-type'] ) ) { @@ -71,30 +66,39 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) continue; } - if ( empty( $metadata['sizes'][ $size_name ]['sources'][ $current_mime ] ) ) { - $metadata['sizes'][ $size_name ]['sources'][ $current_mime ] = array( + // Ensure a `sources` property exists on the existing size. + if ( empty( $properties['sources'] ) || ! is_array( $properties['sources'] ) ) { + $properties['sources'] = array(); + } + + if ( empty( $properties['sources'][ $current_mime ] ) ) { + $properties['sources'][ $current_mime ] = array( 'file' => isset( $properties['file'] ) ? $properties['file'] : '', 'filesize' => 0, ); // Set the filesize from the current mime image. $file_location = path_join( $dirname, $properties['file'] ); if ( file_exists( $file_location ) ) { - $metadata['sizes'][ $size_name ]['sources'][ $current_mime ]['filesize'] = filesize( $file_location ); + $properties['sources'][ $current_mime ]['filesize'] = filesize( $file_location ); } + $metadata['sizes'][ $size_name ] = $properties; wp_update_attachment_metadata( $attachment_id, $metadata ); } $formats = isset( $valid_mime_transforms[ $current_mime ] ) ? $valid_mime_transforms[ $current_mime ] : array(); foreach ( $formats as $mime ) { - if ( empty( $metadata['sizes'][ $size_name ]['sources'][ $mime ] ) ) { + if ( empty( $properties['sources'][ $mime ] ) ) { $source = webp_uploads_generate_image_size( $attachment_id, $size_name, $mime ); if ( is_array( $source ) ) { - $metadata['sizes'][ $size_name ]['sources'][ $mime ] = $source; + $properties['sources'][ $mime ] = $source; + $metadata['sizes'][ $size_name ] = $properties; wp_update_attachment_metadata( $attachment_id, $metadata ); } } } + + $metadata['sizes'][ $size_name ] = $properties; } return $metadata; From 8b7611e9bb0dcca70e2c75afcb0f519c1ff382c2 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 18:28:09 -0600 Subject: [PATCH 09/16] Fix PHP linting --- modules/images/webp-uploads/load.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 2bf9abe9d7..50747a44a4 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -91,7 +91,7 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) if ( empty( $properties['sources'][ $mime ] ) ) { $source = webp_uploads_generate_image_size( $attachment_id, $size_name, $mime ); if ( is_array( $source ) ) { - $properties['sources'][ $mime ] = $source; + $properties['sources'][ $mime ] = $source; $metadata['sizes'][ $size_name ] = $properties; wp_update_attachment_metadata( $attachment_id, $metadata ); } From a2405f8d1e6df137ad632f25fd5e4684ccecab97 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 18:32:03 -0600 Subject: [PATCH 10/16] Update location for hooks and callbacks Make sure the hook is placed closer to the function definition. --- modules/images/webp-uploads/load.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 50747a44a4..23ecf33eb0 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -315,6 +315,8 @@ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta return $missing_sizes; } +add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 ); + /** * Determine if the current request is a valid request to process missing image sizes, executed * via ajax. @@ -340,5 +342,3 @@ function _webp_uploads_is_valid_rest_for_post_process( $body = '' ) { return $valid_route && ! empty( $matches ) && ! empty( $body['action'] ) && 'create-image-subsizes' === $body['action']; } - -add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 ); From 4c17a7c0d7759d9ed2ec158cfd6a0423b24f6c80 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Thu, 24 Feb 2022 19:46:18 -0600 Subject: [PATCH 11/16] Update logic for retry using `debug_backtrace`. Update logic to retry under constrained mechanism with the `debug_backtrace` approach instead. --- modules/images/webp-uploads/load.php | 39 +--- .../images/webp-uploads/webp-uploads-test.php | 180 ------------------ 2 files changed, 9 insertions(+), 210 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 23ecf33eb0..7afde63442 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -304,41 +304,20 @@ function webp_uploads_remove_sources_files( $attachment_id ) { * @return array[] $missing_sizes Associative array of arrays of image sub-size. */ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta, $attachment_id ) { - if ( ! empty( $missing_sizes ) ) { - return $missing_sizes; + $trace = array(); + // Only setup the trace if we no longer have more sizes. + if ( empty( $missing_sizes ) ) { + $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 10 ); } - if ( _webp_uploads_is_valid_ajax_for_image_sizes() || _webp_uploads_is_valid_rest_for_post_process( file_get_contents( 'php://input' ) ) ) { - webp_uploads_create_sources_property( $image_meta, $attachment_id ); + foreach ( $trace as $element ) { + if ( isset( $element['function'] ) && 'wp_update_image_subsizes' === $element['function'] ) { + webp_uploads_create_sources_property( $image_meta, $attachment_id ); + break; + } } return $missing_sizes; } add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 ); - -/** - * Determine if the current request is a valid request to process missing image sizes, executed - * via ajax. - * - * @return bool `true` if the current request is a valid ajax request to recreate missing image sizes. - */ -function _webp_uploads_is_valid_ajax_for_image_sizes() { - return wp_doing_ajax() && isset( $_REQUEST['action'], $_REQUEST['attachment_id'] ) && 'media-create-image-subsizes' === $_REQUEST['action'] && $_REQUEST['attachment_id'] > 0; -} - -/** - * Determine if the provided REST request goes to the appropriate endpoint with the right action. - * - * @param string $body The body from the request. - * - * @return bool `true` if the current request is a valid REST request to process - */ -function _webp_uploads_is_valid_rest_for_post_process( $body = '' ) { - $matches = array(); - $body = json_decode( $body, true ); - $valid_rest = defined( 'REST_REQUEST' ) && REST_REQUEST; - $valid_route = $valid_rest && isset( $GLOBALS['wp'], $GLOBALS['wp']->query_vars['rest_route'] ) && preg_match( '/media\/\d+\/post-process/', $GLOBALS['wp']->query_vars['rest_route'], $matches ); - - return $valid_route && ! empty( $matches ) && ! empty( $body['action'] ) && 'create-image-subsizes' === $body['action']; -} diff --git a/tests/modules/images/webp-uploads/webp-uploads-test.php b/tests/modules/images/webp-uploads/webp-uploads-test.php index dab8bd2c81..6f631e21dd 100644 --- a/tests/modules/images/webp-uploads/webp-uploads-test.php +++ b/tests/modules/images/webp-uploads/webp-uploads-test.php @@ -385,184 +385,4 @@ public function it_should_remove_the_webp_version_of_the_image_if_the_image_is_f path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) ); } - - /** - * Process a request where ajax is not defined - * - * @test - */ - public function it_should_process_a_request_where_ajax_is_not_defined() { - add_filter( 'wp_doing_ajax', '__return_false' ); - $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); - } - - /** - * Process an ajax request with no additional parameters - * - * @test - */ - public function it_should_process_an_ajax_request_with_no_additional_parameters() { - // Simulate ajax request. - add_filter( 'wp_doing_ajax', '__return_true' ); - $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); - } - - /** - * Process an ajax request with invalid action - * - * @test - */ - public function it_should_process_an_ajax_request_with_invalid_action() { - // Simulate ajax request. - add_filter( 'wp_doing_ajax', '__return_true' ); - $_REQUEST['action'] = 'invalid-action'; - $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); - } - - /** - * Process an ajax request with only the attachment id is included in the request - * - * @test - */ - public function it_should_process_an_ajax_request_with_only_the_attachment_id_is_included_in_the_request() { - // Simulate ajax request. - add_filter( 'wp_doing_ajax', '__return_true' ); - $_REQUEST['attachment_id'] = 1; - $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); - } - - /** - * Process an ajax request with invalid attachment id - * - * @test - */ - public function it_should_process_an_ajax_request_with_invalid_attachment_id() { - // Simulate ajax request. - add_filter( 'wp_doing_ajax', '__return_true' ); - $_REQUEST['action'] = 'media-create-image-subsizes'; - $_REQUEST['attachment_id'] = 0; - $this->assertFalse( _webp_uploads_is_valid_ajax_for_image_sizes() ); - } - - /** - * Process an ajax request with valid request parameters - * - * @test - */ - public function it_should_process_an_ajax_request_with_valid_request_parameters() { - // Simulate ajax request. - add_filter( 'wp_doing_ajax', '__return_true' ); - $_REQUEST['action'] = 'media-create-image-subsizes'; - $_REQUEST['attachment_id'] = 1; - $this->assertTrue( _webp_uploads_is_valid_ajax_for_image_sizes() ); - } - - /** - * Process a rest request when rest is not defined - * - * @test - */ - public function it_should_process_a_rest_request_when_rest_is_not_defined() { - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); - } - - /** - * Process a REST request when the global wp is not defined - * - * @test - */ - public function it_should_process_a_rest_request_when_the_global_wp_is_not_defined() { - define( 'REST_REQUEST', true ); - rest_get_server()->dispatch( new WP_REST_Request() ); - unset( $GLOBALS['wp'] ); - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); - } - - /** - * Process a REST request when the rest route query variable is not set - * - * @test - */ - public function it_should_process_a_rest_request_when_the_rest_route_query_variable_is_not_set() { - define( 'REST_REQUEST', true ); - $GLOBALS['wp'] = new WP(); - - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); - } - - /** - * Process a REST request when the query vars is set to a different route - * - * @dataProvider provider_rest_route - * - * @test - */ - public function it_should_process_a_rest_request_when_the_query_vars_is_set_to_a_different_route( $route ) { - define( 'REST_REQUEST', true ); - $GLOBALS['wp'] = new WP(); - $GLOBALS['wp']->query_vars['rest_route'] = $route; - - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); - } - - public function provider_rest_route() { - yield 'media route' => array( '/wp/v2/media' ); - yield 'single attachment route' => array( '/wp/v2/media/1' ); - yield 'edit attachment route' => array( '/wp/v2/media/1/edit' ); - } - - /** - * Process a REST request when dispatched to the right endpoint - * - * @test - */ - public function it_should_process_a_rest_request_when_dispatched_to_the_right_endpoint() { - define( 'REST_REQUEST', true ); - $GLOBALS['wp'] = new WP(); - $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process() ); - } - - /** - * Process a REST request when an action is provided - * - * @test - */ - public function it_should_process_a_rest_request_when_an_action_is_provided() { - define( 'REST_REQUEST', true ); - $GLOBALS['wp'] = new WP(); - $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - $body = wp_json_encode( array( 'action' => 'subsizes' ) ); - - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process( $body ) ); - } - - /** - * Process a REST request with invalid JSON payload - * - * @test - */ - public function it_should_process_a_rest_request_with_invalid_json_payload() { - define( 'REST_REQUEST', true ); - $GLOBALS['wp'] = new WP(); - $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - $body = ']]]]]][[][][]'; - - $this->assertFalse( _webp_uploads_is_valid_rest_for_post_process( $body ) ); - } - - /** - * Process a REST request when the right action is provided - * - * @test - */ - public function it_should_process_a_rest_request_when_the_right_action_is_provided() { - define( 'REST_REQUEST', true ); - $GLOBALS['wp'] = new WP(); - $GLOBALS['wp']->query_vars['rest_route'] = '/wp/v2/media/1/post-process'; - $body = wp_json_encode( array( 'action' => 'create-image-subsizes' ) ); - - $this->assertTrue( _webp_uploads_is_valid_rest_for_post_process( $body ) ); - } } From 5294f0177a922f1d6273538efa72f3ad380ab2ab Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Fri, 25 Feb 2022 10:42:35 -0600 Subject: [PATCH 12/16] Update docblock to explain the usage of `debug_backtrace` --- modules/images/webp-uploads/load.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 7afde63442..5ff380ef2e 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -305,8 +305,19 @@ function webp_uploads_remove_sources_files( $attachment_id ) { */ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta, $attachment_id ) { $trace = array(); - // Only setup the trace if we no longer have more sizes. + // Only setup the trace array if we no longer have more sizes. if ( empty( $missing_sizes ) ) { + /** + * The usage of `debug_backtrace` in this particular case is mainly to ensure the call to this + * filter was originated from `wp_update_image_subsizes()` due this function will call + * `wp_get_missing_image_subsizes` at some point but this function can be called from other places + * as well without having to pass from `wp_update_image_subsizes` in an ideal world an action would + * exist in `wp_update_image_subsizes`, in the meantime, this is a workaround for that scenario. The + * limit to 10 is to have a buffer as in an ideal scenario the function would be index 5 on the array. + * + * @see wp_update_image_subsizes() + * @see wp_get_missing_image_subsizes() + */ $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 10 ); } From 5a82230dc1258c5392c8839db117f03bc621737b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crisoforo=20Gaspar=20Hern=C3=A1ndez?= Date: Fri, 25 Feb 2022 12:52:08 -0600 Subject: [PATCH 13/16] Remove spacing. Co-authored-by: Felix Arntz --- modules/images/webp-uploads/load.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 5ff380ef2e..614841f6d8 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -295,7 +295,7 @@ function webp_uploads_remove_sources_files( $attachment_id ) { * * @since n.e.x.t * - * @see wp_get_missing_image_subsizes() + * @see wp_get_missing_image_subsizes() * * @param array[] $missing_sizes Associative array of arrays of image sub-size. * @param array $image_meta The metadata from the image. From d08474644ce8c0be64c708c8379269720e832350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crisoforo=20Gaspar=20Hern=C3=A1ndez?= Date: Fri, 25 Feb 2022 12:56:48 -0600 Subject: [PATCH 14/16] Update comment about `debug_backtrace` Co-authored-by: Felix Arntz --- modules/images/webp-uploads/load.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 614841f6d8..fd9d06e56d 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -308,12 +308,15 @@ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta // Only setup the trace array if we no longer have more sizes. if ( empty( $missing_sizes ) ) { /** - * The usage of `debug_backtrace` in this particular case is mainly to ensure the call to this - * filter was originated from `wp_update_image_subsizes()` due this function will call - * `wp_get_missing_image_subsizes` at some point but this function can be called from other places - * as well without having to pass from `wp_update_image_subsizes` in an ideal world an action would - * exist in `wp_update_image_subsizes`, in the meantime, this is a workaround for that scenario. The - * limit to 10 is to have a buffer as in an ideal scenario the function would be index 5 on the array. + * The usage of `debug_backtrace` in this particular case is mainly to ensure the call to + * `wp_get_missing_image_subsizes()` originated from `wp_update_image_subsizes()`, since only then the + * additional image sizes should be generated. `wp_get_missing_image_subsizes()` could also be called + * from other places in which case the custom logic should not trigger. In an ideal world an action + * would exist in `wp_update_image_subsizes` that runs any time, but the current + * `wp_generate_attachment_metadata` filter is skipped when all core sub-sizes have been generated. + * An eventual core implementation will not require this workaround. The limit of 10 is used to allow + * for some flexibility. While by default the function would be on index 5, other custom code may + * cause the index to be slightly higher. * * @see wp_update_image_subsizes() * @see wp_get_missing_image_subsizes() From 8bfc21ff3e023c6c02aba2dc004dac793b509101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crisoforo=20Gaspar=20Hern=C3=A1ndez?= Date: Fri, 25 Feb 2022 12:57:09 -0600 Subject: [PATCH 15/16] Code format on docblock Co-authored-by: Felix Arntz --- modules/images/webp-uploads/load.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index fd9d06e56d..5ea20b3cc5 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -297,11 +297,10 @@ function webp_uploads_remove_sources_files( $attachment_id ) { * * @see wp_get_missing_image_subsizes() * - * @param array[] $missing_sizes Associative array of arrays of image sub-size. + * @param array $missing_sizes Associative array of arrays of image sub-sizes. * @param array $image_meta The metadata from the image. * @param int $attachment_id The ID of the attachment. - * - * @return array[] $missing_sizes Associative array of arrays of image sub-size. + * @return array Associative array of arrays of image sub-sizes. */ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta, $attachment_id ) { $trace = array(); From f10c4232934193503578bb73109afeaa593c2df7 Mon Sep 17 00:00:00 2001 From: Crisoforo Gaspar Date: Fri, 25 Feb 2022 13:01:43 -0600 Subject: [PATCH 16/16] Update code based on code review Remove indentation in the code to remove the complexity when reading the code. For the most part early return. --- modules/images/webp-uploads/load.php | 62 +++++++++++++++------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 5ea20b3cc5..dc60380e98 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -88,14 +88,19 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id ) $formats = isset( $valid_mime_transforms[ $current_mime ] ) ? $valid_mime_transforms[ $current_mime ] : array(); foreach ( $formats as $mime ) { - if ( empty( $properties['sources'][ $mime ] ) ) { - $source = webp_uploads_generate_image_size( $attachment_id, $size_name, $mime ); - if ( is_array( $source ) ) { - $properties['sources'][ $mime ] = $source; - $metadata['sizes'][ $size_name ] = $properties; - wp_update_attachment_metadata( $attachment_id, $metadata ); - } + // If this property exists no need to create the image again. + if ( ! empty( $properties['sources'][ $mime ] ) ) { + continue; + } + + $source = webp_uploads_generate_image_size( $attachment_id, $size_name, $mime ); + if ( is_wp_error( $source ) ) { + continue; } + + $properties['sources'][ $mime ] = $source; + $metadata['sizes'][ $size_name ] = $properties; + wp_update_attachment_metadata( $attachment_id, $metadata ); } $metadata['sizes'][ $size_name ] = $properties; @@ -297,32 +302,33 @@ function webp_uploads_remove_sources_files( $attachment_id ) { * * @see wp_get_missing_image_subsizes() * - * @param array $missing_sizes Associative array of arrays of image sub-sizes. - * @param array $image_meta The metadata from the image. - * @param int $attachment_id The ID of the attachment. + * @param array $missing_sizes Associative array of arrays of image sub-sizes. + * @param array $image_meta The metadata from the image. + * @param int $attachment_id The ID of the attachment. * @return array Associative array of arrays of image sub-sizes. */ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta, $attachment_id ) { - $trace = array(); // Only setup the trace array if we no longer have more sizes. - if ( empty( $missing_sizes ) ) { - /** - * The usage of `debug_backtrace` in this particular case is mainly to ensure the call to - * `wp_get_missing_image_subsizes()` originated from `wp_update_image_subsizes()`, since only then the - * additional image sizes should be generated. `wp_get_missing_image_subsizes()` could also be called - * from other places in which case the custom logic should not trigger. In an ideal world an action - * would exist in `wp_update_image_subsizes` that runs any time, but the current - * `wp_generate_attachment_metadata` filter is skipped when all core sub-sizes have been generated. - * An eventual core implementation will not require this workaround. The limit of 10 is used to allow - * for some flexibility. While by default the function would be on index 5, other custom code may - * cause the index to be slightly higher. - * - * @see wp_update_image_subsizes() - * @see wp_get_missing_image_subsizes() - */ - $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 10 ); + if ( ! empty( $missing_sizes ) ) { + return $missing_sizes; } + /** + * The usage of `debug_backtrace` in this particular case is mainly to ensure the call to + * `wp_get_missing_image_subsizes()` originated from `wp_update_image_subsizes()`, since only then the + * additional image sizes should be generated. `wp_get_missing_image_subsizes()` could also be called + * from other places in which case the custom logic should not trigger. In an ideal world an action + * would exist in `wp_update_image_subsizes` that runs any time, but the current + * `wp_generate_attachment_metadata` filter is skipped when all core sub-sizes have been generated. + * An eventual core implementation will not require this workaround. The limit of 10 is used to allow + * for some flexibility. While by default the function would be on index 5, other custom code may + * cause the index to be slightly higher. + * + * @see wp_update_image_subsizes() + * @see wp_get_missing_image_subsizes() + */ + $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 10 ); + foreach ( $trace as $element ) { if ( isset( $element['function'] ) && 'wp_update_image_subsizes' === $element['function'] ) { webp_uploads_create_sources_property( $image_meta, $attachment_id ); @@ -330,7 +336,7 @@ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta } } - return $missing_sizes; + return array(); } add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 );