Repository navigation
fix(sync): auto-regenerate thumbnail sizes left stale after an image edit #1314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
d65f113
25bee78
41a3742
b1f6322
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -277,6 +277,65 @@ public function edit_upload( $attachment_id ) { | |
| return $this->upload_asset( $attachment_id, 'edit' ); | ||
| } | ||
|
|
||
| /** | ||
| * Regenerate an attachment's thumbnail sizes when they no longer match the current attached file. | ||
| * | ||
| * @param int $attachment_id The attachment ID. | ||
| * | ||
| * @return array|\WP_Error | ||
| */ | ||
| public function regenerate_sizes( $attachment_id ) { | ||
| if ( ! function_exists( '_wp_make_subsizes' ) ) { | ||
| require_once ABSPATH . 'wp-admin/includes/image.php'; | ||
| } | ||
|
|
||
| $metadata = wp_get_attachment_metadata( $attachment_id ); | ||
| $file = get_attached_file( $attachment_id ); | ||
|
|
||
| if ( empty( $metadata['sizes'] ) || empty( $file ) || ! file_exists( $file ) ) { | ||
| return new \WP_Error( 'cloudinary_regenerate_sizes_failed', __( 'Could not regenerate attachment sizes.', 'cloudinary' ) ); | ||
| } | ||
|
|
||
| // Only the sizes whose backing file is actually missing get regenerated -- every other size, | ||
| // including one a user deliberately kept (e.g. editing with "all sizes except thumbnail"), is | ||
| // left completely untouched. The missing entries are removed from $metadata first so | ||
| // _wp_make_subsizes() treats them as new sizes to create rather than skipping them as already | ||
| // present (it only checks whether the size *name* already has an entry, not whether the file | ||
| // behind it still exists). | ||
| $dir = dirname( $file ); | ||
| $missing = array(); | ||
| foreach ( $metadata['sizes'] as $size_name => $size_data ) { | ||
| if ( ! empty( $size_data['file'] ) && file_exists( path_join( $dir, $size_data['file'] ) ) ) { | ||
| continue; | ||
| } | ||
| unset( $metadata['sizes'][ $size_name ] ); | ||
| $missing[ $size_name ] = true; | ||
| } | ||
|
|
||
| if ( empty( $missing ) ) { | ||
| return $metadata; | ||
| } | ||
|
|
||
| $registered = wp_get_registered_image_subsizes(); | ||
| /** This filter is documented in wp-admin/includes/image.php */ | ||
| $registered = apply_filters( 'intermediate_image_sizes_advanced', $registered, $metadata, $attachment_id ); | ||
| $new_sizes = array_intersect_key( $registered, $missing ); | ||
|
|
||
| // _wp_make_subsizes() is WP core's own low-level size-creation step (used internally by | ||
| // wp_create_image_subsizes()). Unlike wp_generate_attachment_metadata(), it builds on the | ||
| // $metadata we pass in rather than a fresh array, so unrelated keys (original_image, | ||
| // third-party plugin data) are never at risk of being dropped. It also silently leaves a size | ||
| // out of the result if the image is too small for it, rather than erroring, so that case never | ||
| // reaches the sync-error path below. | ||
| $metadata = _wp_make_subsizes( $new_sizes, $file, $metadata, $attachment_id ); | ||
|
|
||
| wp_update_attachment_metadata( $attachment_id, $metadata ); | ||
| // Persist the new signature, otherwise this would re-trigger on every subsequent render. | ||
| $this->sync->set_signature_item( $attachment_id, 'sizes' ); | ||
|
Comment on lines
+330
to
+334
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: A regeneration failure is saved as a success here, and it cannot be retried.
The missing entries were already unset at L311, so in these cases:
The comment at L327-329 says that a size is left out only when the image is too small for it. That is one cause, but not the only one. Suggestion: after the call, check each requested size. Keep the entries that failed, and return an error if a size that the image could have had was not made: $original = $metadata; // before the unset loop
...
$metadata = _wp_make_subsizes( $new_sizes, $file, $metadata, $attachment_id );
$failed = array();
foreach ( $new_sizes as $size_name => $size_data ) {
if ( isset( $metadata['sizes'][ $size_name ] ) ) {
continue;
}
// Too small for this size: leaving it out is expected.
if ( ! image_resize_dimensions( $metadata['width'], $metadata['height'], $size_data['width'], $size_data['height'], $size_data['crop'] ) ) {
continue;
}
$failed[] = $size_name;
}
if ( $failed ) {
wp_update_attachment_metadata( $attachment_id, $original );
return new \WP_Error( 'cloudinary_regenerate_sizes_failed', ... );
}Note: |
||
|
|
||
| return $metadata; | ||
| } | ||
|
|
||
| /** | ||
| * Upload an asset to Cloudinary. | ||
| * | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.