Skip to content

Commit c803dfb

Browse files
committed
Rename original attachment lineage to edit root
Rename the lineage helpers, postmeta key, REST field and link relation so they no longer read like core's original_image / wp_get_original_image_* APIs, which describe the unscaled upload of the same attachment: - gutenberg_get_original_attachment_id() -> gutenberg_get_edit_root_attachment_id() - gutenberg_record_original_attachment_id() -> gutenberg_record_edit_root_attachment_id() - _wp_attachment_original_id -> _wp_attachment_edit_root_id - REST field original_attachment -> edit_root - Link relation wp:original-attachment -> wp:edit-root The remaining helpers, the meta key constant, the compat and test file names and the test class follow suit. No behaviour change.
1 parent 86e3f19 commit c803dfb

8 files changed

Lines changed: 308 additions & 309 deletions

File tree

Lines changed: 56 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<?php
22
/**
3-
* Records and exposes the lineage root for attachments edited via
3+
* Records and exposes the edit root for attachments edited via
44
* `/wp/v2/media/{id}/edit`.
55
*
66
* Each call to core's `edit_media_item` creates a new child attachment.
7-
* On that path, we record the id at the top of the lineage in a
8-
* dedicated postmeta key (`_wp_attachment_original_id`) so the Media
9-
* Editor modal can offer a "Restore original" action without walking
10-
* the chain on every read, and so cleanup on parent delete can use
11-
* an indexed query.
7+
* On that path, we record the id of the edit root (the attachment at
8+
* the top of the edit chain) in a dedicated postmeta key
9+
* (`_wp_attachment_edit_root_id`) so the Media Editor modal can offer
10+
* a "Restore original" action without walking the chain on every
11+
* read, and so cleanup on edit root delete can use an indexed query.
1212
*
1313
* This applies to every edit that goes through `/edit` — including
1414
* the image block's crop tools in the post editor — on any site
@@ -20,72 +20,71 @@
2020
*/
2121

2222
/**
23-
* Postmeta key for the lineage root id.
23+
* Postmeta key for the edit root id.
2424
*
2525
* Underscore-prefixed so it's treated as private/internal and not
2626
* exposed by the default postmeta REST surface.
2727
*/
28-
const GUTENBERG_ORIGINAL_ATTACHMENT_ID_META_KEY = '_wp_attachment_original_id';
28+
const GUTENBERG_EDIT_ROOT_ATTACHMENT_ID_META_KEY = '_wp_attachment_edit_root_id';
2929

