From cde153b2630faf293797b9eb787d4fd957fbaec3 Mon Sep 17 00:00:00 2001 From: Graham Reynolds Date: Tue, 18 Nov 2025 19:50:05 +1000 Subject: [PATCH 1/2] Allow statamic URLs to use fragments/querystrings --- src/Fieldtypes/Concerns/ResolvesStatamicUrls.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php b/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php index 90eb25ae91b..79714ba3d38 100644 --- a/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php +++ b/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php @@ -13,11 +13,11 @@ trait ResolvesStatamicUrls */ protected function resolveStatamicUrls(string $content) { - return preg_replace_callback('/([("])statamic:\/\/([^()"]*)([)"])/im', function ($matches) { + return preg_replace_callback('/([("])statamic:\/\/([^()"?#]*)([^()"]*)([)"])/im', function ($matches) { $data = Data::find($matches[2]); - $url = $data ? $data->url() : ''; + $url = $data ? $data->url().$matches[3] : ''; - return $matches[1].$url.$matches[3]; + return $matches[1].$url.$matches[4]; }, $content); } } From d8f8084ff25761dfc5219f0e066cce16944adda0 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 18 Nov 2025 11:01:11 -0500 Subject: [PATCH 2/2] add tests --- .../Concerns/ResolvesStatamicUrlsTest.php | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/Fieldtypes/Concerns/ResolvesStatamicUrlsTest.php diff --git a/tests/Fieldtypes/Concerns/ResolvesStatamicUrlsTest.php b/tests/Fieldtypes/Concerns/ResolvesStatamicUrlsTest.php new file mode 100644 index 00000000000..5fbab8345e2 --- /dev/null +++ b/tests/Fieldtypes/Concerns/ResolvesStatamicUrlsTest.php @@ -0,0 +1,136 @@ +testClass = new class + { + use ResolvesStatamicUrls; + + public function resolve(string $content) + { + return $this->resolveStatamicUrls($content); + } + }; + } + + #[Test] + public function it_calls_data_find_with_correct_id() + { + $data = Mockery::mock(); + $data->shouldReceive('url')->andReturn('/some/url'); + + DataFacade::shouldReceive('find') + ->once() + ->with('foo::bar/baz.ext') + ->andReturn($data); + + $content = '[link](statamic://foo::bar/baz.ext)'; + $result = $this->testClass->resolve($content); + + $this->assertEquals('[link](/some/url)', $result); + } + + #[Test] + public function it_handles_non_existent_data() + { + DataFacade::shouldReceive('find') + ->once() + ->with('non-existent') + ->andReturn(null); + + $content = '[link](statamic://non-existent)'; + $result = $this->testClass->resolve($content); + + $this->assertEquals('[link]()', $result); + } + + #[Test] + public function it_handles_multiple_urls() + { + $data1 = Mockery::mock(); + $data1->shouldReceive('url')->andReturn('/url-1'); + + $data2 = Mockery::mock(); + $data2->shouldReceive('url')->andReturn('/url-2'); + + DataFacade::shouldReceive('find') + ->once() + ->with('id-1') + ->andReturn($data1); + + DataFacade::shouldReceive('find') + ->once() + ->with('id-2') + ->andReturn($data2); + + $content = '[link1](statamic://id-1) and '; + $result = $this->testClass->resolve($content); + + $this->assertEquals('[link1](/url-1) and ', $result); + } + + #[Test] + public function it_maintains_hash_fragments() + { + $data = Mockery::mock(); + $data->shouldReceive('url')->andReturn('/some/page'); + + DataFacade::shouldReceive('find') + ->once() + ->with('entry::123') + ->andReturn($data); + + $content = '[link](statamic://entry::123#section)'; + $result = $this->testClass->resolve($content); + + $this->assertEquals('[link](/some/page#section)', $result); + } + + #[Test] + public function it_maintains_query_strings() + { + $data = Mockery::mock(); + $data->shouldReceive('url')->andReturn('/some/page'); + + DataFacade::shouldReceive('find') + ->once() + ->with('entry::123') + ->andReturn($data); + + $content = '[link](statamic://entry::123?foo=bar)'; + $result = $this->testClass->resolve($content); + + $this->assertEquals('[link](/some/page?foo=bar)', $result); + } + + #[Test] + public function it_maintains_query_strings_and_hash_fragments() + { + $data = Mockery::mock(); + $data->shouldReceive('url')->andReturn('/some/page'); + + DataFacade::shouldReceive('find') + ->once() + ->with('entry::123') + ->andReturn($data); + + $content = '[link](statamic://entry::123?foo=bar#section)'; + $result = $this->testClass->resolve($content); + + $this->assertEquals('[link](/some/page?foo=bar#section)', $result); + } +}