Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a6f5e07
Add class to mimic image operations on the editor.
mitogh Mar 19, 2022
4820501
Restore and backup image sizes including `sources`.
mitogh Mar 19, 2022
ab7bf05
Merge branch 'trunk' into feature/228-restore-and-backup-image-sources
mitogh Mar 22, 2022
7e82041
Remove handling of edited images
mitogh Mar 23, 2022
a2b82e3
Update the `success` logic to handle additional cases.
mitogh Mar 23, 2022
ba0cbdf
Update logic to store and restore backup.
mitogh Mar 23, 2022
2dd29d8
Remove empty space
mitogh Mar 23, 2022
b16cee1
Update prefix on functions
mitogh Mar 23, 2022
8a8e967
Update prefix on functions
mitogh Mar 23, 2022
322dd3d
Update prefix on functions
mitogh Mar 23, 2022
226a5aa
Update hooks reference
mitogh Mar 23, 2022
8a809ed
Backup the data from previous metadata
mitogh Mar 23, 2022
6d134e5
Merge branch 'trunk' into feature/228-restore-and-backup-image-sources
mitogh Mar 24, 2022
76307e6
Merge branch 'trunk' into feature/228-restore-and-backup-image-sources
mitogh Mar 24, 2022
951c4ca
Remove the need of auxilary variable to hold the sources
mitogh Mar 26, 2022
61e25e8
Add `since` doc block
mitogh Mar 28, 2022
4c26f4f
Align parameters on the doc block
mitogh Mar 28, 2022
973a7b8
Removal of non required parameter
mitogh Mar 28, 2022
cb35f42
Align parameters to follow WordPress guidelines
mitogh Mar 28, 2022
7880f6b
Include the `@since` tags on missing functions
mitogh Mar 28, 2022
ca8d28e
Move logic of the hook into a variable
mitogh Mar 28, 2022
c381398
Add white spaces on tests
mitogh Mar 30, 2022
93e0d01
Add white spaces on tests
mitogh Mar 30, 2022
c165a11
Removal of `sanitize_text_field` due this value is not required.
mitogh Mar 30, 2022
7d96583
Run logic only if was executed when doing ajax.
mitogh Mar 30, 2022
7a113d3
Update code flow for more performant checks
mitogh Mar 30, 2022
e202548
Split conditionals into separate statements
mitogh Mar 30, 2022
188c7df
Removal of non requried conditional
mitogh Mar 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update logic to store and restore backup.
Due to the only value that is not correctly stored is
the top level sources attributes this now is stored
in a separate meta value. Stored in `_wp_attachment_backup_sources`

Logic was added to handle scenarios where only the thumbnail
or all images except the thumbnail are modified.
  • Loading branch information
mitogh committed Mar 23, 2022
commit ba0cbdf45808d8844fbd371da66e70b57ff5cdd3
63 changes: 27 additions & 36 deletions modules/images/webp-uploads/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -759,8 +759,20 @@ function webp_uploads_backup_sources( $attachment_id, $data ) {
return $data;
}

$data['_sources'] = $data['sources'];
$target = isset( $_REQUEST['target'] ) ? sanitize_text_field( $_REQUEST['target'] ) : 'all';

// When an edit to an image is only applied to a thumbnail there's nothing we need to backu up.
if ( 'thumbnail' === $target ) {
return $data;
}

// Store the current sources before the current metadata is overwritten.
$sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$sources = is_array( $sources ) ? $sources : array();
$sources['_sources'] = $data['sources'];
update_post_meta( $attachment_id, '_wp_attachment_backup_sources', $sources );
// Remove the current sources as at this point the current values are no longer accurate.
// TODO: Requires to be updated from https://github.com/WordPress/performance/issues/158.
unset( $data['sources'] );

