Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f9b1d51
Add tests
duncanmcclean Nov 11, 2025
43fe669
wip
duncanmcclean Nov 11, 2025
f25348a
Merge & extract
duncanmcclean Nov 11, 2025
f7381e0
Update property cache when saving and deleting fieldsets
duncanmcclean Nov 11, 2025
6bcada3
Add `Blueprint::all()`
duncanmcclean Nov 11, 2025
935923c
Don't need this.
duncanmcclean Nov 12, 2025
523db58
Merge branch 'master' into update-set-preview-images
duncanmcclean Nov 12, 2025
508d6c4
Write blueprints to disk and ensure global blueprints are included
duncanmcclean Nov 12, 2025
a05f422
Refactor `Blueprint::all()` to avoid calling all the facades...
duncanmcclean Nov 12, 2025
4195ff6
formatting
duncanmcclean Nov 12, 2025
5e03125
Avoid errors when array offsets don't exist
duncanmcclean Nov 12, 2025
499abb0
Add Blueprint::all() expectation where necessary
duncanmcclean Nov 12, 2025
568c0ca
Merge branch 'master' into update-set-preview-images
duncanmcclean Nov 18, 2025
664d053
Ensure parent is null when getting blueprints
duncanmcclean Nov 18, 2025
7da3fca
Preview images are saved sans folder
duncanmcclean Nov 18, 2025
d2c0eab
Add additional tests
duncanmcclean Nov 18, 2025
3aa802e
Handle assets being deleted & moved out of configured folder
duncanmcclean Nov 18, 2025
61f6339
Fix failing tests
duncanmcclean Nov 18, 2025
b0c39df
Fix more failing tests
duncanmcclean Nov 18, 2025
049e54f
Merge branch 'master' into update-set-preview-images
duncanmcclean Jan 5, 2026
d393254
add missing imports
duncanmcclean Jan 5, 2026
3d17d23
Merge branch '6.x' into update-set-preview-images
duncanmcclean Mar 11, 2026
9a49140
formatting
duncanmcclean Mar 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/Assets/AssetReferenceUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace Statamic\Assets;

use Statamic\Data\DataReferenceUpdater;
use Statamic\Fieldtypes\Sets;
use Statamic\Support\Arr;
use Statamic\Support\Str;

class AssetReferenceUpdater extends DataReferenceUpdater
{
Expand Down Expand Up @@ -65,4 +67,69 @@ protected function recursivelyUpdateFields($fields, $dottedPrefix = null)

$this->updateNestedFieldValues($fields, $dottedPrefix);
}

/**
* Update fields in blueprints and fieldsets.
*
* @return void
*/
protected function updateBlueprintFields()
{
if (
! Sets::previewImageConfig()
|| ! Str::startsWith($this->originalValue, Sets::previewImageConfig()['folder'].'/')
) {
return;
}

$contents = $this->item->contents();

$fieldPaths = $this->findFieldsInBlueprintContents($contents, fieldtypes: ['bard', 'replicator']);

foreach ($fieldPaths as $fieldPath) {
$fieldContents = Arr::get($contents, $fieldPath);

if (! isset($fieldContents['sets'])) {
continue;
}

$fieldContents['sets'] = collect($fieldContents['sets'])
->map(function ($setGroup) {
if (! isset($setGroup['sets'])) {
return $setGroup;
}

$setGroup['sets'] = collect($setGroup['sets'])
->map(function ($set) {
if (isset($set['image'])) {
$fullPath = Sets::previewImageConfig()['folder'].'/'.$set['image'];

if ($fullPath !== $this->originalValue) {
return $set;
}

if (Str::startsWith($this->newValue, Sets::previewImageConfig()['folder'].'/')) {
$set['image'] = Str::after($this->newValue, Sets::previewImageConfig()['folder'].'/');
} else {
unset($set['image']);
}

$this->updated = true;
}

return $set;
})
->all();

return $setGroup;
})
->all();

Arr::set($contents, $fieldPath, $fieldContents);
}

if ($this->updated) {
$this->item->setContents($contents);
}
}
}
42 changes: 41 additions & 1 deletion src/Data/DataReferenceUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
namespace Statamic\Data;

use Statamic\Facades\Blink;
use Statamic\Fields\Blueprint;
use Statamic\Fields\Fields;
use Statamic\Fields\Fieldset;
use Statamic\Fieldtypes\UpdatesReferences;
use Statamic\Git\Subscriber as GitSubscriber;
use Statamic\Support\Arr;
Expand Down Expand Up @@ -66,7 +69,11 @@ public function updateReferences($originalValue, $newValue)
$this->originalValue = $originalValue;
$this->newValue = $newValue;

