From ec860d16583c308d928139b525eee13f8b1615c1 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 8 Sep 2026 13:04:06 +0100 Subject: [PATCH 1/6] show default values for fields saved empty the file writer drops empty values from root entries and default-locale terms, but the in-memory object keeps them, so `Field::preProcess()` never fell back to the default until the stache was cleared. mirror the writer's rule when extracting publish form values. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01EmQ7DBwRHtNLUej3bbyMQW --- .../CP/Collections/ExtractsFromEntryFields.php | 5 ++++- .../CP/Taxonomies/ExtractsFromTermFields.php | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Http/Controllers/CP/Collections/ExtractsFromEntryFields.php b/src/Http/Controllers/CP/Collections/ExtractsFromEntryFields.php index fd76c685c6c..83b4b704e02 100644 --- a/src/Http/Controllers/CP/Collections/ExtractsFromEntryFields.php +++ b/src/Http/Controllers/CP/Collections/ExtractsFromEntryFields.php @@ -2,6 +2,8 @@ namespace Statamic\Http\Controllers\CP\Collections; +use Statamic\Support\Arr; + trait ExtractsFromEntryFields { protected function extractFromFields($entry, $blueprint) @@ -11,7 +13,8 @@ protected function extractFromFields($entry, $blueprint) $values = collect(); $target = $entry; while ($target) { - $values = $target->data()->merge($target->computedData())->merge($values); + $data = $target->isRoot() ? collect(Arr::removeNullValues($target->data()->all())) : $target->data(); + $values = $data->merge($target->computedData())->merge($values); $target = $target->origin(); } $values = $values->all(); diff --git a/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php b/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php index 71c84d63e93..3ba26471665 100644 --- a/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php +++ b/src/Http/Controllers/CP/Taxonomies/ExtractsFromTermFields.php @@ -2,15 +2,19 @@ namespace Statamic\Http\Controllers\CP\Taxonomies; +use Statamic\Support\Arr; + trait ExtractsFromTermFields { protected function extractFromFields($term, $blueprint) { // The values should only be data merged with the origin data. // We don't want injected taxonomy values, which $term->values() would have given us. - $values = $term->inDefaultLocale()->data()->merge( - $term->data() - ); + $values = collect(Arr::removeNullValues($term->inDefaultLocale()->data()->all())); + + if (! $term->isRoot()) { + $values = $values->merge($term->data()); + } $fields = $blueprint ->fields() From 02cdb00a0b3e895d0c75c7b34f8ecfe71dfec082 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 8 Sep 2026 13:04:06 +0100 Subject: [PATCH 2/6] refresh fieldtype meta after saving entries and terms return `meta` from the entry and term update endpoints and apply it in the save pipeline alongside the values, so relationship items added during `EntrySaving`/`TermSaving` render correctly. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01EmQ7DBwRHtNLUej3bbyMQW --- resources/js/components/ui/Publish/SavePipeline.js | 3 +++ src/Http/Controllers/CP/Collections/EntriesController.php | 1 + src/Http/Controllers/CP/Taxonomies/TermsController.php | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/resources/js/components/ui/Publish/SavePipeline.js b/resources/js/components/ui/Publish/SavePipeline.js index 5bd1c3c8592..6245f054fe4 100644 --- a/resources/js/components/ui/Publish/SavePipeline.js +++ b/resources/js/components/ui/Publish/SavePipeline.js @@ -77,6 +77,9 @@ export class Request extends Step { ); container.value.setExtraValues(response.data.data.extraValues); } + if (container && response.data.data?.hasOwnProperty('meta')) { + container.value.setMeta(response.data.data.meta); + } resolve(response); }) .catch((e) => { diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php index 32168c80e3a..d684f82e7e0 100644 --- a/src/Http/Controllers/CP/Collections/EntriesController.php +++ b/src/Http/Controllers/CP/Collections/EntriesController.php @@ -271,6 +271,7 @@ public function update(Request $request, $collection, $entry) return [ 'data' => array_merge((new EntryResource($entry->fresh()))->resolve()['data'], [ 'values' => $values, + 'meta' => $meta, 'extraValues' => $extraValues, ]), 'saved' => $saved, diff --git a/src/Http/Controllers/CP/Taxonomies/TermsController.php b/src/Http/Controllers/CP/Taxonomies/TermsController.php index 4479ef43b04..a1da5e71ca3 100644 --- a/src/Http/Controllers/CP/Taxonomies/TermsController.php +++ b/src/Http/Controllers/CP/Taxonomies/TermsController.php @@ -196,13 +196,14 @@ public function update(Request $request, $taxonomy, $term, $site) $saved = $term->updateLastModified(User::current())->save(); - [$values] = $this->extractFromFields($term, $term->blueprint()); + [$values, $meta] = $this->extractFromFields($term, $term->blueprint()); return (new TermResource($term)) ->additional([ 'saved' => $saved, 'data' => [ 'values' => $values, + 'meta' => $meta, ], ]); } From 3f20c7fc21f12cd2c1dda6a854f930aa82a39240 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 8 Sep 2026 13:04:06 +0100 Subject: [PATCH 3/6] add tests Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01EmQ7DBwRHtNLUej3bbyMQW --- .../ui/Publish/SavePipeline.test.js | 44 ++++++++++++- tests/Feature/Entries/UpdateEntryTest.php | 57 ++++++++++++++++ tests/Feature/Taxonomies/UpdateTermTest.php | 66 +++++++++++++++++++ 3 files changed, 165 insertions(+), 2 deletions(-) diff --git a/resources/js/tests/components/ui/Publish/SavePipeline.test.js b/resources/js/tests/components/ui/Publish/SavePipeline.test.js index 050d026a860..79501565c87 100644 --- a/resources/js/tests/components/ui/Publish/SavePipeline.test.js +++ b/resources/js/tests/components/ui/Publish/SavePipeline.test.js @@ -1,7 +1,12 @@ import { beforeEach, describe, expect, test, vi } from 'vitest'; import { ref } from 'vue'; +import axios from 'axios'; import Hooks from '@/components/Hooks.js'; -import { AfterSaveHooks, BeforeSaveHooks, Pipeline, PipelineStopped } from '@/components/ui/Publish/SavePipeline.js'; +import { AfterSaveHooks, BeforeSaveHooks, Pipeline, PipelineStopped, Request } from '@/components/ui/Publish/SavePipeline.js'; + +vi.mock('axios', () => ({ + default: { patch: vi.fn() }, +})); let saving; let errors; @@ -34,10 +39,45 @@ function throwingStep(error) { beforeEach(() => { saving = ref(false); errors = ref({}); - container = ref({ saving: vi.fn(), saved: vi.fn() }); + container = ref({ + saving: vi.fn(), + saved: vi.fn(), + visibleValues: {}, + values: { id: 'the-id' }, + revealerFields: [], + setValues: vi.fn(), + setExtraValues: vi.fn(), + setMeta: vi.fn(), + }); global.Statamic = { $hooks: new Hooks() }; }); +test('the request applies the values, extra values and meta from the response', async () => { + axios.patch.mockResolvedValue({ + data: { + data: { + values: { title: 'Saved' }, + extraValues: { depth: 1 }, + meta: { tags: { data: [{ id: 'tags::alfa', title: 'Alfa' }] } }, + }, + }, + }); + + await pipeline([new Request('/entries/1', 'PATCH', {})]); + + expect(container.value.setValues).toHaveBeenCalledWith({ id: 'the-id', title: 'Saved' }); + expect(container.value.setExtraValues).toHaveBeenCalledWith({ depth: 1 }); + expect(container.value.setMeta).toHaveBeenCalledWith({ tags: { data: [{ id: 'tags::alfa', title: 'Alfa' }] } }); +}); + +test('the request leaves the meta alone when the response has none', async () => { + axios.patch.mockResolvedValue({ data: { data: { values: { title: 'Saved' } } } }); + + await pipeline([new Request('/entries/1', 'PATCH', {})]); + + expect(container.value.setMeta).not.toHaveBeenCalled(); +}); + test('it runs the steps and finishes', async () => { const middle = step(); diff --git a/tests/Feature/Entries/UpdateEntryTest.php b/tests/Feature/Entries/UpdateEntryTest.php index 0d66cabbf37..fae7b00aa9e 100644 --- a/tests/Feature/Entries/UpdateEntryTest.php +++ b/tests/Feature/Entries/UpdateEntryTest.php @@ -12,6 +12,8 @@ use Statamic\Facades\Collection; use Statamic\Facades\Entry; use Statamic\Facades\Role; +use Statamic\Facades\Taxonomy; +use Statamic\Facades\Term; use Statamic\Facades\User; use Statamic\Structures\CollectionStructure; use Tests\FakesRoles; @@ -386,6 +388,61 @@ public function slug_and_auto_title_get_generated_after_save() $this->assertEquals('auto-avada-kedavra.md', pathinfo($entry->path(), PATHINFO_BASENAME)); } + #[Test] + public function default_values_are_returned_for_fields_saved_empty() + { + [$user, $collection] = $this->seedUserAndCollection(); + $this->seedBlueprintFields($collection, [ + 'nutrition_table' => [ + 'type' => 'grid', + 'default' => [['name' => 'Sugar'], ['name' => 'Salt']], + 'fields' => [['handle' => 'name', 'field' => ['type' => 'text']]], + ], + ]); + + $entry = EntryFactory::collection($collection) + ->slug('existing-entry') + ->data(['title' => 'Existing Entry']) + ->create(); + + $response = $this + ->actingAs($user) + ->update($entry) + ->assertOk(); + + $this->assertEquals(['Sugar', 'Salt'], collect($response->json('data.values.nutrition_table'))->pluck('name')->all()); + } + + #[Test] + public function meta_reflects_values_changed_while_saving() + { + [$user, $collection] = $this->seedUserAndCollection(); + $this->seedBlueprintFields($collection, [ + 'tags' => ['type' => 'terms', 'taxonomies' => ['tags']], + ]); + + Role::find('test')->addPermission('view tags terms'); + Taxonomy::make('tags')->save(); + Term::make()->taxonomy('tags')->inDefaultLocale()->slug('alfa')->data(['title' => 'Alfa'])->save(); + + Event::listen(EntrySaving::class, function (EntrySaving $event) { + $event->entry->set('tags', ['alfa']); + }); + + $entry = EntryFactory::collection($collection) + ->slug('existing-entry') + ->data(['title' => 'Existing Entry']) + ->create(); + + $response = $this + ->actingAs($user) + ->update($entry) + ->assertOk(); + + $this->assertEquals(['tags::alfa'], $response->json('data.values.tags')); + $this->assertEquals('Alfa', $response->json('data.meta.tags.data.0.title')); + } + #[Test] public function auto_title_only_gets_saved_on_localization_when_different_from_origin() { diff --git a/tests/Feature/Taxonomies/UpdateTermTest.php b/tests/Feature/Taxonomies/UpdateTermTest.php index c5fafaa9ac3..38ac0b61d07 100644 --- a/tests/Feature/Taxonomies/UpdateTermTest.php +++ b/tests/Feature/Taxonomies/UpdateTermTest.php @@ -2,7 +2,11 @@ namespace Tests\Feature\Taxonomies; +use Facades\Statamic\Fields\BlueprintRepository; +use Illuminate\Support\Facades\Event; use PHPUnit\Framework\Attributes\Test; +use Statamic\Events\TermSaving; +use Statamic\Facades\Blueprint; use Statamic\Facades\Taxonomy; use Statamic\Facades\Term; use Statamic\Facades\User; @@ -77,6 +81,68 @@ public function term_gets_updated() $this->assertEquals('Updated alfa', $term->title); } + #[Test] + public function default_values_are_returned_for_fields_saved_empty() + { + $this->setTestRoles(['test' => ['access cp', 'edit tags terms']]); + $user = tap(User::make()->assignRole('test'))->save(); + + Taxonomy::make('tags')->save(); + $this->seedBlueprintFields('tags', [ + 'nutrition_table' => [ + 'type' => 'grid', + 'default' => [['name' => 'Sugar'], ['name' => 'Salt']], + 'fields' => [['handle' => 'name', 'field' => ['type' => 'text']]], + ], + ]); + $term = tap(Term::make()->taxonomy('tags')->inDefaultLocale()->slug('alfa')->data(['title' => 'alfa']))->save(); + + $response = $this + ->actingAs($user) + ->update($term, ['title' => 'Updated alfa']) + ->assertOk(); + + $this->assertEquals(['Sugar', 'Salt'], collect($response->json('data.values.nutrition_table'))->pluck('name')->all()); + } + + #[Test] + public function meta_reflects_values_changed_while_saving() + { + $this->setTestRoles(['test' => ['access cp', 'edit tags terms', 'view topics terms']]); + $user = tap(User::make()->assignRole('test'))->save(); + + Taxonomy::make('tags')->save(); + Taxonomy::make('topics')->save(); + $this->seedBlueprintFields('tags', [ + 'topics' => ['type' => 'terms', 'taxonomies' => ['topics']], + ]); + $this->seedBlueprintFields('topics', []); + Term::make()->taxonomy('topics')->inDefaultLocale()->slug('bravo')->data(['title' => 'Bravo'])->save(); + $term = tap(Term::make()->taxonomy('tags')->inDefaultLocale()->slug('alfa')->data(['title' => 'alfa']))->save(); + + Event::listen(TermSaving::class, function (TermSaving $event) { + $event->term->set('topics', ['bravo']); + }); + + $response = $this + ->actingAs($user) + ->update($term, ['title' => 'Updated alfa']) + ->assertOk(); + + $this->assertEquals(['topics::bravo'], $response->json('data.values.topics')); + $this->assertEquals('Bravo', $response->json('data.meta.topics.data.0.title')); + } + + private function seedBlueprintFields($taxonomy, $fields) + { + $blueprint = Blueprint::makeFromFields($fields); + + BlueprintRepository::partialMock(); + BlueprintRepository::shouldReceive('in') + ->with('taxonomies/'.$taxonomy) + ->andReturn(collect([$blueprint])); + } + private function update($term, $attrs = []) { $payload = array_merge([ From 2daba46943f2598340d931ccaf15977d4fb071b2 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Wed, 9 Sep 2026 08:54:35 +0100 Subject: [PATCH 4/6] keep the slug's `auto` meta when refreshing meta after save Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01YNCvgvTMeBuxi35uWUEf1p --- .../js/components/ui/Publish/Container.vue | 1 + .../js/components/ui/Publish/SavePipeline.js | 3 ++- .../ui/Publish/SavePipeline.test.js | 20 +++++++++++++++++++ resources/js/util/resetMetaFromResponse.js | 12 +++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 resources/js/util/resetMetaFromResponse.js diff --git a/resources/js/components/ui/Publish/Container.vue b/resources/js/components/ui/Publish/Container.vue index 764daf728d9..5bae1670409 100644 --- a/resources/js/components/ui/Publish/Container.vue +++ b/resources/js/components/ui/Publish/Container.vue @@ -372,6 +372,7 @@ onUnmounted(() => { defineExpose({ name: props.name, values, + meta, saving, saved, revealerFields, diff --git a/resources/js/components/ui/Publish/SavePipeline.js b/resources/js/components/ui/Publish/SavePipeline.js index 6245f054fe4..115da46f4cd 100644 --- a/resources/js/components/ui/Publish/SavePipeline.js +++ b/resources/js/components/ui/Publish/SavePipeline.js @@ -1,5 +1,6 @@ import axios from 'axios'; import resetValuesFromResponse from '@/util/resetValuesFromResponse.js'; +import resetMetaFromResponse from '@/util/resetMetaFromResponse.js'; import { reveal } from '@api'; import { UPDATE_DEBOUNCE_MS } from '@/components/fieldtypes/constants'; @@ -78,7 +79,7 @@ export class Request extends Step { container.value.setExtraValues(response.data.data.extraValues); } if (container && response.data.data?.hasOwnProperty('meta')) { - container.value.setMeta(response.data.data.meta); + container.value.setMeta(resetMetaFromResponse(response.data.data.meta, container.value)); } resolve(response); }) diff --git a/resources/js/tests/components/ui/Publish/SavePipeline.test.js b/resources/js/tests/components/ui/Publish/SavePipeline.test.js index 79501565c87..437ea4edcdc 100644 --- a/resources/js/tests/components/ui/Publish/SavePipeline.test.js +++ b/resources/js/tests/components/ui/Publish/SavePipeline.test.js @@ -44,6 +44,7 @@ beforeEach(() => { saved: vi.fn(), visibleValues: {}, values: { id: 'the-id' }, + meta: {}, revealerFields: [], setValues: vi.fn(), setExtraValues: vi.fn(), @@ -70,6 +71,25 @@ test('the request applies the values, extra values and meta from the response', expect(container.value.setMeta).toHaveBeenCalledWith({ tags: { data: [{ id: 'tags::alfa', title: 'Alfa' }] } }); }); +test('the request keeps whether the slug is automatic when refreshing the meta', async () => { + container.value.meta = { slug: { auto: true }, tags: { data: [] } }; + axios.patch.mockResolvedValue({ + data: { + data: { + values: { title: 'Saved' }, + meta: { slug: null, tags: { data: [{ id: 'tags::alfa', title: 'Alfa' }] } }, + }, + }, + }); + + await pipeline([new Request('/entries/1', 'PATCH', {})]); + + expect(container.value.setMeta).toHaveBeenCalledWith({ + slug: { auto: true }, + tags: { data: [{ id: 'tags::alfa', title: 'Alfa' }] }, + }); +}); + test('the request leaves the meta alone when the response has none', async () => { axios.patch.mockResolvedValue({ data: { data: { values: { title: 'Saved' } } } }); diff --git a/resources/js/util/resetMetaFromResponse.js b/resources/js/util/resetMetaFromResponse.js new file mode 100644 index 00000000000..b9e7add42b8 --- /dev/null +++ b/resources/js/util/resetMetaFromResponse.js @@ -0,0 +1,12 @@ +export default function resetMetaFromResponse(responseMeta, container) { + const existingMeta = container.meta; + + if (!responseMeta) return existingMeta; + + // The slug fieldtype tracks whether the slug still follows its source. The server never sends it. + const auto = existingMeta?.slug?.auto; + + if (auto === undefined) return responseMeta; + + return { ...responseMeta, slug: { ...responseMeta.slug, auto } }; +} From 59f869c3174a593c0e9ad86a398119c33c676018 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Wed, 9 Sep 2026 08:54:36 +0100 Subject: [PATCH 5/6] add tests for localized entries and terms saved with empty values Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01YNCvgvTMeBuxi35uWUEf1p --- tests/Feature/Entries/UpdateEntryTest.php | 38 +++++++++++++++++++++ tests/Feature/Taxonomies/UpdateTermTest.php | 35 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/tests/Feature/Entries/UpdateEntryTest.php b/tests/Feature/Entries/UpdateEntryTest.php index fae7b00aa9e..694b8795bb3 100644 --- a/tests/Feature/Entries/UpdateEntryTest.php +++ b/tests/Feature/Entries/UpdateEntryTest.php @@ -413,6 +413,44 @@ public function default_values_are_returned_for_fields_saved_empty() $this->assertEquals(['Sugar', 'Salt'], collect($response->json('data.values.nutrition_table'))->pluck('name')->all()); } + #[Test] + public function localized_fields_saved_empty_stay_empty() + { + $this->setSites([ + 'en' => ['locale' => 'en', 'url' => '/'], + 'fr' => ['locale' => 'fr', 'url' => '/fr/'], + ]); + + [$user, $collection] = $this->seedUserAndCollection(); + $collection->sites(['en', 'fr'])->save(); + $this->seedBlueprintFields($collection, [ + 'nutrition_table' => [ + 'type' => 'grid', + 'default' => [['name' => 'Sugar'], ['name' => 'Salt']], + 'fields' => [['handle' => 'name', 'field' => ['type' => 'text']]], + ], + ]); + + $origin = EntryFactory::collection($collection) + ->locale('en') + ->slug('origin') + ->data(['title' => 'Origin', 'nutrition_table' => [['name' => 'Fat']]]) + ->create(); + + $localization = EntryFactory::collection($collection) + ->locale('fr') + ->origin($origin) + ->slug('localization') + ->create(); + + $response = $this + ->actingAs($user) + ->update($localization, ['nutrition_table' => [], '_localized' => ['nutrition_table']]) + ->assertOk(); + + $this->assertSame([], $response->json('data.values.nutrition_table')); + } + #[Test] public function meta_reflects_values_changed_while_saving() { diff --git a/tests/Feature/Taxonomies/UpdateTermTest.php b/tests/Feature/Taxonomies/UpdateTermTest.php index 38ac0b61d07..4f1c1dae8de 100644 --- a/tests/Feature/Taxonomies/UpdateTermTest.php +++ b/tests/Feature/Taxonomies/UpdateTermTest.php @@ -105,6 +105,41 @@ public function default_values_are_returned_for_fields_saved_empty() $this->assertEquals(['Sugar', 'Salt'], collect($response->json('data.values.nutrition_table'))->pluck('name')->all()); } + #[Test] + public function localized_fields_saved_empty_stay_empty() + { + $this->setSites([ + 'en' => ['locale' => 'en', 'url' => '/'], + 'fr' => ['locale' => 'fr', 'url' => '/fr'], + ]); + $this->setTestRoles(['test' => ['access cp', 'edit tags terms', 'access fr site']]); + $user = tap(User::make()->assignRole('test'))->save(); + + Taxonomy::make('tags')->save(); + $this->seedBlueprintFields('tags', [ + 'nutrition_table' => [ + 'type' => 'grid', + 'default' => [['name' => 'Sugar'], ['name' => 'Salt']], + 'fields' => [['handle' => 'name', 'field' => ['type' => 'text']]], + ], + ]); + $term = tap(Term::make()->taxonomy('tags')->slug('alfa') + ->dataForLocale('en', ['title' => 'alfa', 'nutrition_table' => [['name' => 'Fat']]]) + ->dataForLocale('fr', ['title' => 'le alfa']) + )->save(); + + $response = $this + ->actingAs($user) + ->update($term->in('fr'), [ + 'title' => 'le alfa', + 'nutrition_table' => [], + '_localized' => ['title', 'nutrition_table'], + ]) + ->assertOk(); + + $this->assertSame([], $response->json('data.values.nutrition_table')); + } + #[Test] public function meta_reflects_values_changed_while_saving() { From e7fed6fb78fe3b167a96727454f07ea743f6ce1f Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Wed, 9 Sep 2026 09:05:37 +0100 Subject: [PATCH 6/6] drop guards that never fire from `resetMetaFromResponse` Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01YNCvgvTMeBuxi35uWUEf1p --- resources/js/util/resetMetaFromResponse.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/resources/js/util/resetMetaFromResponse.js b/resources/js/util/resetMetaFromResponse.js index b9e7add42b8..cb1ed8da4dc 100644 --- a/resources/js/util/resetMetaFromResponse.js +++ b/resources/js/util/resetMetaFromResponse.js @@ -1,10 +1,6 @@ export default function resetMetaFromResponse(responseMeta, container) { - const existingMeta = container.meta; - - if (!responseMeta) return existingMeta; - // The slug fieldtype tracks whether the slug still follows its source. The server never sends it. - const auto = existingMeta?.slug?.auto; + const auto = container.meta.slug?.auto; if (auto === undefined) return responseMeta;