diff --git a/lang/en/fieldtypes.php b/lang/en/fieldtypes.php index 650448ef7a2..9c8001cc338 100644 --- a/lang/en/fieldtypes.php +++ b/lang/en/fieldtypes.php @@ -121,6 +121,7 @@ 'integer.title' => 'Integer', 'link.config.collections' => 'Entries from these collections will be available. Leaving this empty will make entries from routable collections available.', 'link.config.container' => 'Choose which asset container to use for this field.', + 'link.config.default_option' => 'The default Link type option, if available for the fieldtype\'s configuration.', 'link.title' => 'Link', 'list.config.add_row' => 'Customize the label of the "Add Item" button.', 'list.title' => 'List', diff --git a/src/Fieldtypes/Link.php b/src/Fieldtypes/Link.php index a42c37e7a91..d5ca4200819 100644 --- a/src/Fieldtypes/Link.php +++ b/src/Fieldtypes/Link.php @@ -49,6 +49,21 @@ protected function configFieldItems(): array 'type' => 'toggle', 'width' => '50', ], + 'default_option' => [ + 'display' => __('Default Option'), + 'instructions' => __('statamic::fieldtypes.link.config.default_option'), + 'type' => 'select', + 'max_items' => 1, + 'width' => '50', + 'clearable' => true, + 'placeholder' => __('Default'), + 'options' => [ + 'asset' => __('Asset'), + 'entry' => __('Entry'), + 'first-child' => __('First Child'), + 'url' => __('URL'), + ], + ], ], ], ]; @@ -131,7 +146,18 @@ public function preload() private function initialOption($value, $entry, $asset) { if (! $value) { - return $this->field->isRequired() ? 'url' : null; + $fallback = $this->field->isRequired() ? 'url' : null; + $option = $this->field->get('default_option', $fallback); + + if ($option === 'first-child' && ! $this->showFirstChildOption()) { + return $fallback; + } + + if ($option === 'asset' && ! $this->showAssetOption()) { + return $fallback; + } + + return $option; } if ($value === '@child') { diff --git a/tests/Fieldtypes/LinkTest.php b/tests/Fieldtypes/LinkTest.php index be520a0262f..bdab29b236d 100644 --- a/tests/Fieldtypes/LinkTest.php +++ b/tests/Fieldtypes/LinkTest.php @@ -4,16 +4,20 @@ use Facades\Statamic\Routing\ResolveRedirect; use Mockery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use Statamic\Entries\Entry; use Statamic\Facades; use Statamic\Fields\ArrayableString; use Statamic\Fields\Field; use Statamic\Fieldtypes\Link; +use Tests\PreventSavingStacheItemsToDisk; use Tests\TestCase; class LinkTest extends TestCase { + use PreventSavingStacheItemsToDisk; + #[Test] public function it_augments_string_to_string() { @@ -261,4 +265,36 @@ public function it_pre_processes_first_child_for_index_when_no_children() $this->assertNull($fieldtype->preProcessIndex('@child')); } + + #[Test] + #[DataProvider('initialOptionProvider')] + public function it_preloads_the_initial_option(array $config, mixed $value, bool $withParent, mixed $expected) + { + $this->actingAs(tap(Facades\User::make()->makeSuper())->save()); + tap(Facades\Collection::make('pages')->routes('{slug}'))->sites(['en'])->save(); + + $field = new Field('test', $config); + $field->setValue($value); + + if ($withParent) { + $field->setParent(Mockery::mock()); + } + + $fieldtype = (new Link)->setField($field); + + $this->assertSame($expected, $fieldtype->preload()['initialOption']); + } + + public static function initialOptionProvider(): array + { + return [ + 'configured option is used' => [['type' => 'link', 'default_option' => 'entry'], null, false, 'entry'], + 'url when required and no default option' => [['type' => 'link', 'required' => true], null, false, 'url'], + 'null when optional and no default option' => [['type' => 'link'], null, false, null], + 'first-child falls back to url when unavailable' => [['type' => 'link', 'default_option' => 'first-child', 'required' => true], null, true, 'url'], + 'asset falls back to url when unavailable and required' => [['type' => 'link', 'default_option' => 'asset', 'required' => true], null, false, 'url'], + 'asset falls back to null when unavailable and optional' => [['type' => 'link', 'default_option' => 'asset'], null, false, null], + 'existing value overrides default option' => [['type' => 'link', 'default_option' => 'entry'], 'https://example.com', false, 'url'], + ]; + } }