Skip to content

Restore and backup image sizes alongside the sources properties #242

New issue

Have a question about this project? Sign up for a free account to open an issue and contact its maintainers and the community.

By clicking “Sign up for ”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on ? Sign in to your account

Merged
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.
mitoghMar 19, 2022
4820501
Restore and backup image sizes including `sources`.
mitoghMar 19, 2022
ab7bf05
Merge branch 'trunk' into feature/228-restore-and-backup-image-sources
mitoghMar 22, 2022
7e82041
Remove handling of edited images
mitoghMar 23, 2022
a2b82e3
Update the `success` logic to handle additional cases.
mitoghMar 23, 2022
ba0cbdf
Update logic to store and restore backup.
mitoghMar 23, 2022
2dd29d8
Remove empty space
mitoghMar 23, 2022
b16cee1
Update prefix on functions
mitoghMar 23, 2022
8a8e967
Update prefix on functions
mitoghMar 23, 2022
322dd3d
Update prefix on functions
mitoghMar 23, 2022
226a5aa
Update hooks reference
mitoghMar 23, 2022
8a809ed
Backup the data from previous metadata
mitoghMar 23, 2022
6d134e5
Merge branch 'trunk' into feature/228-restore-and-backup-image-sources
mitoghMar 24, 2022
76307e6
Merge branch 'trunk' into feature/228-restore-and-backup-image-sources
mitoghMar 24, 2022
951c4ca
Remove the need of auxilary variable to hold the sources
mitoghMar 26, 2022
61e25e8
Add `since` doc block
mitoghMar 28, 2022
4c26f4f
Align parameters on the doc block
mitoghMar 28, 2022
973a7b8
Removal of non required parameter
mitoghMar 28, 2022
cb35f42
Align parameters to follow WordPress guidelines
mitoghMar 28, 2022
7880f6b
Include the `@since` tags on missing functions
mitoghMar 28, 2022
ca8d28e
Move logic of the hook into a variable
mitoghMar 28, 2022
c381398
Add white spaces on tests
mitoghMar 30, 2022
93e0d01
Add white spaces on tests
mitoghMar 30, 2022
c165a11
Removal of `sanitize_text_field` due this value is not required.
mitoghMar 30, 2022
7d96583
Run logic only if was executed when doing ajax.
mitoghMar 30, 2022
7a113d3
Update code flow for more performant checks
mitoghMar 30, 2022
e202548
Split conditionals into separate statements
mitoghMar 30, 2022
188c7df
Removal of non requried conditional
mitoghMar 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
PrevPrevious commit
Next Next commit
Restore and backup image sizes including sources.
When an image is edited the `sources` properties is going to be backup with
the rest of the sizes properties, however that's not the case for the `full`
size which is a virtual type and the top level `sources` would be moved
into the backup metadata.

When the image is restored any edited image available in the sources array would
be removed before the restore takes place. The `sources` property for the `full-orig`
would be placed at the top level `sources` with the rest of the metadata.
  • Loading branch information
@mitogh
mitogh committedMar 19, 2022
commit 4820501b979d4e710baed19bd75d4597b628562b
187 changes: 187 additions & 0 deletions modules/images/webp-uploads/load.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -683,3 +683,190 @@ function webp_uploads_update_rest_attachment( WP_REST_Response $response, WP_Pos
return rest_ensure_response( $data );
}
add_filter( 'rest_prepare_attachment', 'webp_uploads_update_rest_attachment', 10, 3 );

/**
* Inspect if the current call to `wp_update_attachment_metadata()` was done from within the context
* of an edit to an attachment either restore or other type of edit, in that case we perform operations
* to save the sources properties, specifically for the `full` size image due this is a virtual image size.
*
* @since n.e.x.t
*
* @see wp_update_attachment_metadata()
*
* @param array $data The current metadata of the attachment.
* @param int $attachment_id The ID of the current attachment.
* @return array The updated metadata for the attachment to be stored in the meta table.
*/
function webp_wp_update_attachment_metadata( $data, $attachment_id ) {

$trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 10 );

