From 0351d1d6d88bf27cba9155da179073e775f83a97 Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Mon, 2 Feb 2026 13:25:56 +0100 Subject: [PATCH 1/7] Explicitly check value for null/empty --- src/Fieldtypes/Text.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fieldtypes/Text.php b/src/Fieldtypes/Text.php index d2e8dbfc32b..dd7663a355f 100644 --- a/src/Fieldtypes/Text.php +++ b/src/Fieldtypes/Text.php @@ -154,7 +154,7 @@ public function process($data) public function preProcessIndex($value) { - if ($value) { + if ($value !== null && $value !== '') { return $this->config('prepend').$value.$this->config('append'); } } From 9e8a91cd1013d0f415a49241f9c571a6d1626d59 Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Mon, 2 Feb 2026 13:27:52 +0100 Subject: [PATCH 2/7] Return proper JSON --- src/Http/Controllers/CP/SlugController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Http/Controllers/CP/SlugController.php b/src/Http/Controllers/CP/SlugController.php index b17de462def..c0f195969c6 100644 --- a/src/Http/Controllers/CP/SlugController.php +++ b/src/Http/Controllers/CP/SlugController.php @@ -9,10 +9,12 @@ class SlugController extends CpController { public function __invoke(Request $request) { - return Str::slug(...$request->validate([ + $slug = Str::slug(...$request->validate([ 'string' => ['required'], 'separator' => ['required'], 'language' => ['required'], ])); + + return response()->json($slug); } } From ea41a0dd3b9eec793d14ab3a71e830654a44b5dd Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Mon, 2 Feb 2026 13:28:44 +0100 Subject: [PATCH 3/7] Check for null/undefined/empty instead of falsy checks --- resources/js/components/slugs/Slugify.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/slugs/Slugify.vue b/resources/js/components/slugs/Slugify.vue index 4c32be80d61..31c2aa12e45 100644 --- a/resources/js/components/slugs/Slugify.vue +++ b/resources/js/components/slugs/Slugify.vue @@ -42,7 +42,7 @@ export default { handler() { if (!this.shouldSlugify) { this.slug = this.to; - } else if (!this.from) { + } else if (this.from === null || this.from === undefined || this.from === '') { this.slug = ''; } else { this.slugify(); From 0979b38c455ce335a005c9a78df5c7ff744909a4 Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Mon, 2 Feb 2026 13:29:05 +0100 Subject: [PATCH 4/7] Tweak test to handle JSON response --- tests/Feature/SlugTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/Feature/SlugTest.php b/tests/Feature/SlugTest.php index d9a017e628e..f97e86d3064 100644 --- a/tests/Feature/SlugTest.php +++ b/tests/Feature/SlugTest.php @@ -16,15 +16,16 @@ class SlugTest extends TestCase #[DataProvider('slugProvider')] public function it_generates_a_slug($string, $separator, $language, $expected) { - $this + $response = $this ->actingAs(tap(User::make()->makeSuper())->save()) ->postJson('/cp/slug', [ 'string' => $string, 'separator' => $separator, 'language' => $language, ]) - ->assertOk() - ->assertContent($expected); + ->assertOk(); + + $this->assertEquals($expected, $response->json()); } public static function slugProvider() From 2ae4d558c0383ff8ac654816dbeb9a86a85a756a Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 3 Feb 2026 14:37:35 -0500 Subject: [PATCH 5/7] use guard to check for null --- src/Fieldtypes/Text.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Fieldtypes/Text.php b/src/Fieldtypes/Text.php index dd7663a355f..dfc580e74c4 100644 --- a/src/Fieldtypes/Text.php +++ b/src/Fieldtypes/Text.php @@ -154,8 +154,10 @@ public function process($data) public function preProcessIndex($value) { - if ($value !== null && $value !== '') { - return $this->config('prepend').$value.$this->config('append'); + if (is_null($value)) { + return null; } + + return $this->config('prepend').$value.$this->config('append'); } } From e203e7c947ed0062294da0ed12ac0b11230c1ea2 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 3 Feb 2026 14:51:38 -0500 Subject: [PATCH 6/7] the endpoint is supposed to just return a slug as a string. no need for json. we will prevent axios from parsing it as json instead. --- resources/js/components/slugs/Slug.js | 2 +- src/Http/Controllers/CP/SlugController.php | 4 +--- tests/Feature/SlugTest.php | 7 +++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/resources/js/components/slugs/Slug.js b/resources/js/components/slugs/Slug.js index b40167e5a41..d1cf5b9a86d 100644 --- a/resources/js/components/slugs/Slug.js +++ b/resources/js/components/slugs/Slug.js @@ -113,7 +113,7 @@ export default class Slug { this.#controller = new AbortController; let aborted = false; - return axios.post(cp_url('slug'), payload, { signal: this.#controller.signal }) + return axios.post(cp_url('slug'), payload, { signal: this.#controller.signal, transformResponse: [(data) => data] }) .then(response => response.data) .catch(e => { if (axios.isCancel(e)) { diff --git a/src/Http/Controllers/CP/SlugController.php b/src/Http/Controllers/CP/SlugController.php index c0f195969c6..b17de462def 100644 --- a/src/Http/Controllers/CP/SlugController.php +++ b/src/Http/Controllers/CP/SlugController.php @@ -9,12 +9,10 @@ class SlugController extends CpController { public function __invoke(Request $request) { - $slug = Str::slug(...$request->validate([ + return Str::slug(...$request->validate([ 'string' => ['required'], 'separator' => ['required'], 'language' => ['required'], ])); - - return response()->json($slug); } } diff --git a/tests/Feature/SlugTest.php b/tests/Feature/SlugTest.php index f97e86d3064..d9a017e628e 100644 --- a/tests/Feature/SlugTest.php +++ b/tests/Feature/SlugTest.php @@ -16,16 +16,15 @@ class SlugTest extends TestCase #[DataProvider('slugProvider')] public function it_generates_a_slug($string, $separator, $language, $expected) { - $response = $this + $this ->actingAs(tap(User::make()->makeSuper())->save()) ->postJson('/cp/slug', [ 'string' => $string, 'separator' => $separator, 'language' => $language, ]) - ->assertOk(); - - $this->assertEquals($expected, $response->json()); + ->assertOk() + ->assertContent($expected); } public static function slugProvider() From f03da27dd60595f3255e24bb85b575f49f34f98e Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 3 Feb 2026 14:52:00 -0500 Subject: [PATCH 7/7] tests --- tests/Feature/SlugTest.php | 3 +++ tests/Fieldtypes/TextTest.php | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tests/Feature/SlugTest.php b/tests/Feature/SlugTest.php index d9a017e628e..c78798f98a5 100644 --- a/tests/Feature/SlugTest.php +++ b/tests/Feature/SlugTest.php @@ -40,6 +40,9 @@ public static function slugProvider() 'german characters' => ['Björn Müller', '-', 'de', 'bjoern-mueller'], 'arabic characters' => ['صباح الخير', '-', 'ar', 'sbah-alkhyr'], 'alternate separator' => ['one two three', '_', 'en', 'one_two_three'], + 'null string' => ['null', '-', 'en', 'null'], + 'zero string' => ['0', '-', 'en', '0'], + 'false string' => ['false', '-', 'en', 'false'], ]; } } diff --git a/tests/Fieldtypes/TextTest.php b/tests/Fieldtypes/TextTest.php index b679a4652f6..9f483409e52 100644 --- a/tests/Fieldtypes/TextTest.php +++ b/tests/Fieldtypes/TextTest.php @@ -33,4 +33,29 @@ public static function processValuesProvider() 'number' => ['number', [0, 3, 3, 3.14, null]], ]; } + + #[Test] + #[DataProvider('preProcessIndexProvider')] + public function it_pre_processes_index_values($config, $value, $expected) + { + $field = (new Text)->setField(new Field('test', array_merge([ + 'type' => 'text', + ], $config))); + + $this->assertSame($expected, $field->preProcessIndex($value)); + } + + public static function preProcessIndexProvider() + { + return [ + 'string value' => [[], 'hello', 'hello'], + 'null value' => [[], null, null], + 'zero integer' => [[], 0, '0'], + 'zero string' => [[], '0', '0'], + 'zero with prepend' => [['prepend' => '$'], 0, '$0'], + 'zero with append' => [['append' => '%'], 0, '0%'], + 'zero with prepend and append' => [['prepend' => '$', 'append' => '%'], 0, '$0%'], + 'string with prepend' => [['prepend' => '$'], 'hello', '$hello'], + ]; + } }