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