Customizer: Minimize duplicate header crops in the media library.

This adds `Custom_Image_Header::get_previous_crop()`, which finds any
previously cropped headers created from the same base image and replaces
that attachment rather than creating a new attachment.

After updating a crop, the replaced images is also removed from the list
of previous header images in the Customizer.

See #21819.


git-svn-id: https://develop.svn.wordpress.org/trunk@41732 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Joe McGill 2017-10-04 14:58:07 +00:00
parent d77da9cd2a
commit 59c0329461
4 changed files with 100 additions and 2 deletions

View File

@ -1164,7 +1164,8 @@ wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
'post_title' => basename($cropped),
'post_mime_type' => $image_type,
'guid' => $url,
'context' => 'custom-header'
'context' => 'custom-header',
'post_parent' => $parent_attachment_id,
);
return $object;
@ -1180,8 +1181,12 @@ wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
* @return int Attachment ID.
*/
final public function insert_attachment( $object, $cropped ) {
$parent_id = isset( $object['post_parent'] ) ? $object['post_parent'] : null;
unset( $object['post_parent'] );
$attachment_id = wp_insert_attachment( $object, $cropped );
$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
/**
* Filters the header image attachment metadata.
*
@ -1193,6 +1198,11 @@ wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
*/
$metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );
wp_update_attachment_metadata( $attachment_id, $metadata );
if ( $parent_id ) {
$meta = add_post_meta( $attachment_id, '_wp_attachment_parent', $parent_id, true );
}
return $attachment_id;
}
@ -1241,7 +1251,13 @@ wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
$object = $this->create_attachment_object( $cropped, $attachment_id );
unset( $object['ID'] );
$previous = $this->get_previous_crop( $object );
if ( $previous ) {
$object['ID'] = $previous;
} else {
unset( $object['ID'] );
}
$new_attachment_id = $this->insert_attachment( $object, $cropped );
@ -1396,4 +1412,32 @@ wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
return $header_images;
}
/**
* Get the ID of a previous crop from the same base image.
*
* @since 4.9.0
*
* @param array $object A crop attachment object.
* @return int|false An attachment ID if one exists. False if none.
*/
public function get_previous_crop( $object ) {
$header_images = $this->get_uploaded_header_images();
// Bail early if there are no header images.
if ( empty( $header_images ) ) {
return false;
}
$previous = false;
foreach ( $header_images as $image ) {
if ( $image['attachment_parent'] === $object['post_parent'] ) {
$previous = $image['attachment_id'];
break;
}
}
return $previous;
}
}

View File

@ -164,6 +164,7 @@
this.on('control:setImage', this.setImage, this);
this.on('control:removeImage', this.removeImage, this);
this.on('add', this.maybeRemoveOldCrop, this);
this.on('add', this.maybeAddRandomChoice, this);
_.each(this.data, function(elt, index) {
@ -187,6 +188,25 @@
}
},
maybeRemoveOldCrop: function( model ) {
var newID = model.get( 'header' ).attachment_id || false,
oldCrop;
// Bail early if we don't have a new attachment ID.
if ( ! newID ) {
return;
}
oldCrop = this.find( function( item ) {
return ( item.cid !== model.cid && item.get( 'header' ).attachment_id === newID );
} );
// If we found an old crop, remove it from the collection.
if ( oldCrop ) {
this.remove( oldCrop );
}
},
maybeAddRandomChoice: function() {
if (this.size() === 1) {
this.addRandomChoice();

View File

@ -1214,6 +1214,7 @@ function get_uploaded_header_images() {
$header_images[$header_index]['url'] = $url;
$header_images[$header_index]['thumbnail_url'] = $url;
$header_images[$header_index]['alt_text'] = get_post_meta( $header->ID, '_wp_attachment_image_alt', true );
$header_images[$header_index]['attachment_parent'] = (int) get_post_meta( $header->ID, '_wp_attachment_parent', true );
if ( isset( $header_data['width'] ) )
$header_images[$header_index]['width'] = $header_data['width'];

View File

@ -137,4 +137,37 @@ class Tests_Image_Header extends WP_UnitTestCase {
$this->assertGreaterThan( 0, $cropped_id );
}
/**
* @ticket 21819
*/
function test_check_get_previous_crop() {
$id = wp_insert_attachment( array(
'post_status' => 'publish',
'post_title' => 'foo.png',
'post_type' => 'post',
'guid' => 'http://localhost/foo.png'
) );
// Create inital crop object.
$cropped_1 = 'foo-cropped-1.png';
$object = $this->custom_image_header->create_attachment_object( $cropped_1, $id );
// Ensure no previous crop exists.
$previous = $this->custom_image_header->get_previous_crop( $object );
$this->assertFalse( $previous );
// Create the inital crop attachment and set it as the header.
$cropped_1_id = $this->custom_image_header->insert_attachment( $object, $cropped_1 );
$key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
update_post_meta( $cropped_1_id, $key, time() );
update_post_meta( $cropped_1_id, '_wp_attachment_is_custom_header', get_stylesheet() );
// Create second crop.
$cropped_2 = 'foo-cropped-2.png';
$object = $this->custom_image_header->create_attachment_object( $cropped_2, $id );
// Test that a previous crop is found.
$previous = $this->custom_image_header->get_previous_crop( $object );
$this->assertSame( $previous, $cropped_1_id );
}
}