Skip to content

Commit

Permalink
Media: Accessibility: Copy attachment properties on site icon crop.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
joedolson committed Mar 2, 2024
1 parent 04afd90 commit ee5142e
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 82 deletions.
49 changes: 6 additions & 43 deletions src/wp-admin/includes/ajax-actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -4035,9 +4035,10 @@ function wp_ajax_crop_image() {
}

/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
$attachment = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
unset( $attachment['ID'] );
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.

// Copy attachment properties.
$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context );

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

$parent_url = wp_get_attachment_url( $attachment_id );
$parent_basename = wp_basename( $parent_url );
$url = str_replace( $parent_basename, wp_basename( $cropped ), $parent_url );

$size = wp_getimagesize( $cropped );
$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';

// Get the original image's post to pre-populate the cropped image.
$original_attachment = get_post( $attachment_id );
$sanitized_post_title = sanitize_file_name( $original_attachment->post_title );
$use_original_title = (
( '' !== trim( $original_attachment->post_title ) ) &&
/*
* Check if the original image has a title other than the "filename" default,
* meaning the image had a title when originally uploaded or its title was edited.
*/
( $parent_basename !== $sanitized_post_title ) &&
( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title )
);
$use_original_description = ( '' !== trim( $original_attachment->post_content ) );

$attachment = array(
'post_title' => $use_original_title ? $original_attachment->post_title : wp_basename( $cropped ),
'post_content' => $use_original_description ? $original_attachment->post_content : $url,
'post_mime_type' => $image_type,
'guid' => $url,
'context' => $context,
);

// Copy the image caption attribute (post_excerpt field) from the original image.
if ( '' !== trim( $original_attachment->post_excerpt ) ) {
$attachment['post_excerpt'] = $original_attachment->post_excerpt;
}

// Copy the image alt text attribute from the original image.
if ( '' !== trim( $original_attachment->_wp_attachment_image_alt ) ) {
$attachment['meta_input'] = array(
'_wp_attachment_image_alt' => wp_slash( $original_attachment->_wp_attachment_image_alt ),
);
}
// Copy attachment properties.
$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context );