return $data;
Expand All @@ -778,32 +790,16 @@ function webp_uploads_backup_sources( $attachment_id, $data ) {
* @return array The updated metadata of the attachment.
*/
function webp_uploads_restore_image( $attachment_id, $data ) {
$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );

if ( ! is_array( $backup_sizes ) ) {
if ( ! is_array( $backup_sources ) || ! isset( $backup_sources['full-orig'] ) || ! is_array( $backup_sources['full-orig'] ) ) {
return $data;
}

// TODO: Handle the case If `IMAGE_EDIT_OVERWRITE` is defined and is truthy remove any edited images if present before replacing the metadata.
// See: https://github.com/WordPress/performance/issues/158.

foreach ( $properties['sources'] as $mime => $source_properties ) {
if ( empty( $source_properties['file'] ) ) {
continue;
}

// Delete only if it's an edited image.
if ( preg_match( '/-e\d{13}/', $source_properties['file'] ) ) {
$delete_file = path_join( $dirname, $source_properties['file'] );
wp_delete_file( $delete_file );
}
}
}
}

if ( isset( $backup_sizes['full-orig']['sources'] ) ) {
$data['sources'] = $backup_sizes['full-orig']['sources'];
}
$data['sources'] = $backup_sources['full-orig'];

return $data;
}
Expand All @@ -824,17 +820,15 @@ function webp_uploads_restore_image( $attachment_id, $data ) {
* @param array $backup_sizes An array with the metadata value in this case the backup sizes.
*/
function webp_updated_postmeta( $meta_id, $attachment_id, $meta_name, $backup_sizes ) {
// The backup sources array.
if ( '_wp_attachment_backup_sizes' !== $meta_name ) {
return;
}

if ( ! is_array( $backup_sizes ) ) {
return;
}
$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$backup_sources = is_array( $backup_sources ) ? $backup_sources : array();

$metadata = wp_get_attachment_metadata( $attachment_id );
// No backup sources exists for the full size.
if ( ! isset( $metadata['_sources'] ) ) {
if ( ! isset( $backup_sources['_sources'] ) ) {
return;
}

Expand All @@ -845,26 +839,23 @@ function webp_updated_postmeta( $meta_id, $attachment_id, $meta_name, $backup_si
continue;
}
// If the target already has the sources attributes find the next one.
if ( isset( $backup_sizes[ $size_name ]['sources'] ) ) {
if ( isset( $backup_sources[ $size_name ] ) ) {
continue;
}

$target = $size_name;
break;
}

if ( null === $target || ! isset( $backup_sizes[ $target ] ) ) {
if ( null === $target ) {
return;
}

$updated_backup_sizes = $backup_sizes;
$updated_backup_sizes[ $target ]['sources'] = $metadata['_sources'];
// Prevent infinite loop.
remove_action( 'update_post_meta', 'webp_updated_postmeta' );
$backup_sources[ $target ] = $backup_sources['_sources'];
// Remove the temporary used space.
unset( $backup_sources['_sources'] );
// Store the `sources` property into the full size if present.
update_post_meta( $attachment_id, '_wp_attachment_backup_sizes', $updated_backup_sizes, $backup_sizes );
// Make sure the metadata no longer has a reference to the _sources property once has been stored.
unset( $metadata['_sources'] );
wp_update_attachment_metadata( $attachment_id, $metadata );
update_post_meta( $attachment_id, '_wp_attachment_backup_sources', $backup_sources );
}

add_action( 'added_post_meta', 'webp_updated_postmeta', 10, 4 );
Expand Down
146 changes: 96 additions & 50 deletions tests/modules/images/webp-uploads/webp-uploads-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ public function it_should_backup_the_sources_structure_alongside_the_full_size()

$metadata = wp_get_attachment_metadata( $attachment_id );
$this->assertEmpty( get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true ) );
$this->assertEmpty( get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true ) );

$editor = new WP_Image_Edit( $attachment_id );
$editor->rotate_right()->save();
Expand All @@ -833,15 +834,21 @@ public function it_should_backup_the_sources_structure_alongside_the_full_size()
$this->assertNotEmpty( $backup_sizes );
$this->assertIsArray( $backup_sizes );

$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$this->assertIsArray( $backup_sources );
$this->assertArrayHasKey( 'full-orig', $backup_sources );
$this->assertSame( $metadata['sources'], $backup_sources['full-orig'] );
$this->assertArrayNotHasKey( '_sources', $backup_sources );

foreach ( $backup_sizes as $size => $properties ) {
$size_name = str_replace( '-orig', '', $size );
$this->assertArrayHasKey( 'sources', $properties );

if ( 'full-orig' === $size ) {
$this->assertSame( $metadata['sources'], $properties['sources'] );
} else {
$this->assertSame( $metadata['sizes'][ $size_name ]['sources'], $properties['sources'] );
continue;
}

$this->assertArrayHasKey( 'sources', $properties );
$this->assertSame( $metadata['sizes'][ $size_name ]['sources'], $properties['sources'] );
}

$metadata = wp_get_attachment_metadata( $attachment_id );
Expand All @@ -851,83 +858,122 @@ public function it_should_backup_the_sources_structure_alongside_the_full_size()
}