$this->recursivelyUpdateFields($this->getTopLevelFields());
if ($this->item instanceof Blueprint || $this->item instanceof Fieldset) {
$this->updateBlueprintFields();
} else {
$this->recursivelyUpdateFields($this->getTopLevelFields());
}

if ($this->updated) {
$this->saveItem();
Expand All @@ -75,6 +82,39 @@ public function updateReferences($originalValue, $newValue)
return (bool) $this->updated;
}

/**
* Update fields in blueprints and fieldsets.
*
* @return void
*/
abstract protected function updateBlueprintFields();

/**
* Finds fields of a given type in the contents of a blueprint.
* Returns dot-notation paths to the fields.
*
* @param array $array
* @param array $fieldtypes
* @param string|null $dottedPrefix
* @param array $fieldPaths
* @return array
*/
protected function findFieldsInBlueprintContents($array, $fieldtypes, $dottedPrefix = '', &$fieldPaths = [])
{
foreach ($array as $key => $value) {
if (is_array($value)) {
$fieldPath = $dottedPrefix ? "$dottedPrefix.$key" : $key;
$this->findFieldsInBlueprintContents($value, $fieldtypes, $fieldPath, $fieldPaths);
}

if (is_string($value) && $key === 'type' && in_array($value, $fieldtypes)) {
$fieldPaths[] = $dottedPrefix;
}
}

return $fieldPaths;
}

/**
* Get top level fields off item blueprint.
*
Expand Down
15 changes: 14 additions & 1 deletion src/Fields/BlueprintRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Exception;
use Illuminate\Support\Collection;
use Statamic\Exceptions\BlueprintNotFoundException;
use Statamic\Facades;
use Statamic\Facades\Blink;
use Statamic\Facades\File;
use Statamic\Facades\Path;
Expand All @@ -23,6 +24,18 @@ class BlueprintRepository
protected $fallbacks = [];
protected $additionalNamespaces = [];

public function all()
{
$namespaces = [
...Facades\Collection::all()->map(fn ($collection) => "collections/{$collection->handle()}")->all(),
...Facades\Taxonomy::all()->map(fn ($taxonomy) => "taxonomies/{$taxonomy->handle()}")->all(),
'navigation', 'assets', 'globals', 'forms',
...$this->getAdditionalNamespaces()->keys()->all(),
];

return collect($namespaces)->flatMap(fn ($namespace) => $this->in($namespace)->values());
}

public function setDirectories(string|array $directories)
{
if (is_string($directories)) {
Expand Down Expand Up @@ -334,7 +347,7 @@ protected function makeBlueprintFromFile($path, $namespace = null)
->setInitialPath($path)
->setNamespace($namespace ?? null)
->setContents($contents);
});
})->setParent(null);
}

protected function getNamespaceAndHandle($blueprint)
Expand Down
4 changes: 4 additions & 0 deletions src/Fields/FieldsetRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ public function save(Fieldset $fieldset)
"{$directory}/{$handle}.yaml",
YAML::dump($fieldset->contents())
);

$this->fieldsets[$fieldset->handle()] = $fieldset;
}

public function delete(Fieldset $fieldset)
Expand All @@ -181,6 +183,8 @@ public function delete(Fieldset $fieldset)
}

File::delete($fieldset->path());

unset($this->fieldsets[$fieldset->handle()]);
}

public function reset(Fieldset $fieldset)
Expand Down
22 changes: 22 additions & 0 deletions src/Listeners/UpdateAssetReferences.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Statamic\Events\AssetReplaced;
use Statamic\Events\AssetSaved;
use Statamic\Events\Subscriber;
use Statamic\Facades\Blueprint;
use Statamic\Facades\Fieldset;

class UpdateAssetReferences extends Subscriber implements ShouldQueue
{
Expand Down Expand Up @@ -112,6 +114,26 @@ protected function replaceReferences($asset, $originalPath, $newPath)
}
});

Blueprint::all()
->each(function ($blueprint) use ($originalPath, $newPath, &$hasUpdatedItems) {
$updated = AssetReferenceUpdater::item($blueprint)
->updateReferences($originalPath, $newPath);

if ($updated) {
$hasUpdatedItems = true;
}
});

Fieldset::all()
->each(function ($fieldset) use ($originalPath, $newPath, &$hasUpdatedItems) {
$updated = AssetReferenceUpdater::item($fieldset)
->updateReferences($originalPath, $newPath);

if ($updated) {
$hasUpdatedItems = true;
}
});

if ($hasUpdatedItems) {
AssetReferencesUpdated::dispatch($asset);
}
Expand Down
10 changes: 10 additions & 0 deletions src/Taxonomies/TermReferenceUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,14 @@ protected function recursivelyUpdateFields($fields, $dottedPrefix = null)

$this->updateNestedFieldValues($fields, $dottedPrefix);
}

/**
* Update fields in blueprints and fieldsets.
*
* @return void
*/
protected function updateBlueprintFields()
{
//
}
}
1 change: 1 addition & 0 deletions tests/Assets/AssetFolderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,7 @@ private function containerWithDisk()
Storage::fake('local');

