cms icon indicating copy to clipboard operation
cms copied to clipboard

Replicator Field Blink Cache Issue in Event Listener

Open hamsterkacke opened this issue 3 months ago • 3 comments

Bug description

I have an Event Listener that is called on the EntrySaved $event. I grab the freshly saved entry, go over it and populate all the used fields in my custom array. I don't rely on $entry->get() because it did not work for my use case with localization.

I get the available fields from the blueprint of the entry:

$blueprint = $entry->blueprint();
$fields    = $blueprint->fields()->toPublishArray();

I then loop over the fields, check if data is set in the entry and add it to my data array. While doing this, i resolve association fields, grid fields, asset fields and replicator fields.

I started with grid fields and had no problems with association fields inside the grid field. But since we are talking like 20 Rows of grids i converted them to replicator because we need to be able to collapse.

After that change, the problem started

Workflow: I open my collection and save it -> my array is populated correctly I save again (Without leaving or reload) -> all the associations in my replicator fields are now suddenly completely ignored and return null if i get them via $entry->{$field_handle};

This led me to the believe, that this is a caching issue. I tried to find out where Blink is interefering etc. but since documentation is really rare for this, i just tested some things.

In the end the only solution that worked was calling Blink::flush(); before processing the entry. Then it populated them correctly again.

When i was debugging i also noticed, that this seems to be related to filling the Relation Entry with the wrong parent. (using multisite feature). And that is the reason that it then can't find the Relation in the entry itself, because this is the original one.

How to reproduce

Not sure if this is easily reproducable. I think the following criteria have to be met:

  1. Multisite
  2. Having a entry that is connected with another language
  3. Replicator field with relation field inside

Logs


Environment

Environment
Application Name: App Name
Laravel Version: 12.40.2
PHP Version: 8.2.29
Composer Version: 2.9.2
Environment: local
Debug Mode: ENABLED
URL: statamic.local
Maintenance Mode: OFF
Timezone: UTC
Locale: en

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Storage
public/storage: NOT LINKED

Statamic
Addons: 0
Sites: 2 (App Name, App Name Spanish)
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 5.69.0 PRO

Installation

Fresh statamic/statamic site via CLI

Additional details

No response

hamsterkacke avatar Dec 01 '25 14:12 hamsterkacke

Probably related: https://github.com/statamic/ssg/issues/171

I observed similar behavior in the static site generator since all the caching optimizations we’re introduced in Statamic V5, and it wasn’t consistently reproducible. The only workaround was the same one you suggested: flushing blink. It would probably be better to identify and fix the underlying root cause.

o1y avatar Dec 02 '25 08:12 o1y

For me it is reproducable in my setup and only happens with relations inside replicator fields. If someone can point me in the right direction where to check the Blink Cache generation for that, i maybe could dig deeper myself.

hamsterkacke avatar Dec 02 '25 09:12 hamsterkacke

I tried to pin down the problem for my usecase with the help of Claude.ai. We tested the fix, and it is working. I give you the summary:

Bug: In multisite, replicator relationship fields resolve to the wrong locale on subsequent saves in the CP (without a page reload). First save is correct; second save returns relationships from a different locale. Flushing Blink between saves avoids it.

Steps to Reproduce (generic):

  1. In a multisite site, edit a localized entry that has a replicator set containing a relationship/entries field.
  2. Save once → relationships resolve correctly in the current locale.
  3. Without reloading, save again (or switch locales in the same session and save). The relationship now resolves to another locale or comes back null.
  4. Blink::flush() before the second save prevents the wrong-locale resolution.

Observed Behavior:

  • On the second save, EntriesFieldtype::queryBuilder() resolves site_resolved to the previous locale because the parent locale is stale in the cached replicator Fields.
  • Root cause: Replicator::fields() caches Fields instances via Blink::once() using a key that omits locale/parent context, so the cache is reused across locales and carries the first locale’s parent. Relationship field augmentation then localizes to that stale locale.

Relevant Source:

  • vendor/statamic/cms/src/Fieldtypes/Replicator.php::fields() (Blink key missing locale/parent).
  • vendor/statamic/cms/src/Fieldtypes/Entries.php::queryBuilder() (uses parent locale to pick site).

Fix Applied Locally (verified): Include locale and parent id in the Blink key to prevent cross-locale reuse:

  $parent = $this->field()->parent();
  $locale = $parent && method_exists($parent, 'locale')
      ? $parent->locale()
      : Site::current()->handle();
  $parentId = $parent && method_exists($parent, 'id') ? $parent->id() : null;

  $hash = md5($this->field->fieldPathPrefix().$index.json_encode($config).$locale.$parentId);

After this change, saving twice keeps relationships in the correct locale without flushing Blink.

Suggested Upstream Fix: Adjust Replicator::fields() (and review other Blink caches like Fields::toPublishArray()) to include locale/parent context in cache keys so cached Fields instances aren’t reused across locales.


I am of course not sure, if this would break other things. But in my mind this is just something that was forgotten / overlooked when implementing cache. There are also places where site identifier is used in cache code and places, where it is not.

I hope this was helpful!

hamsterkacke avatar Dec 02 '25 12:12 hamsterkacke