Skip to content

[6.x] Give reference updater fields the item being updated as their parent - #15443

Merged
jasonvarga merged 1 commit into
6.xfrom
fix/data-reference-updater-parent
Sep 10, 2026
Merged

[6.x] Give reference updater fields the item being updated as their parent#15443
jasonvarga merged 1 commit into
6.xfrom
fix/data-reference-updater-parent

Conversation

@jasonvarga

Copy link
Copy Markdown
Member

When a term is renamed or an asset is moved, DataReferenceUpdater loops over every entry, term, global and user, and hands each item's fields to the fieldtypes that participate in reference updating. Those fields were not reliably carrying the item as their parent, so any fieldtype reading $field->parent() during a reference update would read the wrong thing.

Two separate causes:

  • Top-level fields. getTopLevelFields() used $this->item->blueprint()->fields()->all(). Blueprint::fields() returns $this->fieldsCache before it re-applies the parent, and the Fields object underneath comes from Blink::once($this->fieldsBlinkKey(), ...) — cached globally by blueprint handle, not per Blueprint instance. In a loop over many items, the parent stuck on whichever item got there first.
  • Nested fields. processNestedFields() called $fields->all() with no parent at all. Replicator, Bard, Grid and Group each build a bare new Fields($fields) for the reference-update path, so there was nothing to inherit.

Both call sites now go through one helper. It clones each field rather than calling setParent() on the shared Fields, because Fields::setParent() mutates in place and propagates to every child Field — setting the parent there would fix the loop but leave the last-updated item pinned to the blueprint's cached fields for the rest of the request, where an unrelated reader would pick it up.

Scope

This is a latent bug on 6.x: nothing currently on the reference-update path reads $field->parent(). I checked every implementation — Assets, Link, Markdown, Bard, Replicator, Grid, Group and Terms — and none of them do. The one asset-side parent read, Assets::dynamicFolder(), is on the publish path, not this one.

So this is a contract fix rather than a user-visible bug fix: during a reference update, a field's parent is the item being updated, and now it says so. It's being fixed on its own because the hierarchical taxonomies work (#15192) adds the first fieldtype that would misread it, and the fix doesn't belong in a taxonomy PR.

Tests

tests/Data/DataReferenceUpdaterTest.php registers a fieldtype that records the parent it was handed, since no stock fieldtype exercises this yet. Each test was checked to fail for the right reason:

Test Before With setParent() on the shared fields This PR
top-level parent across two entries fails — both record the first entry passes passes
nested (grid) field parent fails — records null passes passes
parent doesn't leak onto the blueprint's shared fields passes — nothing was ever set fails passes

Blueprints hand back a Fields instance cached globally by handle, and nested
fields are constructed without a parent at all, so neither can be relied upon
to have the right one during a reference update. Clone the fields rather than
mutating them in place, so the item doesn't leak into every other consumer of
that blueprint for the rest of the request.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jasonvarga
jasonvarga merged commit ccac3c3 into 6.x Sep 10, 2026
65 checks passed
@jasonvarga
jasonvarga deleted the fix/data-reference-updater-parent branch September 10, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant