diff --git a/README.md b/README.md index d737a86f..99da512a 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,29 @@ class Page extends SiteTree Note that you also need to add a `has_one` relation on the `Link` model to match your `has_many` here. See [official docs about `has_many`](https://docs.silverstripe.org/en/developer_guides/model/relations/#has-many) +## Default title for each link type + +By default, if the title for the link has not been set, then the default title will be used instead according to the type of link that is used. Default link is not stored in the database as link title. This value is used only when rendering page content. + +The developer also can set his own default title value using an extension by using `updateDefaultLinkTitle` method for each link type class. +*app/src/ExternalLinkExtension* +```php +owner->ExternalUrl); + } +} + +``` + ## Migrating from Shae Dawson's Linkable module https://github.com/sheadawson/silverstripe-linkable diff --git a/lang/en.yml b/lang/en.yml index 619f15c8..8e123a8c 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -18,6 +18,7 @@ en: KEYS_ARE_NOT_ARRAY: 'If `keys` is provdied, it must be an array' LINK_TYPE_TITLE: 'Link Type' LINK_FIELD_TITLE: 'Title' + LINK_FIELD_TITLE_DESCRIPTION: 'If left blank, default title will be used' NO_CLASSNAME: '"{class}": All types should reference a valid classname' NOT_REGISTERED_LINKTYPE: '"{class}": "{typekey}" is not a registered Link Type.' NOTHING_TO_PROCESS: "Nothing to process for `{table}`\r\n" @@ -32,3 +33,5 @@ en: UNAUTHORIZED: 'Unauthorized' UPDATE_LINK: 'Update link' VERSIONED_STATUS_MISMATCH: 'Linkable and LinkField do not have matching Versioned applications. Make sure that both are either un-Versioned or Versioned' + SilverStripe\LinkField\Models\SiteTreeLink: + MISSING_DEFAULT_TITLE: 'Page missing' diff --git a/src/Models/EmailLink.php b/src/Models/EmailLink.php index 2410af4a..31e1836b 100644 --- a/src/Models/EmailLink.php +++ b/src/Models/EmailLink.php @@ -38,4 +38,9 @@ public function getURL(): string { return $this->Email ? sprintf('mailto:%s', $this->Email) : ''; } + + public function getDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/ExternalLink.php b/src/Models/ExternalLink.php index 27c167db..3f9c7820 100644 --- a/src/Models/ExternalLink.php +++ b/src/Models/ExternalLink.php @@ -35,4 +35,9 @@ public function getURL(): string { return $this->ExternalUrl ?: ''; } + + public function getDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/FileLink.php b/src/Models/FileLink.php index 15c7779e..02d35c60 100644 --- a/src/Models/FileLink.php +++ b/src/Models/FileLink.php @@ -24,7 +24,8 @@ public function getCMSFields(): FieldList public function getDescription(): string { - return $this->File()?->getFilename() ?? ''; + $file = $this->File(); + return $file->exists() ? (string) $file->getFilename() : ''; } public function getURL(): string @@ -32,4 +33,9 @@ public function getURL(): string $file = $this->File(); return $file->exists() ? (string) $file->getURL() : ''; } + + public function getDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/Link.php b/src/Models/Link.php index 78e9cb55..0cfbf3c6 100644 --- a/src/Models/Link.php +++ b/src/Models/Link.php @@ -5,6 +5,7 @@ use InvalidArgumentException; use ReflectionException; use SilverStripe\Core\ClassInfo; +use SilverStripe\Core\Config\Config; use SilverStripe\Core\Injector\Injector; use SilverStripe\Forms\CompositeValidator; use SilverStripe\Forms\DropdownField; @@ -68,6 +69,7 @@ public function getCMSFields(): FieldList $titleField = $fields->dataFieldByName('Title'); $titleField->setTitle(_t('LinkField.LINK_FIELD_TITLE', 'Title')); + $titleField->setDescription(_t('LinkField.LINK_FIELD_TITLE_DESCRIPTION', 'If left blank, default title will be used')); $openInNewField = $fields->dataFieldByName('OpenInNew'); $openInNewField->setTitle(_t('LinkField.OPEN_IN_NEW_TITLE', 'Open in new window?')); @@ -290,4 +292,23 @@ private function getLinkTypes(): array return $types; } + + public function getDisplayTitle(): string + { + // If we have a title, we can just bail out without any changes + if ($this->Title && $this->getURL()) { + return $this->Title; + } + + $defaultLinkTitle = $this->getDefaultTitle(); + + $this->extend('updateDefaultLinkTitle', $defaultLinkTitle); + + return $defaultLinkTitle; + } + + public function getDefaultTitle(): string + { + return $this->getDescription() ?: $this->getURL(); + } } diff --git a/src/Models/PhoneLink.php b/src/Models/PhoneLink.php index 63fdf45d..cabeeb91 100644 --- a/src/Models/PhoneLink.php +++ b/src/Models/PhoneLink.php @@ -33,4 +33,9 @@ public function getURL(): string { return $this->Phone ? sprintf('tel:%s', $this->Phone) : ''; } + + public function getDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/SiteTreeLink.php b/src/Models/SiteTreeLink.php index 87c1f590..764c5f28 100644 --- a/src/Models/SiteTreeLink.php +++ b/src/Models/SiteTreeLink.php @@ -134,4 +134,20 @@ public function getTitle(): ?string // Use page title as a default value in case CMS user didn't provide the title return $page->Title; } + + public function getDefaultTitle(): string + { + $page = $this->Page(); + $pageExist = $this->Page()->exists(); + + // If the page doesn't exist, we can't get the title + if (!$pageExist) { + return _t( + static::class . '.MISSING_DEFAULT_TITLE', + 'Page missing', + ); + } + + return $page->Title; + } } diff --git a/templates/SilverStripe/LinkField/Models/Link.ss b/templates/SilverStripe/LinkField/Models/Link.ss index 7b95b36b..ebfb3eed 100644 --- a/templates/SilverStripe/LinkField/Models/Link.ss +++ b/templates/SilverStripe/LinkField/Models/Link.ss @@ -1 +1 @@ -target="_blank" rel="noopener noreferrer"<% end_if %>>$Title +target="_blank" rel="noopener noreferrer"<% end_if %>>$DisplayTitle diff --git a/tests/php/Models/Extensions/ExternalLinkExtension.php b/tests/php/Models/Extensions/ExternalLinkExtension.php new file mode 100644 index 00000000..abd7f570 --- /dev/null +++ b/tests/php/Models/Extensions/ExternalLinkExtension.php @@ -0,0 +1,14 @@ +owner->getURL()); + } +} diff --git a/tests/php/Models/LinkTest.php b/tests/php/Models/LinkTest.php index 37fd43d0..bb66bd70 100644 --- a/tests/php/Models/LinkTest.php +++ b/tests/php/Models/LinkTest.php @@ -20,6 +20,7 @@ use SilverStripe\ORM\DataObject; use SilverStripe\ORM\ValidationException; use SilverStripe\Versioned\Versioned; +use SilverStripe\LinkField\Tests\Models\Extensions\ExternalLinkExtension; class LinkTest extends SapphireTest { @@ -28,6 +29,12 @@ class LinkTest extends SapphireTest */ protected static $fixture_file = 'LinkTest.yml'; + protected static $required_extensions = [ + ExternalLink::class => [ + ExternalLinkExtension::class, + ], + ]; + protected function setUp(): void { parent::setUp(); @@ -329,4 +336,71 @@ public function linkUrlCasesDataProvider(): array ], ]; } + + function linkDefaultTitleDataProvider(): array + { + return [ + 'page link' => [ + 'page-link-1', + SiteTreeLink::class, + 'PageLink1' + ], + 'email link' => [ + 'email-link-with-email', + EmailLink::class, + 'EmailLinkWithEmail' + ], + 'external link' => [ + 'external-link-with-url', + ExternalLink::class, + 'ExternalLinkWithUrl' + ], + 'phone link' => [ + 'phone-link-with-phone', + PhoneLink::class, + 'PhoneLinkWithPhone' + ], + 'file link' => [ + 'file-link-no-image', + FileLink::class, + 'FileLinkNoImage' + ], + 'page link with default title' => [ + 'page-link-with-default-title', + SiteTreeLink::class, + 'Page1' + ], + 'email link with default title' => [ + 'email-link-with-default-title', + EmailLink::class, + 'maxime@silverstripe.com' + ], + 'external link with default title' => [ + 'external-link-with-default-title', + ExternalLink::class, + 'External Link: https://google.com' + ], + 'phone link with default title' => [ + 'phone-link-with-default-title', + PhoneLink::class, + '+64 4 978 7330' + ], + 'file link with default title' => [ + 'file-link-with-default-title', + FileLink::class, + '600x400.png' + ], + ]; + } + + /** + * @dataProvider linkDefaultTitleDataProvider + */ + public function testDefaultLinkTitle(string $identifier, string $class, string $expected): void + { + /** @var Link $link */ + $link = $this->objFromFixture($class, $identifier); + + $this->assertEquals($expected, $link->getDisplayTitle()); + } } diff --git a/tests/php/Models/LinkTest.yml b/tests/php/Models/LinkTest.yml index 7faac9d9..6263d974 100644 --- a/tests/php/Models/LinkTest.yml +++ b/tests/php/Models/LinkTest.yml @@ -36,6 +36,8 @@ SilverStripe\LinkField\Models\SiteTreeLink: QueryString: 'param1=value1¶m2=option2' Anchor: 'my-anchor' Page: =>SilverStripe\CMS\Model\SiteTree.page-1 + page-link-with-default-title: + Page: =>SilverStripe\CMS\Model\SiteTree.page-1 SilverStripe\LinkField\Models\EmailLink: email-link-with-email: @@ -43,6 +45,8 @@ SilverStripe\LinkField\Models\EmailLink: Email: 'maxime@silverstripe.com' email-link-no-email: Title: 'EmailLinkNoEmail' + email-link-with-default-title: + Email: 'maxime@silverstripe.com' SilverStripe\LinkField\Models\ExternalLink: external-link-with-url: @@ -50,6 +54,8 @@ SilverStripe\LinkField\Models\ExternalLink: ExternalUrl: 'https://google.com' external-link-no-url: Title: 'ExternalLinkNoUrl' + external-link-with-default-title: + ExternalUrl: 'https://google.com' SilverStripe\LinkField\Models\PhoneLink: phone-link-with-phone: @@ -57,6 +63,8 @@ SilverStripe\LinkField\Models\PhoneLink: Phone: '+64 4 978 7330' phone-link-no-phone: Title: 'PhoneLinkNoPhone' + phone-link-with-default-title: + Phone: '+64 4 978 7330' SilverStripe\LinkField\Models\FileLink: file-link-with-image: @@ -64,3 +72,5 @@ SilverStripe\LinkField\Models\FileLink: File: =>SilverStripe\Assets\Image.image-1 file-link-no-image: Title: 'FileLinkNoImage' + file-link-with-default-title: + File: =>SilverStripe\Assets\Image.image-1