$container = Facades\AssetContainer::make('test')->disk('local');
Facades\AssetContainer::shouldReceive('find')->with('assets')->andReturn(null);
Facades\AssetContainer::shouldReceive('findByHandle')->with('test')->andReturn($container);
Facades\AssetContainer::shouldReceive('save')->with($container);

Expand Down
3 changes: 3 additions & 0 deletions tests/Assets/AssetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,7 @@ public function it_can_be_moved_to_another_folder_with_a_new_filename()
$disk->put('old/asset.txt', 'The asset contents');
$container = Facades\AssetContainer::make('test')->disk('local');
Facades\AssetContainer::shouldReceive('save')->with($container);
Facades\AssetContainer::shouldReceive('find')->with('assets')->andReturnNull();
Facades\AssetContainer::shouldReceive('findByHandle')->with('test')->andReturn($container);
$asset = $container->makeAsset('old/asset.txt')->data(['foo' => 'bar']);
$asset->save();
Expand Down Expand Up @@ -1224,6 +1225,7 @@ public function it_lowercases_when_moving_to_another_folder_with_a_new_filename(
$disk->put('old/asset.txt', 'The asset contents');
$container = Facades\AssetContainer::make('test')->disk('local');
Facades\AssetContainer::shouldReceive('save')->with($container);
Facades\AssetContainer::shouldReceive('find')->with('assets')->andReturnNull();
Facades\AssetContainer::shouldReceive('findByHandle')->with('test')->andReturn($container);
$asset = $container->makeAsset('old/asset.txt');
$asset->save();
Expand All @@ -1247,6 +1249,7 @@ public function it_doesnt_lowercase_moved_files_when_configured()
$disk->put('old/asset.txt', 'The asset contents');
$container = Facades\AssetContainer::make('test')->disk('local');
Facades\AssetContainer::shouldReceive('save')->with($container);
Facades\AssetContainer::shouldReceive('find')->with('assets')->andReturnNull();
Facades\AssetContainer::shouldReceive('findByHandle')->with('test')->andReturn($container);
$asset = $container->makeAsset('old/asset.txt');
$asset->save();
Expand Down
39 changes: 39 additions & 0 deletions tests/Fields/BlueprintRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
use Statamic\Fields\Blueprint;
use Statamic\Fields\BlueprintRepository;
use Statamic\Support\FileCollection;
use Tests\PreventSavingStacheItemsToDisk;
use Tests\TestCase;

class BlueprintRepositoryTest extends TestCase
{
use PreventSavingStacheItemsToDisk;

private $repo;

public function setUp(): void
Expand All @@ -26,6 +29,42 @@ public function setUp(): void
Facades\Blueprint::swap($this->repo);
}

#[Test]
public function it_gets_all_blueprints()
{
$this->repo->setDirectories($this->fakeStacheDirectory.'/dev-null/blueprints');

$collection = tap(Facades\Collection::make('test'))->save();
$collection->entryBlueprint()->save();

$taxonomy = tap(Facades\Taxonomy::make('test'))->save();
$taxonomy->termBlueprint()->save();

$nav = tap(Facades\Nav::make('test'))->save();
$nav->blueprint()->save();

$assetContainer = tap(Facades\AssetContainer::make('test'))->save();
$assetContainer->blueprint()->save();

Facades\GlobalSet::make('test')->save();
$this->repo->make('test')->setNamespace('globals')->save();

$form = tap(Facades\Form::make('test'))->save();
$form->blueprint()->save();

$all = $this->repo->all();

$this->assertEveryItemIsInstanceOf(Blueprint::class, $all);
$this->assertEquals([
'collections.test.test',
'taxonomies.test.test',
'navigation.test',
'assets.test',
'globals.test',
'forms.test',
], $all->map->fullyQualifiedHandle()->all());
}

#[Test]
public function it_gets_a_blueprint()
{
Expand Down
1 change: 1 addition & 0 deletions tests/Git/GitEventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ public function it_batches_asset_references_changes_into_one_commit()
],
]);

BlueprintRepository::shouldReceive('all')->andReturn(collect([$blueprint]));
BlueprintRepository::shouldReceive('in')->with('collections/pages')->andReturn(collect([$blueprint]));

foreach (range(1, 3) as $i) {
Expand Down
Loading
Loading