Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[6.x] Support reference updates for custom fieldtypes and working copies#13693

Open
morhi wants to merge 10 commits intostatamic:6.x from
morhi:feature/reference-update-custom-fieldtypes
Open

[6.x] Support reference updates for custom fieldtypes and working copies #13693
morhi wants to merge 10 commits intostatamic:6.x from
morhi:feature/reference-update-custom-fieldtypes

Conversation

@morhi
Copy link
Contributor

@morhi morhi commented Jan 27, 2026
edited
Loading

Problem

Statamic's DataReferenceUpdater delegates asset reference updates to AssetReferenceUpdater, which only supports Statamic's built-in fieldtypes. Custom fieldtypes referencing assets or containing nested fields (including nested Statamic Asset fields) don't receive reference updates when assets are renamed, moved, or deleted. This causes broken references.

Because of this, I had to disable renaming and moving files entirely in all of my projects.

Also, while working on this PR I noticed, that working copies don't receive any data updates, which makes assets and terms disappear if the entry has a working copy that you are working on. The PR also fixes that issue.

Solution

This PR moves reference update logic into the fieldtypes themselves via the UpdatesReferences trait. Since only the fieldtype knows its internal data structure, it's best positioned to locate and replace references.

All built-in fieldtypes (Assets, Link, Bard, Markdown, Grid, Group, Replicator, Terms) now use this trait, serving as reference implementations for addon developers. The updater classes (AssetReferenceUpdater, TermReferenceUpdater, DataReferenceUpdater) are simplified to generic loops that delegate to fieldtype methods, with a one-time cached Blink lookup to detect which fieldtypes participate.

The trait provides three no-op methods to override:

Method Purpose
replaceAssetReferences($data, $newValue, $oldValue, $container) Replace direct asset references
replaceTermReferences($data, $newValue, $oldValue, $taxonomy) Replace direct term references
iterateReferenceFields($data, NestedFieldUpdater $updater) Traverse nested sub-fields for recursion

Plus three helpers: replaceValue(), replaceValuesInArray(), replaceStatamicUrls().

Examples

Custom fieldtype with asset references

class MyLinkFieldtype extends Fieldtype
{
 use UpdatesReferences;
 public function replaceAssetReferences($data, ?string $newValue, string $oldValue, string $container)
 {
 if ($this->config('container') !== $container) {
 return $data;
 }
 return $this->replaceValue($data, $newValue, $oldValue);
 }
}

Custom fieldtype with term references

class MyTagsFieldtype extends Fieldtype
{
 use UpdatesReferences;
 public function replaceTermReferences($data, ?string $newValue, string $oldValue, string $taxonomy)
 {
 return $this->replaceValuesInArray($data, $newValue, $oldValue);
 }
}

Custom fieldtype with nested sub-fields

use Statamic\Data\NestedFieldUpdater;
use Statamic\Fields\Fields;
use Statamic\Fields\Fieldtype;
use Statamic\Fieldtypes\UpdatesReferences;
class ColumnsFieldtype extends Fieldtype
{
 use UpdatesReferences;
 public function iterateReferenceFields($data, NestedFieldUpdater $updater): void
 {
 if (! is_array($data)) {
 return;
 }
 $fields = new Fields($this->config('fields'));
 foreach (array_keys($data) as $idx) {
 $updater->update($fields, "{$idx}.");
 }
 }
}

Closes statamic/ideas#698

daun reacted with thumbs up emoji
@duncanmcclean duncanmcclean changed the title (削除) [5.x] Support reference updates for custom fieldtypes (削除ここまで) (追記) [6.x] Support reference updates for custom fieldtypes (追記ここまで) Jan 28, 2026
@duncanmcclean duncanmcclean changed the base branch from 5.x to 6.x January 28, 2026 17:25
Copy link
Contributor

daun commented Feb 10, 2026
edited
Loading

This would be amazing to have! We developed a custom asset fieldtype to better manage contextual metadata. While great for using custom fieldtype components, it also disables automatic reference updates for those fields. This PR would really help make this possible without re-implementing the logic of the reference updater classes in our addon.

morhi reacted with thumbs up emoji

Copy link
Contributor Author

morhi commented Feb 10, 2026

Thanks @daun Do you have any thoughts or concerns about the implementation I suggested?

morhi and others added 3 commits February 10, 2026 13:47
- Use strict null checks instead of falsy checks to avoid skipping valid data like empty arrays or 0
- Replace json_encode comparison with native PHP strict equality for change detection
- Add non-array guards in helper methods to prevent TypeError on unexpected data
- Standardize helper parameter ordering: callable always last
Copy link
Contributor

daun commented Feb 10, 2026

@morhi No concerns here, looks logical to me :) An approach we explored previously was to create a new AssetReferencesUpdating event that fires for every item/entry and field during the update, but that ended up firing an endless amount of events, even for no-ops. So your solution looks much more efficient.

Copy link
Contributor Author

morhi commented Feb 10, 2026
edited
Loading

@morhi No concerns here, looks logical to me :) An approach we explored previously was to create a new AssetReferencesUpdating event that fires for every item/entry and field during the update, but that ended up firing an endless amount of events, even for no-ops. So your solution looks much more efficient.

Yea, I developed something similar too. It works, but it requires going through all fields twice.

I was just thinking if there is a solution that would be easier to integrate in custom fieldtypes. Currently, you have to use the trait and implement the given methods.

morhi added 5 commits February 10, 2026 15:47
Instead of hardcoding type checks in the updater classes, each fieldtype
now owns its reference update logic. Built-in fieldtypes use the same
trait as addon developers, serving as examples. Updater classes are
simplified to generic loops with cached fieldtype detection via Blink.
...elds
Improves IDE discoverability for addon developers by replacing the opaque
callable parameter with a typed NestedFieldUpdater class.
The current data reference update system only replaced data in the
published entry. This commits also replaces the data of a working copy,
if it exists.
@morhi morhi changed the title (削除) [6.x] Support reference updates for custom fieldtypes (削除ここまで) (追記) [6.x] Support reference updates for custom fieldtypes and working copies (追記ここまで) Feb 10, 2026
@morhi morhi marked this pull request as ready for review February 10, 2026 17:34
Copy link
Contributor Author

morhi commented Feb 10, 2026
edited
Loading

Hey @ryanmitchell @jasonvarga @jacksleight @marcorieser ! Would love to hear your opinion on this PR. I am quite sure that all of us came across this issue at some point and it would be super cool to have this fixed :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Support custom callbacks in AssetReferenceUpdater for handling custom fieldtypes

2 participants

AltStyle によって変換されたページ (->オリジナル) /