3030
/**
31-
* Get the lineage root (original) attachment id for an attachment.
31+
* Get the edit root attachment id for an attachment.
3232
*
33-
* Returns the id recorded in `_wp_attachment_original_id` when the
33+
* Returns the id recorded in `_wp_attachment_edit_root_id` when the
3434
* attachment was created by editing another one, or the attachment's
3535
* own id when it has no edit lineage. Callers that want to tell
36-
* "has an original" apart from "is its own original" should compare
36+
* "has an edit root" apart from "is its own edit root" should compare
3737
* the result against the id they passed in.
3838
*
39-
* In core this would be `wp_get_original_attachment_id()`.
39+
* In core this would be `wp_get_edit_root_attachment_id()`.
4040
*
4141
* @param int $attachment_id Attachment id to resolve.
42-
* @return int The original attachment id, or `$attachment_id` when there is no lineage.
42+
* @return int The edit root attachment id, or `$attachment_id` when there is no lineage.
4343
*/
44-
function gutenberg_get_original_attachment_id( $attachment_id ) {
45-
$original_id = (int) get_post_meta(
44+
function gutenberg_get_edit_root_attachment_id( $attachment_id ) {
45+
$edit_root_id = (int) get_post_meta(
4646
$attachment_id,
47-
GUTENBERG_ORIGINAL_ATTACHMENT_ID_META_KEY,
47+
GUTENBERG_EDIT_ROOT_ATTACHMENT_ID_META_KEY,
4848
true
4949
);
5050

51-
return $original_id > 0 ? $original_id : (int) $attachment_id;
51+
return $edit_root_id > 0 ? $edit_root_id : (int) $attachment_id;
5252
}
5353

5454
/**
55-
* Persist the original attachment id when /edit creates a new edited
55+
* Persist the edit root attachment id when /edit creates a new edited
5656
* attachment.
5757
*
5858
* Hooks `wp_edited_image_metadata` (fired by core inside
5959
* `WP_REST_Attachments_Controller::edit_media_item`, after the new
6060
* attachment id has been inserted but before its image metadata is
61-
* stored). The new child's original is its parent's original if the
61+
* stored). The new child's edit root is its parent's edit root if the
6262
* parent has one, otherwise the parent itself.
6363
*
6464
* @param array $new_image_meta Metadata for the new edited attachment (unused).
6565
* @param int $new_attachment_id The new attachment id.
6666
* @param int $attachment_id The parent (source) attachment id.
6767
* @return array Filtered metadata (unchanged).
6868
*/
69-
function gutenberg_record_original_attachment_id( $new_image_meta, $new_attachment_id, $attachment_id ) {
70-
// The new child's original is its parent's original, or the parent
71-
// itself when the parent has no lineage of its own.
72-
$original_id = gutenberg_get_original_attachment_id( $attachment_id );
69+
function gutenberg_record_edit_root_attachment_id( $new_image_meta, $new_attachment_id, $attachment_id ) {
70+
// The new child's edit root is its parent's edit root, or the
71+
// parent itself when the parent has no lineage of its own.
72+
$edit_root_id = gutenberg_get_edit_root_attachment_id( $attachment_id );
7373

7474
update_post_meta(
7575
$new_attachment_id,
76-
GUTENBERG_ORIGINAL_ATTACHMENT_ID_META_KEY,
77-
$original_id
76+
GUTENBERG_EDIT_ROOT_ATTACHMENT_ID_META_KEY,
77+
$edit_root_id
7878
);
7979

8080
return $new_image_meta;
8181
}
82-
add_filter( 'wp_edited_image_metadata', 'gutenberg_record_original_attachment_id', 10, 3 );
82+
add_filter( 'wp_edited_image_metadata', 'gutenberg_record_edit_root_attachment_id', 10, 3 );
8383

8484
/**
85-
* Registers `original_attachment` as a REST field on the attachment
86-
* schema.
85+
* Registers `edit_root` as a REST field on the attachment schema.
8786
*
88-
* The value is the id of the lineage root the attachment was edited
87+
* The value is the id of the edit root the attachment was edited
8988
* from, or `0` when it has no edit lineage — mirroring
9089
* `featured_media`, where `0` means "none". Registering the field
9190
* (rather than injecting it in a response filter) exposes it in the
@@ -100,48 +99,48 @@ function gutenberg_record_original_attachment_id( $new_image_meta, $new_attachme
10099
* `view` context and never carries this field. Clients must refetch
101100
* the new attachment with `?context=edit`.
102101
*/
103-
function gutenberg_register_original_attachment_field() {
102+
function gutenberg_register_edit_root_field() {
104103
register_rest_field(
105104
'attachment',
106-
'original_attachment',
105+
'edit_root',
107106
array(
108-
'get_callback' => 'gutenberg_get_original_attachment_field',
107+
'get_callback' => 'gutenberg_get_edit_root_field',
109108
'schema' => array(
110-
'description' => __( 'The ID of the original attachment this attachment was edited from, or 0 when it was not created by editing another attachment.', 'gutenberg' ),
109+
'description' => __( 'The ID of the edit root attachment this attachment was edited from, or 0 when it was not created by editing another attachment.', 'gutenberg' ),
111110
'type' => 'integer',
112111
'context' => array( 'edit' ),
113112
'readonly' => true,
114113
),
115114
)
116115
);
117116
}
118-
add_action( 'rest_api_init', 'gutenberg_register_original_attachment_field' );
117+
add_action( 'rest_api_init', 'gutenberg_register_edit_root_field' );
119118

120119
/**
121-
* Resolves the `original_attachment` field value for a REST response.
120+
* Resolves the `edit_root` field value for a REST response.
122121
*
123-
* Trusts the stored meta rather than verifying the original still
122+
* Trusts the stored meta rather than verifying the edit root still
124123
* exists: the `delete_attachment` cleanup below keeps it accurate,
125-
* and a consumer fetching a dangling id (e.g. an original sitting in
124+
* and a consumer fetching a dangling id (e.g. an edit root sitting in
126125
* the trash) simply gets no record.
127126
*
128127
* @param array $attachment Prepared attachment response data.
129-
* @return int The lineage root id, or 0 when there is no lineage.
128+
* @return int The edit root id, or 0 when there is no lineage.
130129
*/
131-
function gutenberg_get_original_attachment_field( $attachment ) {
130+
function gutenberg_get_edit_root_field( $attachment ) {
132131
$attachment_id = isset( $attachment['id'] ) ? (int) $attachment['id'] : 0;
133132
if ( $attachment_id <= 0 ) {
134133
return 0;
135134
}
136135

137-
$original_id = gutenberg_get_original_attachment_id( $attachment_id );
136+
$edit_root_id = gutenberg_get_edit_root_attachment_id( $attachment_id );
138137

139-
return $original_id === $attachment_id ? 0 : $original_id;
138+
return $edit_root_id === $attachment_id ? 0 : $edit_root_id;
140139
}
141140

142141
/**
143-
* Filter `rest_prepare_attachment` to add the `wp:original-attachment`
144-
* link for attachments with an edit lineage.
142+
* Filter `rest_prepare_attachment` to add the `wp:edit-root` link for
143+
* attachments with an edit lineage.
145144
*
146145
* `register_rest_field` has no mechanism for links, so the link rides
147146
* a response filter while the field itself is registered above. Only
@@ -152,53 +151,53 @@ function gutenberg_get_original_attachment_field( $attachment ) {
152151
* @param WP_REST_Request $request REST request.
153152
* @return WP_REST_Response
154153
*/
155-
function gutenberg_add_original_attachment_link( $response, $post, $request ) {
154+
function gutenberg_add_edit_root_link( $response, $post, $request ) {
156155
if ( 'edit' !== $request['context'] ) {
157156
return $response;
158157
}
159158

160-
$original_id = gutenberg_get_original_attachment_id( $post->ID );
161-
if ( $original_id === (int) $post->ID ) {
159+
$edit_root_id = gutenberg_get_edit_root_attachment_id( $post->ID );
160+
if ( $edit_root_id === (int) $post->ID ) {
162161
return $response;
163162
}
164163

165164
// Mirror `featured_media`: an embeddable link so clients can
166-
// hydrate the original attachment with `?_embed`. Core fires
165+
// hydrate the edit root attachment with `?_embed`. Core fires
167166
// `rest_prepare_attachment` twice per attachment — once from the
168167
// posts controller's `prepare_item_for_response()` and again from
169168
// the attachments controller wrapping it — and `add_link()`
170169
// appends unconditionally, so guard against adding it twice.
171-
$rel = 'https://api.w.org/original-attachment';
170+
$rel = 'https://api.w.org/edit-root';
172171
$links = $response->get_links();
173172
if ( ! isset( $links[ $rel ] ) ) {
174173
$response->add_link(
175174
$rel,
176-
rest_url( 'wp/v2/media/' . $original_id ),
175+
rest_url( 'wp/v2/media/' . $edit_root_id ),
177176
array( 'embeddable' => true )
178177
);
179178
}
180179

181180
return $response;
182181
}
183-
add_filter( 'rest_prepare_attachment', 'gutenberg_add_original_attachment_link', 10, 3 );
182+
add_filter( 'rest_prepare_attachment', 'gutenberg_add_edit_root_link', 10, 3 );
184183

185184
/**
186-
* Clear `_wp_attachment_original_id` from descendants when their
187-
* original is deleted.
185+
* Clear `_wp_attachment_edit_root_id` from descendants when their
186+
* edit root is deleted.
188187
*
189188
* Without this, descendants would carry a dangling pointer at a
190189
* recycled attachment id. The REST filter trusts this meta without
191-
* verifying the original still exists, so this cleanup is what keeps
190+
* verifying the edit root still exists, so this cleanup is what keeps
192191
* the exposed field accurate and prevents it from pointing at an
193192
* unrelated attachment if the deleted id is later reused.
194193
*
195194
* Runs on hard delete only: with `MEDIA_TRASH`, trashing fires no
196195
* `delete_attachment`, so descendants keep pointing at a trashed
197-
* original (whose URL still resolves) until the trash is purged.
196+
* edit root (whose URL still resolves) until the trash is purged.
198197
*
199198
* @param int $attachment_id Attachment id being deleted.
200199
*/
201-
function gutenberg_clear_original_attachment_id_on_delete( $attachment_id ) {
200+
function gutenberg_clear_edit_root_attachment_id_on_delete( $attachment_id ) {
202201
$attachment_id = (int) $attachment_id;
203202
if ( $attachment_id <= 0 ) {
204203
return;
@@ -211,9 +210,9 @@ function gutenberg_clear_original_attachment_id_on_delete( $attachment_id ) {
211210
delete_metadata(
212211
'post',
213212
0,
214-
GUTENBERG_ORIGINAL_ATTACHMENT_ID_META_KEY,
213+
GUTENBERG_EDIT_ROOT_ATTACHMENT_ID_META_KEY,
215214
$attachment_id,
216215
true
217216
);
218217
}
219-
add_action( 'delete_attachment', 'gutenberg_clear_original_attachment_id_on_delete' );
218+
add_action( 'delete_attachment', 'gutenberg_clear_edit_root_attachment_id_on_delete' );

‎lib/load.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function gutenberg_is_experiment_enabled( $name ) {
6868
require __DIR__ . '/compat/wordpress-7.2/view-config-api.php';
6969
require __DIR__ . '/compat/wordpress-7.2/class-gutenberg-rest-view-config-controller-7-2.php';
7070
require __DIR__ . '/compat/wordpress-7.2/rest-api.php';
71-
require __DIR__ . '/compat/wordpress-7.2/original-attachment.php';
71+
require __DIR__ . '/compat/wordpress-7.2/edit-root-attachment.php';
7272

7373
// Real-time collaboration.
7474
require __DIR__ . '/experimental/collaboration/class-gutenberg-rest-autosaves-controller.php';

‎packages/core-data/CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### Enhancements
66

7-
- Add the root-level `original_attachment` field to the `Attachment` entity type — the original attachment's id, or `0` when the attachment was not created by editing another one; embeddable via the `wp:original-attachment` link, exposed in the `edit` context ([#81803](https://github.com/WordPress/gutenberg/pull/81803)).
7+
- Add the root-level `edit_root` field to the `Attachment` entity type — the edit root attachment's id, or `0` when the attachment was not created by editing another one; embeddable via the `wp:edit-root` link, exposed in the `edit` context ([#81803](https://github.com/WordPress/gutenberg/pull/81803)).
88
- `Icon`: add the `keywords` field exposed by the icons REST endpoint ([#82367](https://github.com/WordPress/gutenberg/pull/82367)).
99
- `__experimentalFetchLinkSuggestions`: add a `preferTypes` option to rank matches from one or more search types above the usual order ([#83408](https://github.com/WordPress/gutenberg/pull/83408)).
1010

‎packages/core-data/src/entity-types/attachment.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ declare module './base-entity-records' {
206206
*/
207207
post: ContextualField< number | null, 'view' | 'edit', C >;
208208
/**
209-
* The ID of the original attachment this attachment was edited
209+
* The ID of the edit root attachment this attachment was edited
210210
* from, or 0 when it has no edit lineage. Embeddable via the
211-
* `wp:original-attachment` link.
211+
* `wp:edit-root` link.
212212
*/
213-
original_attachment: ContextualField< number, 'edit', C >;
213+
edit_root: ContextualField< number, 'edit', C >;
214214
/**
215215
* URL to the original attachment file.
216216
*/

‎packages/media-fields/src/media_thumbnail/test/get-best-image-url.jsdom.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const baseMedia: Media = {
2020
title: { raw: 'Test Image', rendered: 'Test Image' },
2121
author: 1,
2222
featured_media: 0,
23-
original_attachment: 0,
23+
edit_root: 0,
2424
comment_status: 'open',
2525
ping_status: 'closed',
2626
template: '',

‎packages/media-fields/src/stories/index.story.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const sampleMediaItem: MediaItem = {
4444
},
4545
author: 1,
4646
featured_media: 0,
47-
original_attachment: 0,
47+
edit_root: 0,
4848
comment_status: 'open',
4949
ping_status: 'closed',
5050
template: '',
@@ -142,7 +142,7 @@ const sampleMediaItemZip: MediaItem = {
142142
},
143143
author: 1,
144144
featured_media: 0,
145-
original_attachment: 0,
145+
edit_root: 0,
146146
comment_status: 'open',
147147
ping_status: 'closed',
148148
template: '',
@@ -242,7 +242,7 @@ const sampleMediaItemBrokenImage: MediaItem = {
242242
},
243243
author: 1,
244244
featured_media: 0,
245-
original_attachment: 0,
245+
edit_root: 0,
246246
comment_status: 'open',
247247
ping_status: 'closed',
248248
template: '',

0 commit comments

Comments
 (0)