Skip to content

Commit ee5142e

Browse files
committed
Media: Accessibility: Copy attachment properties on site icon crop.
Add parity between site icon, custom header, and default image crop behaviors. [53027] fixed a bug where alt text and caption were not copied on custom headers, but did not apply that change in any other context. Deprecate the `create_attachment_object` method in the `Wp_Site_Icon` and `Custom_Image_Header` classes and replace that functionality with the new function `wp_copy_parent_attachment_properties()` to improve consistency. Props afercia, rcreators, jorbin, joedolson, huzaifaalmesbah, shailu25, swissspidy, mukesh27. Fixes #60524. git-svn-id: https://develop.svn.wordpress.org/trunk@57755 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 04afd90 commit ee5142e

7 files changed

Lines changed: 125 additions & 82 deletions

File tree

src/wp-admin/includes/ajax-actions.php

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4035,9 +4035,10 @@ function wp_ajax_crop_image() {
40354035
}
40364036

40374037
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
4038-
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
4039-
$attachment = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
4040-
unset( $attachment['ID'] );
4038+
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
4039+
4040+
// Copy attachment properties.
4041+
$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context );
40414042

40424043
// Update the attachment.
40434044
add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
@@ -4065,46 +4066,8 @@ function wp_ajax_crop_image() {
40654066
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
40664067
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
40674068

4068-
$parent_url = wp_get_attachment_url( $attachment_id );
4069-
$parent_basename = wp_basename( $parent_url );
4070-
$url = str_replace( $parent_basename, wp_basename( $cropped ), $parent_url );
4071-
4072-
$size = wp_getimagesize( $cropped );
4073-
$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
4074-
4075-
// Get the original image's post to pre-populate the cropped image.
4076-
$original_attachment = get_post( $attachment_id );
4077-
$sanitized_post_title = sanitize_file_name( $original_attachment->post_title );
4078-
$use_original_title = (
4079-
( '' !== trim( $original_attachment->post_title ) ) &&
4080-
/*
4081-
* Check if the original image has a title other than the "filename" default,
4082-
* meaning the image had a title when originally uploaded or its title was edited.
4083-
*/
4084-
( $parent_basename !== $sanitized_post_title ) &&
4085-
( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title )
4086-
);
4087-
$use_original_description = ( '' !== trim( $original_attachment->post_content ) );
4088-
4089-
$attachment = array(
4090-
'post_title' => $use_original_title ? $original_attachment->post_title : wp_basename( $cropped ),
4091-
'post_content' => $use_original_description ? $original_attachment->post_content : $url,
4092-
'post_mime_type' => $image_type,
4093-
'guid' => $url,
4094-
'context' => $context,
4095-
);
4096-
4097-
// Copy the image caption attribute (post_excerpt field) from the original image.
4098-
if ( '' !== trim( $original_attachment->post_excerpt ) ) {
4099-
$attachment['post_excerpt'] = $original_attachment->post_excerpt;
4100-
}
4101-
4102-
// Copy the image alt text attribute from the original image.
4103-
if ( '' !== trim( $original_attachment->_wp_attachment_image_alt ) ) {
4104-
$attachment['meta_input'] = array(
4105-
'_wp_attachment_image_alt' => wp_slash( $original_attachment->_wp_attachment_image_alt ),
4106-
);
4107-
}
4069+
// Copy attachment properties.
4070+
$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context );
41084071

41094072
$attachment_id = wp_insert_attachment( $attachment, $cropped );
41104073
$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );

src/wp-admin/includes/class-custom-image-header.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ public function step_3() {
10771077
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
10781078
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
10791079

1080-
$attachment = $this->create_attachment_object( $cropped, $attachment_id );
1080+
$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' );
10811081

10821082
if ( ! empty( $_POST['create-new-attachment'] ) ) {
10831083
unset( $attachment['ID'] );
@@ -1314,12 +1314,14 @@ final public function get_header_dimensions( $dimensions ) {
13141314
* Creates an attachment 'object'.
13151315
*
13161316
* @since 3.9.0
1317+
* @deprecated 6.5.0
13171318
*
13181319
* @param string $cropped Cropped image URL.
13191320
* @param int $parent_attachment_id Attachment ID of parent image.
13201321
* @return array An array with attachment object data.
13211322
*/
13221323
final public function create_attachment_object( $cropped, $parent_attachment_id ) {
1324+
_deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' );
13231325
$parent = get_post( $parent_attachment_id );
13241326
$parent_url = wp_get_attachment_url( $parent->ID );
13251327
$url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
@@ -1421,7 +1423,7 @@ public function ajax_header_crop() {
14211423
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
14221424
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
14231425

1424-
$attachment = $this->create_attachment_object( $cropped, $attachment_id );
1426+
$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' );
14251427

14261428
$previous = $this->get_previous_crop( $attachment );
14271429

src/wp-admin/includes/class-wp-site-icon.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,15 @@ public function __construct() {
7878
* Creates an attachment 'object'.
7979
*
8080
* @since 4.3.0
81+
* @deprecated 6.5.0
8182
*
8283
* @param string $cropped Cropped image URL.
8384
* @param int $parent_attachment_id Attachment ID of parent image.
8485
* @return array An array with attachment object data.
8586
*/
8687
public function create_attachment_object( $cropped, $parent_attachment_id ) {
88+
_deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' );
89+
8790
$parent = get_post( $parent_attachment_id );
8891
$parent_url = wp_get_attachment_url( $parent->ID );
8992
$url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );

src/wp-admin/includes/image.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,62 @@ function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) {
482482
return $image_meta;
483483
}
484484

485+
/**
486+
* Copy parent attachment properties to newly cropped image.
487+
*
488+
* @since 6.5.0
489+
*
490+
* @param string $cropped Path to the cropped image file.
491+
* @param int $parent_attachment_id Parent file Attachment ID.
492+
* @param string $context Control calling the function.
493+
* @return array Properties of attachment.
494+
*/
495+
function wp_copy_parent_attachment_properties( $cropped, $parent_attachment_id, $context = '' ) {
496+
$parent = get_post( $parent_attachment_id );
497+
$parent_url = wp_get_attachment_url( $parent->ID );
498+
$parent_basename = wp_basename( $parent_url );
499+
$url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
500+
501+
$size = wp_getimagesize( $cropped );
502+
$image_type = $size ? $size['mime'] : 'image/jpeg';
503+
504+
$sanitized_post_title = sanitize_file_name( $parent->post_title );
505+
$use_original_title = (
506+
( '' !== trim( $parent->post_title ) ) &&
507+
/*
508+
* Check if the original image has a title other than the "filename" default,
509+
* meaning the image had a title when originally uploaded or its title was edited.
510+
*/
511+
( $parent_basename !== $sanitized_post_title ) &&
512+
( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title )
513+
);
514+
$use_original_description = ( '' !== trim( $parent->post_content ) );
515+
516+
$attachment = array(
517+
'post_title' => $use_original_title ? $parent->post_title : wp_basename( $cropped ),
518+
'post_content' => $use_original_description ? $parent->post_content : $url,
519+
'post_mime_type' => $image_type,
520+
'guid' => $url,
521+
'context' => $context,
522+
);
523+
524+
// Copy the image caption attribute (post_excerpt field) from the original image.
525+
if ( '' !== trim( $parent->post_excerpt ) ) {
526+
$attachment['post_excerpt'] = $parent->post_excerpt;
527+
}
528+
529+
// Copy the image alt text attribute from the original image.
530+
if ( '' !== trim( $parent->_wp_attachment_image_alt ) ) {
531+
$attachment['meta_input'] = array(
532+
'_wp_attachment_image_alt' => wp_slash( $parent->_wp_attachment_image_alt ),
533+
);
534+
}
535+
536+
$attachment['post_parent'] = $parent_attachment_id;
537+
538+
return $attachment;
539+
}
540+
485541
/**
486542
* Generates attachment meta data and create image sub-sizes for images.
487543
*

tests/phpunit/tests/image/header.php

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -108,25 +108,6 @@ public function test_header_image_has_correct_dimensions_with_flex_width_and_hei
108108
$this->assertSame( 1200, $dimensions['dst_height'] );
109109
}
110110

111-
public function test_create_attachment_object() {
112-
$id = wp_insert_attachment(
113-
array(
114-
'post_status' => 'publish',
115-
'post_title' => 'foo.png',
116-
'post_type' => 'post',
117-
'guid' => 'http://localhost/foo.png',
118-
)
119-
);
120-
121-
$cropped = 'foo-cropped.png';
122-
123-
$object = $this->custom_image_header->create_attachment_object( $cropped, $id );
124-
$this->assertSame( 'foo-cropped.png', $object['post_title'] );
125-
$this->assertSame( 'http://localhost/' . $cropped, $object['guid'] );
126-
$this->assertSame( 'custom-header', $object['context'] );
127-
$this->assertSame( 'image/jpeg', $object['post_mime_type'] );
128-
}
129-
130111
public function test_insert_cropped_attachment() {
131112
$id = wp_insert_attachment(
132113
array(
@@ -138,7 +119,7 @@ public function test_insert_cropped_attachment() {
138119
);
139120

140121
$cropped = 'foo-cropped.png';
141-
$object = $this->custom_image_header->create_attachment_object( $cropped, $id );
122+
$object = wp_copy_parent_attachment_properties( $cropped, $id, 'custom-header' );
142123

143124
$cropped_id = $this->custom_image_header->insert_attachment( $object, $cropped );
144125

@@ -161,7 +142,7 @@ public function test_check_get_previous_crop() {
161142

162143
// Create inital crop object.
163144
$cropped_1 = 'foo-cropped-1.png';
164-
$object = $this->custom_image_header->create_attachment_object( $cropped_1, $id );
145+
$object = wp_copy_parent_attachment_properties( $cropped_1, $id, 'custom-header' );
165146

166147
// Ensure no previous crop exists.
167148
$previous = $this->custom_image_header->get_previous_crop( $object );
@@ -175,7 +156,7 @@ public function test_check_get_previous_crop() {
175156

176157
// Create second crop.
177158
$cropped_2 = 'foo-cropped-2.png';
178-
$object = $this->custom_image_header->create_attachment_object( $cropped_2, $id );
159+
$object = wp_copy_parent_attachment_properties( $cropped_2, $id );
179160

180161
// Test that a previous crop is found.
181162
$previous = $this->custom_image_header->get_previous_crop( $object );

tests/phpunit/tests/image/siteIcon.php

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,26 +98,12 @@ public function test_additional_sizes_with_filter() {
9898
unset( $this->wp_site_icon->site_icon_sizes[ array_search( 321, $this->wp_site_icon->site_icon_sizes, true ) ] );
9999
}
100100

101-
public function test_create_attachment_object() {
102-
$attachment_id = $this->insert_attachment();
103-
$parent_url = get_post( $attachment_id )->guid;
104-
$cropped = str_replace( wp_basename( $parent_url ), 'cropped-test-image.jpg', $parent_url );
105-
106-
$object = $this->wp_site_icon->create_attachment_object( $cropped, $attachment_id );
107-
108-
$this->assertSame( $object['post_title'], 'cropped-test-image.jpg' );
109-
$this->assertSame( $object['context'], 'site-icon' );
110-
$this->assertSame( $object['post_mime_type'], 'image/jpeg' );
111-
$this->assertSame( $object['post_content'], $cropped );
112-
$this->assertSame( $object['guid'], $cropped );
113-
}
114-
115101
public function test_insert_cropped_attachment() {
116102
$attachment_id = $this->insert_attachment();
117103
$parent_url = get_post( $attachment_id )->guid;
118104
$cropped = str_replace( wp_basename( $parent_url ), 'cropped-test-image.jpg', $parent_url );
119105

120-
$object = $this->wp_site_icon->create_attachment_object( $cropped, $attachment_id );
106+
$object = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'site-icon' );
121107
$cropped_id = $this->wp_site_icon->insert_attachment( $object, $cropped );
122108

123109
$this->assertIsInt( $cropped_id );
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/**
4+
* Tests for the `wp_copy_parent_attachment_properties()` function.
5+
*
6+
* @group media
7+
* @covers ::wp_copy_parent_attachment_properties
8+
*/
9+
class Tests_Media_wpCopyParentAttachmentProperties extends WP_UnitTestCase {
10+
11+
public function tear_down() {
12+
$this->remove_added_uploads();
13+
14+
parent::tear_down();
15+
}
16+
17+
public function test_wp_copy_parent_attachment_properties() {
18+
$attachment = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' );
19+
$parent_url = get_post( $attachment )->guid;
20+
// Add alternative text.
21+
update_post_meta( $attachment, '_wp_attachment_image_alt', 'Alt text' );
22+
// Add image description.
23+
wp_update_post(
24+
array(
25+
'ID' => $attachment,
26+
'post_excerpt' => 'Image description',
27+
)
28+
);
29+
$file = wp_crop_image(
30+
DIR_TESTDATA . '/images/canola.jpg',
31+
0,
32+
0,
33+
100,
34+
100,
35+
100,
36+
100
37+
);
38+
39+
$object = wp_copy_parent_attachment_properties( $file, $attachment );
40+
$cropped = str_replace( wp_basename( $parent_url ), 'cropped-canola.jpg', $parent_url );
41+
42+
$this->assertSame( $object['post_title'], 'cropped-canola.jpg', 'Attachment title is not identical' );
43+
$this->assertSame( $object['context'], '', 'Attachment context is not identical' );
44+
$this->assertSame( $object['post_mime_type'], 'image/jpeg', 'Attachment mime type is not identical' );
45+
$this->assertSame( $object['post_content'], $cropped, 'Attachment content is not identical' );
46+
$this->assertSame( $object['guid'], $cropped, 'Attachment GUID is not identical' );
47+
$this->assertSame( $object['meta_input']['_wp_attachment_image_alt'], 'Alt text', 'Attachment alt text is not identical' );
48+
$this->assertSame( $object['post_excerpt'], 'Image description', 'Attachment description is not identical' );
49+
50+
unlink( $file );
51+
}
52+
}

0 commit comments

Comments
 (0)