$attachment_id = wp_insert_attachment( $attachment, $cropped );
$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
Expand Down
6 changes: 4 additions & 2 deletions src/wp-admin/includes/class-custom-image-header.php
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ public function step_3() {
/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.

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

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

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

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

Expand Down
3 changes: 3 additions & 0 deletions src/wp-admin/includes/class-wp-site-icon.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,15 @@ public function __construct() {
* Creates an attachment 'object'.
*
* @since 4.3.0
* @deprecated 6.5.0
*
* @param string $cropped Cropped image URL.
* @param int $parent_attachment_id Attachment ID of parent image.
* @return array An array with attachment object data.
*/
public function create_attachment_object( $cropped, $parent_attachment_id ) {
_deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' );

$parent = get_post( $parent_attachment_id );
$parent_url = wp_get_attachment_url( $parent->ID );
$url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
Expand Down
56 changes: 56 additions & 0 deletions src/wp-admin/includes/image.php
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,62 @@ function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) {
return $image_meta;
}

/**
* Copy parent attachment properties to newly cropped image.
*
* @since 6.5.0
*
* @param string $cropped Path to the cropped image file.
* @param int $parent_attachment_id Parent file Attachment ID.
* @param string $context Control calling the function.
* @return array Properties of attachment.
*/
function wp_copy_parent_attachment_properties( $cropped, $parent_attachment_id, $context = '' ) {
$parent = get_post( $parent_attachment_id );
$parent_url = wp_get_attachment_url( $parent->ID );
$parent_basename = wp_basename( $parent_url );
$url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );

$size = wp_getimagesize( $cropped );
$image_type = $size ? $size['mime'] : 'image/jpeg';

$sanitized_post_title = sanitize_file_name( $parent->post_title );
$use_original_title = (
( '' !== trim( $parent->post_title ) ) &&
/*
* Check if the original image has a title other than the "filename" default,
* meaning the image had a title when originally uploaded or its title was edited.
*/
( $parent_basename !== $sanitized_post_title ) &&
( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title )
);
$use_original_description = ( '' !== trim( $parent->post_content ) );

$attachment = array(
'post_title' => $use_original_title ? $parent->post_title : wp_basename( $cropped ),
'post_content' => $use_original_description ? $parent->post_content : $url,
'post_mime_type' => $image_type,
'guid' => $url,
'context' => $context,
);

// Copy the image caption attribute (post_excerpt field) from the original image.
if ( '' !== trim( $parent->post_excerpt ) ) {
$attachment['post_excerpt'] = $parent->post_excerpt;
}

// Copy the image alt text attribute from the original image.
if ( '' !== trim( $parent->_wp_attachment_image_alt ) ) {
$attachment['meta_input'] = array(
'_wp_attachment_image_alt' => wp_slash( $parent->_wp_attachment_image_alt ),
);
}

$attachment['post_parent'] = $parent_attachment_id;

return $attachment;
}

/**
* Generates attachment meta data and create image sub-sizes for images.
*
Expand Down
25 changes: 3 additions & 22 deletions tests/phpunit/tests/image/header.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,6 @@ public function test_header_image_has_correct_dimensions_with_flex_width_and_hei
$this->assertSame( 1200, $dimensions['dst_height'] );
}

public function test_create_attachment_object() {
$id = wp_insert_attachment(
array(
'post_status' => 'publish',
'post_title' => 'foo.png',
'post_type' => 'post',
'guid' => 'http://localhost/foo.png',
)
);

$cropped = 'foo-cropped.png';

$object = $this->custom_image_header->create_attachment_object( $cropped, $id );
$this->assertSame( 'foo-cropped.png', $object['post_title'] );
$this->assertSame( 'http://localhost/' . $cropped, $object['guid'] );
$this->assertSame( 'custom-header', $object['context'] );
$this->assertSame( 'image/jpeg', $object['post_mime_type'] );
}

public function test_insert_cropped_attachment() {
$id = wp_insert_attachment(
array(
Expand All @@ -138,7 +119,7 @@ public function test_insert_cropped_attachment() {
);

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

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

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

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

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

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

// Test that a previous crop is found.
$previous = $this->custom_image_header->get_previous_crop( $object );
Expand Down
16 changes: 1 addition & 15 deletions tests/phpunit/tests/image/siteIcon.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,12 @@ public function test_additional_sizes_with_filter() {
unset( $this->wp_site_icon->site_icon_sizes[ array_search( 321, $this->wp_site_icon->site_icon_sizes, true ) ] );
}

public function test_create_attachment_object() {
$attachment_id = $this->insert_attachment();
$parent_url = get_post( $attachment_id )->guid;
$cropped = str_replace( wp_basename( $parent_url ), 'cropped-test-image.jpg', $parent_url );

$object = $this->wp_site_icon->create_attachment_object( $cropped, $attachment_id );

$this->assertSame( $object['post_title'], 'cropped-test-image.jpg' );
$this->assertSame( $object['context'], 'site-icon' );
$this->assertSame( $object['post_mime_type'], 'image/jpeg' );
$this->assertSame( $object['post_content'], $cropped );
$this->assertSame( $object['guid'], $cropped );
}

public function test_insert_cropped_attachment() {
$attachment_id = $this->insert_attachment();
$parent_url = get_post( $attachment_id )->guid;
$cropped = str_replace( wp_basename( $parent_url ), 'cropped-test-image.jpg', $parent_url );

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

$this->assertIsInt( $cropped_id );
Expand Down
52 changes: 52 additions & 0 deletions tests/phpunit/tests/media/wpCopyParentAttachmentProperties.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/**
* Tests for the `wp_copy_parent_attachment_properties()` function.
*
* @group media
* @covers ::wp_copy_parent_attachment_properties
*/
class Tests_Media_wpCopyParentAttachmentProperties extends WP_UnitTestCase {

public function tear_down() {
$this->remove_added_uploads();

parent::tear_down();
}

public function test_wp_copy_parent_attachment_properties() {
$attachment = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' );
$parent_url = get_post( $attachment )->guid;
// Add alternative text.
update_post_meta( $attachment, '_wp_attachment_image_alt', 'Alt text' );
// Add image description.
wp_update_post(
array(
'ID' => $attachment,
'post_excerpt' => 'Image description',
)
);
$file = wp_crop_image(
DIR_TESTDATA . '/images/canola.jpg',
0,
0,
100,
100,
100,
100
);

$object = wp_copy_parent_attachment_properties( $file, $attachment );
$cropped = str_replace( wp_basename( $parent_url ), 'cropped-canola.jpg', $parent_url );

$this->assertSame( $object['post_title'], 'cropped-canola.jpg', 'Attachment title is not identical' );
$this->assertSame( $object['context'], '', 'Attachment context is not identical' );
$this->assertSame( $object['post_mime_type'], 'image/jpeg', 'Attachment mime type is not identical' );
$this->assertSame( $object['post_content'], $cropped, 'Attachment content is not identical' );
$this->assertSame( $object['guid'], $cropped, 'Attachment GUID is not identical' );
$this->assertSame( $object['meta_input']['_wp_attachment_image_alt'], 'Alt text', 'Attachment alt text is not identical' );
$this->assertSame( $object['post_excerpt'], 'Image description', 'Attachment description is not identical' );

unlink( $file );
}
}

0 comments on commit ee5142e

Please sign in to comment.