Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 15 additions & 16 deletions inc/dam.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ public function insert_attachments( $images ) {
$existing = $this->check_existing_attachments( $images );

foreach ( $images as $image ) {
if ( ! isset( $image['isEdit'] ) && array_key_exists( $image['meta']['resourceS3'], $existing ) ) {
$ids[] = $existing[ $image['meta']['resourceS3'] ];
if ( ! isset( $image['isEdit'] ) && array_key_exists( $image['resourceS3'], $existing ) ) {
$ids[] = $existing[ $image['resourceS3'] ];
Comment on lines +115 to +116
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$images objects are still sent through the media modal without any normalization (see assets/src/media/modal/messageHandler.js), and the existing unit tests build DAM images as { url, meta: { resourceS3, mimeType, ... } }. Switching to $image['resourceS3'] here will trigger undefined-index notices and prevent duplicate detection when the payload still contains meta.resourceS3. Consider normalizing once at the start of insert_attachments() (or in the REST handler) to support both shapes ($image['resourceS3'] ?? $image['meta']['resourceS3'] ?? null).

Copilot uses AI. Check for mistakes.

continue;
}
Expand Down Expand Up @@ -143,7 +143,7 @@ private function insert_attachment( $image ) {
$args = [
'post_title' => $name,
'post_type' => 'attachment',
'post_mime_type' => $image['meta']['mimeType'],
'post_mime_type' => $image['mimeType'],
'guid' => $image['url'],
];

Expand All @@ -153,24 +153,24 @@ private function insert_attachment( $image ) {
return $id;
}

update_post_meta( $id, self::OM_DAM_IMPORTED_FLAG, $image['meta']['resourceS3'] );
update_post_meta( $id, self::OM_DAM_IMPORTED_FLAG, $image['resourceS3'] );

if ( isset( $image['isEdit'] ) ) {
update_post_meta( $id, self::IS_EDIT_FLAG, true );
}

$metadata = [];

$metadata['file'] = '/id:' . $image['meta']['resourceS3'] . '/' . get_home_url() . '/' . $filename;
$metadata['mime-type'] = $image['meta']['mimeType'];
$metadata['file'] = '/id:' . $image['resourceS3'] . '/' . get_home_url() . '/' . $filename;
$metadata['mime-type'] = $image['mimeType'];

Comment on lines 146 to 166
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method now reads mimeType, resourceS3, originalWidth/Height, and fileSize from the top-level $image array. The rest of the plugin currently passes DAM data through unchanged (and the repo’s tests use $image['meta'][...]), so these indices may be missing at runtime and cause attachment inserts to fail. A safer approach is to normalize $image (flatten meta into the top-level) before using it, or read from both locations.

Copilot uses AI. Check for mistakes.
if ( isset( $image['meta']['filesize'] ) ) {
$metadata['filesize'] = $image['meta']['fileSize'];
if ( isset( $image['fileSize'] ) ) {
$metadata['fileSize'] = $image['fileSize'];
}

if ( isset( $image['meta']['originalWidth'] ) && isset( $image['meta']['originalHeight'] ) ) {
$metadata['width'] = $image['meta']['originalWidth'];
$metadata['height'] = $image['meta']['originalHeight'];
if ( isset( $image['originalWidth'] ) && isset( $image['originalHeight'] ) ) {
$metadata['width'] = $image['originalWidth'];
$metadata['height'] = $image['originalHeight'];
}

wp_update_attachment_metadata( $id, $metadata );
Expand All @@ -197,7 +197,6 @@ private function insert_attachment( $image ) {
* @return array $image.
*/
public function alter_attachment_image_src( $image, $attachment_id, $size, $icon ) {

// Skip if not DAM image.
if ( ! $this->is_dam_imported_image( $attachment_id ) ) {
return $image;
Expand Down Expand Up @@ -287,7 +286,7 @@ private function check_existing_attachments( $images ) {
$remaining = array_filter(
$images,
function ( $image ) use ( $already_imported ) {
return ! array_key_exists( $image['meta']['resourceS3'], $already_imported );
return ! array_key_exists( $image['resourceS3'], $already_imported );
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_existing_attachments() now assumes $image['resourceS3'] exists, but images coming from the DAM modal are forwarded as-is and are currently structured with meta.resourceS3. Without normalization this filter will emit notices and treat all images as “remaining”, which can lead to duplicate inserts.

Suggested change
return ! array_key_exists( $image['resourceS3'], $already_imported );
// Support both top-level `resourceS3` and nested `meta.resourceS3`.
$resource_key = null;
if ( isset( $image['resourceS3'] ) ) {
$resource_key = $image['resourceS3'];
} elseif ( isset( $image['meta'] ) && is_array( $image['meta'] ) && isset( $image['meta']['resourceS3'] ) ) {
$resource_key = $image['meta']['resourceS3'];
}
// If we cannot determine a resource key, treat the image as not yet imported.
if ( null === $resource_key ) {
return true;
}
return ! array_key_exists( $resource_key, $already_imported );

Copilot uses AI. Check for mistakes.
}
);

Expand All @@ -314,7 +313,7 @@ private function get_dam_imported_attachments( $images ) {
$s3_ids = [];

foreach ( $images as $image ) {
$s3_ids[] = esc_sql( strval( $image['meta']['resourceS3'] ) );
$s3_ids[] = esc_sql( strval( $image['resourceS3'] ) );
}
Comment on lines 315 to 317
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop now pulls S3 ids from $image['resourceS3'], but other parts of the codebase (and tests) provide meta.resourceS3. If the incoming images still contain the nested meta object, the query will be built with empty/undefined values and existing attachments won’t be detected. Consider normalizing $images before calling get_dam_imported_attachments() or reading from both keys here.

Copilot uses AI. Check for mistakes.

$meta_values_str = "'" . join( "', '", $s3_ids ) . "'";
Expand Down Expand Up @@ -364,7 +363,7 @@ private function get_offloaded_attachments( $images ) {
$map = [];

foreach ( $images as $image ) {
$like = '%id:' . $image['meta']['resourceS3'] . '%';
$like = '%id:' . $image['resourceS3'] . '%';

$found_attachments = $wpdb->get_results(
$wpdb->prepare(
Expand All @@ -378,7 +377,7 @@ private function get_offloaded_attachments( $images ) {
return [];
}

$map[ $image['meta']['resourceS3'] ] = (int) $found_attachments[0]->post_id;
$map[ $image['resourceS3'] ] = (int) $found_attachments[0]->post_id;
}
Comment on lines 365 to 381
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_offloaded_attachments() now uses $image['resourceS3'] when building the LIKE and map key. If the images payload is still { meta: { resourceS3: ... } }, this will break offloaded-attachment detection and can cause duplicate inserts. Normalize the image structure before this point or fall back to $image['meta']['resourceS3'].

Copilot uses AI. Check for mistakes.

return $map;
Expand Down
21 changes: 9 additions & 12 deletions tests/media_rename/test-attachment-model.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,15 @@ class Test_Attachment_Model extends WP_UnitTestCase {

const MOCK_REMOTE_ATTACHMENT = [
'url' => 'https://cloudUrlTest.test/w:auto/h:auto/q:auto/id:b1b12ee03bf3945d9d9bb963ce79cd4f/https://test-site.test/9.jpg',
'meta' =>
[
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage1',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/9.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage1',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/9.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
];

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
Expand Down
65 changes: 28 additions & 37 deletions tests/test-dam.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,27 @@ class Test_Dam extends WP_UnitTestCase {
const MOCK_ATTACHMENTS = [
[
'url' => 'https://cloudUrlTest.test/w:auto/h:auto/q:auto/id:b1b12ee03bf3945d9d9bb963ce79cd4f/https://test-site.test/9.jpg',
'meta' =>
[
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage1',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/9.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage1',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/9.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
[
'url' => 'https://cloudUrlTest.test/w:auto/h:auto/q:auto/id:b1b12ee03bf3945d9d9bb963ce79cd4f/https://test-site.test/10.jpg',
'meta' =>
[
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage2',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/10.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage2',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/10.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
];

Expand Down Expand Up @@ -144,7 +138,7 @@ public function test_insert_attachments() {
$attachment = get_post( $id );

$this->assertEquals( self::MOCK_ATTACHMENTS[ $index ]['url'], $attachment->guid );
$this->assertEquals( self::MOCK_ATTACHMENTS[ $index ]['meta']['mimeType'], $attachment->post_mime_type );
$this->assertEquals( self::MOCK_ATTACHMENTS[ $index ]['mimeType'], $attachment->post_mime_type );
}
}

Expand All @@ -165,18 +159,15 @@ public function test_insert_duplicates() {
[
[
'url' => 'https://cloudUrlTest.test/w:auto/h:auto/q:auto/id:b1b12ee03bf3945d9d9bb963ce79cd4f/https://test-site.test/11.jpg',
'meta' =>
[
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage3',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/11.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
'originalHeight' => 1800,
'originalWidth' => 1200,
'updateTime' => 1688553629048,
'resourceS3' => 'randomHashForImage3',
'mimeType' => 'image/jpeg',
'userKey' => 'mlckcuxuuuyb',
'fileSize' => 171114,
'originURL' => 'https://test-site.test/wp-content/uploads/2023/07/11.jpg',
'domain_hash' => 'dWwtcG9sZWNhdC15dWtpLmluc3Rhd3AueHl6',
],
],
);
Expand Down
Loading