/**
* Store all the information on the original backup key when image edit overwrite is defined
* Restore the sources array from the backup when an image is edited
*
* @test
*/
public function it_should_store_all_the_information_on_the_original_backup_key_when_image_edit_overwrite_is_defined() {
define( 'IMAGE_EDIT_OVERWRITE', true );

$attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/leafs.jpg' );
$original_metadata = wp_get_attachment_metadata( $attachment_id );

$editor = new WP_Image_Edit( $attachment_id );
public function it_should_restore_the_sources_array_from_the_backup_when_an_image_is_edited() {
$attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/leafs.jpg' );
$metadata = wp_get_attachment_metadata( $attachment_id );
$editor = new WP_Image_Edit( $attachment_id );
$editor->rotate_right()->save();
$this->assertTrue( $editor->success() );

$metadata = wp_get_attachment_metadata( $attachment_id );
$updated_metadata = $metadata;
$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$this->assertArrayHasKey( 'full-orig', $backup_sources );
$this->assertIsArray( $backup_sources['full-orig'] );
$this->assertSame( $metadata['sources'], $backup_sources['full-orig'] );
$this->assertArrayNotHasKey( '_sources', $backup_sources['full-orig'] );

// Fake the creation of sources array to the existing metadata.
$updated_metadata['sources'] = array(
get_post_mime_type( $attachment_id ) => pathinfo( $updated_metadata['file'], PATHINFO_FILENAME ),
);
wp_restore_image( $attachment_id );

foreach ( $updated_metadata['sizes'] as $size_name => $props ) {
$updated_metadata['sizes'][ $size_name ]['sources'] = array(
$props['mime-type'] => $props['file'],
);
$metadata = wp_get_attachment_metadata( $attachment_id );
$this->assertArrayHasKey( 'sources', $metadata );
$this->assertSame( $backup_sources['full-orig'], $metadata['sources'] );
$this->assertSame( $backup_sources, get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true ) );

$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
foreach ( $metadata['sizes'] as $size_name => $properties ) {
$this->assertArrayHasKey( 'sources', $backup_sizes[ $size_name . '-orig' ] );
$this->assertSame( $backup_sizes[ $size_name . '-orig' ]['sources'], $properties['sources'] );
}
}

wp_update_attachment_metadata( $attachment_id, $updated_metadata );
/**
* Prevent to back up the sources when the sources attributes does not exists
*
* @test
*/
public function it_should_prevent_to_back_up_the_sources_when_the_sources_attributes_does_not_exists() {
// Disable the generation of the sources attributes.
add_filter( 'webp_uploads_upload_image_mime_transforms', '__return_empty_array' );

$editor->rotate_left()->save();
$attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/leafs.jpg' );
$metadata = wp_get_attachment_metadata( $attachment_id );

$this->assertArrayNotHasKey( 'sources', $metadata );

$editor = new WP_Image_Edit( $attachment_id );
$editor->flip_vertical()->save();
$this->assertTrue( $editor->success() );

$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$this->assertEmpty( $backup_sources );

$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertIsArray( $backup_sizes );

// Make sure the original images were stored in the backup.
foreach ( $backup_sizes as $size_name => $properties ) {
$this->assertDoesNotMatchRegularExpression( '/-\d{13}/', $size_name );
$this->assertMatchesRegularExpression( '/-orig/', $size_name );
$this->assertArrayHasKey( 'sources', $properties, "Sources not present in '{$size_name}'" );

if ( 'full-orig' === $size_name ) {
$sources = $original_metadata['sources'];
} else {
$name = str_replace( '-orig', '', $size_name );
$sources = $original_metadata['sizes'][ $name ]['sources'];
}

$this->assertSame( $sources, $properties['sources'], "The '{$size_name} is not identical.'" );
$this->assertArrayNotHasKey( 'sources', $properties );
}
}

/**
* Restore the sources array from the backup when an image is edited
* Prevent to backup the full size image if only the thumbnail is edited
*
* @test
*/
public function it_should_restore_the_sources_array_from_the_backup_when_an_image_is_edited() {
public function it_should_prevent_to_backup_the_full_size_image_if_only_the_thumbnail_is_edited() {
$attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/leafs.jpg' );
$editor = new WP_Image_Edit( $attachment_id );
$editor->rotate_right()->save();
$metadata = wp_get_attachment_metadata( $attachment_id );
$this->assertArrayHasKey( 'sources', $metadata );

$editor = new WP_Image_Edit( $attachment_id );
$editor->flip_vertical()->only_thumbnail()->save();
$this->assertTrue( $editor->success() );

$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertArrayHasKey( 'full-orig', $backup_sizes );
$this->assertArrayHasKey( 'sources', $backup_sizes['full-orig'] );
$this->assertIsArray( $backup_sizes['full-orig']['sources'] );
$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$this->assertEmpty( $backup_sources );

wp_restore_image( $attachment_id );
$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertIsArray( $backup_sizes );
$this->assertCount( 1, $backup_sizes );
$this->assertArrayHasKey( 'thumbnail-orig', $backup_sizes );
$this->assertArrayHasKey( 'sources', $backup_sizes['thumbnail-orig'] );

$metadata = wp_get_attachment_metadata( $attachment_id );
$this->assertArrayHasKey( 'sources', $metadata );
$this->assertSame( $backup_sizes['full-orig']['sources'], $metadata['sources'] );
}

foreach ( $metadata['sizes'] as $size_name => $properties ) {
$this->assertArrayHasKey( 'sources', $backup_sizes[ $size_name . '-orig' ] );
$this->assertSame( $backup_sizes[ $size_name . '-orig' ]['sources'], $properties['sources'] );
/**
* Backup the image when all images except the thumbnail are updated
*
* @test
*/
public function it_should_backup_the_image_when_all_images_except_the_thumbnail_are_updated() {
$attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/leafs.jpg' );
$metadata = wp_get_attachment_metadata( $attachment_id );

$editor = new WP_Image_Edit( $attachment_id );
$editor->rotate_left()->all_except_thumbnail()->save();
$this->assertTrue( $editor->success() );

$backup_sources = get_post_meta( $attachment_id, '_wp_attachment_backup_sources', true );
$this->assertIsArray( $backup_sources );
$this->assertArrayHasKey( 'full-orig', $backup_sources );
$this->assertSame( $metadata['sources'], $backup_sources['full-orig'] );

$this->assertArrayNotHasKey( 'sources', wp_get_attachment_metadata( $attachment_id ), 'The sources attributes was not removed from the metadata.' );

$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertIsArray( $backup_sizes );
$this->assertArrayNotHasKey( 'thumbnail-orig', $backup_sizes, 'The thumbnail-orig was stored in the back up' );

foreach ( $backup_sizes as $size_name => $properties ) {
if ( 'full-orig' === $size_name ) {
continue;
}
$this->assertArrayHasKey( 'sources', $properties, "The '{$size_name}' does not have the sources." );
}
}
}