Skip to content

Conversation

@aerni
Copy link
Contributor

@aerni aerni commented Aug 29, 2025

I'm doing some heavy blueprint manipulation on a site and ran into an issue with the blueprint blink cache that would cause EntryBlueprintFound events to not be dispatched after an entry has been saved for the first time.

EntryBlueprintFound events are only dispatched once per request. Once the blueprint is in the blink cache, it will be used on subsequent requests. See the blueprint method here.

This is a simple listener that I'm using in the videos below to showcase the issue:

<?php

namespace App\Listeners;

use Statamic\Events\EntryBlueprintFound;

class ModifyBlueprint
{
    public function handle(EntryBlueprintFound $event): void
    {
        $instructions = $event->entry ? 'Editing entry' : 'Creating entry';

        $event->blueprint->ensureFieldHasConfig('title', [
            'instructions' => $instructions,
        ]);
    }
}

The bug

When creating an entry, the instructions say, Creating entry. So far, so good. But once the entry is saved, the instructions fall back to the instructions saved in the blueprint yaml rather than using the instructions Editing entry as set in the listener.

CleanShot.2025-08-29.at.17.59.42.mp4

The fix

This issue can easily be resolved by clearing the blueprint blink cache when the edit route is loaded after the entry has been saved. Honestly, I'm not quite sure if this is a great solution. It feels more like a workaround.

CleanShot.2025-08-29.at.18.00.25.mp4

Other approach

Another approach is to also dispatch the EntryBlueprintFound event when the blink cache is loaded. But this kind of defeats the purpose of the blink cache.

if (Blink::has($key)) {
    $blueprint = Blink::get($key);
    EntryBlueprintFound::dispatch($blueprint, $this);
    return $blueprint;
}

How to reproduce

I was able to reproduce this bug on a fresh installation. See this repo here.

  1. Create a user
  2. Visit the theatres colleciton in the CP
  3. Create a new theatre -> notice the Entry creating instructions on the title field
  4. Save entry with cmd + s -> Notice the instructions disappear instead of reading Entry created
CleanShot.2025-09-01.at.09.42.44.mp4

What causes the bug

I tracked the issue down to a query in the AppServiceProvider of my site. If you remove the query, the blueprint fields are ensured as expected.

Entry::query()
    ->where('collection', 'theatres')
    ->get()
    ->each(function ($entry) {
        //
    });

A potential solution for this scenario

The bug can also be fixed by clearing the Blink cache directly in the service provider. But I'm not sure this is a good solution either.

Entry::query()
    ->where('collection', 'theatres')
    ->get()
    ->each(function ($entry) {
        Blink::forget("entry-{$entry->id()}-blueprint");
    });

A similar bug

I noticed a similar blueprint caching bug when a blueprint contains a parent field. This is the case with structured collections or if the blueprint contains a parent entries fieldtype.

Check out the Pages collection. The title instructions will always read Entry creating. Even when editing an existing entry. This is likely the underlying issue as in the theatres collection, as the pages collection is queried by the parent entries fieldtype.

However, the fix provided in this PR doesn't solve the issue in this scenario.

CleanShot.2025-09-01.at.09.42.04.mp4

@jasonvarga
Copy link
Member

I know that "don't do something" isn't a solution, but I'm curious why you're doing a query like that in boot anyway?

@aerni
Copy link
Contributor Author

aerni commented Sep 1, 2025

Fair question. For multiple reasons. Creating filesystems on the fly and manipulating the CP nav.

public function bootFilesystems(): self
{
    Entry::query()
        ->where('collection', 'theatres')
        ->whereNotNull('asset_container')
        ->pluck('id', 'asset_container')
        ->each(function ($id, $container) {
            /**
             * This is a hotfix for the issue described here: https://github.com/statamic/cms/pull/12232
             * It ensured that blueprin fields are ensured correctly after an entry has been created.
             */
            Blink::forget("entry-{$id}-blueprint");

            config()->set("filesystems.disks.{$container}", [
                'driver' => 'scoped',
                'disk' => 'assets',
                'prefix' => 'theatres/'.Str::slug($container),
            ]);
        });

    return $this;
}

protected function bootMembersAdminUserNavigation(): self
{
    Nav::extend(function ($nav) {
        if (! User::current()->hasRole('members_admin')) {
            return;
        }

        Entry::query()
            ->where('collection', 'theatres')
            ->whereNotNull('asset_container')
            ->pluck('asset_container')
            ->each(function ($container) use ($nav) {
                $title = AssetContainer::find($container)?->title();

                if (! $title) {
                    return; /* Ensure we don't remove the whole section if a container doesn't exist */
                }

                $nav->remove('Content', 'Assets', $title);
            });
    });

    return $this;
}

@jasonvarga
Copy link
Member

Alright, thanks. We can use this as a workaround for now.

@jasonvarga jasonvarga merged commit 0c6b9f6 into statamic:5.x Sep 1, 2025
24 checks passed
@aerni
Copy link
Contributor Author

aerni commented Sep 1, 2025

Thanks for taking care of this so quickly. Do you want me to open an issue regarding the related but with structured collections? Might make sense to revisit this solution at a later point as well and make it less of a "workaround".

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.

2 participants