diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 1e16b26bf0..8ffbcfad8c 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -486,16 +486,38 @@ function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id $basename = wp_basename( $metadata['file'] ); if ( $basename !== $replacement_source ) { - $image = str_replace( - $basename, - $replacement_source, - $image - ); + + /** + * Filter to replace additional image source file, by locating the original + * mime types of the file and return correct file path in the end. + * + * Altering the $image tag through this filter effectively short-circuits the default replacement logic using the preferred MIME type. + * + * @since n.e.x.t + * + * @param string $image An tag where the urls would be updated. + * @param int $attachment_id The ID of the attachment being modified. + * @param string $size The size name that would be used to create this image, out of the registered subsizes. + * @param string $target_mime The target mime in which the image should be created. + * @param string $context The context where this is function is being used. + */ + $filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, 'full', $target_mime, $context ); + + // If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image. + if ( $filtered_image === $image ) { + $image = str_replace( + $basename, + $metadata['sources'][ $target_mime ]['file'], + $image + ); + } else { + $image = $filtered_image; + } } } // Replace sub sizes for the image if present. - foreach ( $metadata['sizes'] as $name => $size_data ) { + foreach ( $metadata['sizes'] as $size => $size_data ) { if ( empty( $size_data['file'] ) ) { continue; } @@ -518,11 +540,19 @@ function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id continue; } - $image = str_replace( - $size_data['file'], - $size_data['sources'][ $target_mime ]['file'], - $image - ); + /** This filter is documented in modules/images/webp-uploads/load.php */ + $filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, $size, $target_mime, $context ); + + // If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image. + if ( $filtered_image === $image ) { + $image = str_replace( + $size_data['file'], + $size_data['sources'][ $target_mime ]['file'], + $image + ); + } else { + $image = $filtered_image; + } } return $image; diff --git a/tests/modules/images/webp-uploads/load-tests.php b/tests/modules/images/webp-uploads/load-tests.php index 2d384be08e..dfd41c658c 100644 --- a/tests/modules/images/webp-uploads/load-tests.php +++ b/tests/modules/images/webp-uploads/load-tests.php @@ -608,4 +608,27 @@ public function it_should_replace_the_featured_image_to_web_p_when_requesting_th $this->assertStringContainsString( '.webp', $featured_image ); $this->assertStringNotContainsString( '.jpeg', $featured_image ); } + + /** + * Prevent replacing an image if image was uploaded via external source or plugin. + * + * @group webp_uploads_update_image_references + * + * @test + */ + public function it_should_prevent_replacing_an_image_uploaded_via_external_source() { + remove_all_filters( 'webp_uploads_pre_replace_additional_image_source' ); + + add_filter( + 'webp_uploads_pre_replace_additional_image_source', + function() { + return ''; + } + ); + + $attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/car.jpeg' ); + + $tag = wp_get_attachment_image( $attachment_id, 'medium', false, array( 'class' => "wp-image-{$attachment_id}" ) ); + $this->assertNotSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); + } }