foreach ( $trace as $element ) {
if ( ! isset( $element['function'] ) ) {
continue;
}

switch ( $element['function'] ) {
case 'wp_save_image':
// Right after an image has been edited.
return webp_uploads_backup_sources( $attachment_id, $data );
case 'wp_restore_image':
// When an image has been restored.
return webp_uploads_restore_image( $attachment_id, $data );
}
}

return $data;
}

add_filter( 'wp_update_attachment_metadata', 'webp_wp_update_attachment_metadata', 10, 2 );

/**
* Before saving the metadata of the image store a backup values for the sources and file property
* those files would be used and deleted by the backup mechanism, right after the metadata has
* been updated. It removes the current sources property due once this function is executed
* right after an edit has taken place and the current sources are no longer accurate.
*
* @since n.e.x.t
*
* @param int $attachment_id The ID representing the attachment.
* @param array $data The current metadata of the attachment.
* @return array The updated metadata for the attachment.
*/
function webp_uploads_backup_sources( $attachment_id, $data ) {
if ( ! isset( $data['sources'] ) ) {
return $data;
}

$data['_sources'] = $data['sources'];
// Remove the current sources as at this point the current values are no longer accurate.
unset( $data['sources'] );

return $data;
}

/**
* Restore an image from the backup sizes, the current hook moves the `sources` from the `full-orig` key into
* the top level `sources` into the metadata, in order to ensure the restore process has a reference to the right
* images. When `IMAGE_EDIT_OVERWRITE` is defined and is truthy the function would loop into the sources array
* and remove any sources that was created as an edited version, the filenames for those cases are constructed out
* of `e-{digits}` where `{digits}` is a number of length 13.
*
* @param int $attachment_id The ID of the attachment.
* @param array $data The current metadata to be stored in the attachment.
* @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 );

if ( ! is_array( $backup_sizes ) ) {
return $data;
}

// If `IMAGE_EDIT_OVERWRITE` is defined and is truthy remove any edited images if present before replacing the metadata.
if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE ) {
$file = get_attached_file( $attachment_id );
$dirname = pathinfo( $file, PATHINFO_DIRNAME );
$metadata = wp_get_attachment_metadata( $attachment_id );

$sources = isset( $metadata['sources'] ) && is_array( $metadata['sources'] ) ? $metadata['sources'] : array();

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

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

foreach ( $metadata['sizes'] as $size_name => $properties ) {
if ( ! isset( $properties['sources'] ) || ! is_array( $properties['sources'] ) ) {
continue;
}

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'];
}

return $data;
}

/**
* Hook fired right after a metadata has been created or updated, this function would look
* specifically only for the key: `_wp_attachment_backup_sizes` which is the one used to
* store all the backup sizes. This hook is in charge of cleaning up the additional meta
* keys stored in the metadata of the attachment and storing the `sources` property in the
* previous full size image due this is not a size we need to move the `sources` from the
* metadata back into the full size similar as how it's done on the rest of the sizes.
*
* @since n.e.x.t
*
* @param int $meta_id The ID of the meta value stored in the DB.
* @param int $attachment_id The ID of the post used for this meta, in our case the attachment ID.
* @param string $meta_name The name of the metadata to be updated.
* @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 ) {
if ( '_wp_attachment_backup_sizes' !== $meta_name ) {
return;
}

if ( ! is_array( $backup_sizes ) ) {
return;
}

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

$target = null;
foreach ( array_keys( $backup_sizes ) as $size_name ) {
// We are only interested in the `full-` sizes.
if ( strpos( $size_name, 'full-' ) === false ) {
continue;
}
// If the target already has the sources attributes find the next one.
if ( isset( $backup_sizes[ $size_name ]['sources'] ) ) {
continue;
}

$target = $size_name;
}

if ( null === $target || ! isset( $backup_sizes[ $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' );
// 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 );
}

add_action( 'added_post_meta', 'webp_updated_postmeta', 10, 4 );
add_action( 'updated_post_meta', 'webp_updated_postmeta', 10, 4 );
Loading