diff --git a/README.md b/README.md index d737a86f..1b1b5484 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,57 @@ 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. +This title is used by default. The developer can completely disable the use of the default title for all types of links or for each type separately. + +*app/_config/mylink.yml* +```yml +SilverStripe\LinkField\Models\Link: + use_default_title: false + +SilverStripe\LinkField\Models\PhoneLink: + use_default_title: false +``` + +The developer also can set his own default title value using an extension by using `updateDefaultLinkTitle` method for each link type class or by setting the `default_link_title` value in the configuration file. + +*app/_config/mylink.yml* +```yml +SilverStripe\LinkField\Models\Link: + use_default_title: true + +SilverStripe\LinkField\Models\PhoneLink: + default_link_title: 'My Phone Link' +``` + +*app/src/ExternalLinkExtension* +```php +owner->ExternalUrl); + } +} + +``` + +## Migrating from Version `1.0.0` or `dev-master` + +Please be aware that in early versions of this module (and in untagged `dev-master`) there were no table names defined +for our `Link` classes. These have now all been defined, which may mean that you need to rename your old tables, or +migrate the data across. + +EG: `SilverStripe_LinkField_Models_Link` needs to be migrated to `LinkField_Link`. + ## 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..9cb66881 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -5,6 +5,7 @@ en: BAD_DATA: 'Bad data' CREATE_LINK: 'Create link' DATA_HAS_NO_TYPEKEY: '"{class}": $data does not have a typeKey.' + DEFAULT_LINK_TITLE_WRONG_SITE_TREE_LINK: 'Page missing' EMPTY_DATA: 'Empty data' EXTERNAL_URL_FIELD: 'External url' EMAIL_FIELD: 'Email address' @@ -18,6 +19,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" diff --git a/src/Models/EmailLink.php b/src/Models/EmailLink.php index 2410af4a..d7125387 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 getLinkTypeDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/ExternalLink.php b/src/Models/ExternalLink.php index 27c167db..1e5132c7 100644 --- a/src/Models/ExternalLink.php +++ b/src/Models/ExternalLink.php @@ -35,4 +35,9 @@ public function getURL(): string { return $this->ExternalUrl ?: ''; } + + public function getLinkTypeDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/FileLink.php b/src/Models/FileLink.php index 15c7779e..7fbf65f9 100644 --- a/src/Models/FileLink.php +++ b/src/Models/FileLink.php @@ -32,4 +32,9 @@ public function getURL(): string $file = $this->File(); return $file->exists() ? (string) $file->getURL() : ''; } + + public function getLinkTypeDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/Link.php b/src/Models/Link.php index 78e9cb55..14b9c804 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; @@ -30,6 +31,10 @@ class Link extends DataObject 'OpenInNew' => 'Boolean', ]; + private static bool $use_default_title = true; + + private static string $default_link_title = 'Link'; + /** * In-memory only property used to change link type * This case is relevant for CMS edit form which doesn't use React driven UI @@ -68,6 +73,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 +296,23 @@ private function getLinkTypes(): array return $types; } + + public function getDefaultTitle(): string + { + // If we have a title or don't have link, we can just bail out without any changes + if (!$this->config()->get('use_default_title') || empty($this->getURL()) || $this->Title) { + return ''; + } + + $defaultLinkTitle = $this->getLinkTypeDefaultTitle(); + + $this->extend('updateDefaultLinkTitle', $defaultLinkTitle); + + return $defaultLinkTitle; + } + + public function getLinkTypeDefaultTitle(): string + { + return $this->config()->get('default_link_title'); + } } diff --git a/src/Models/PhoneLink.php b/src/Models/PhoneLink.php index 63fdf45d..d54dc0e2 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 getLinkTypeDefaultTitle(): string + { + return $this->getDescription(); + } } diff --git a/src/Models/SiteTreeLink.php b/src/Models/SiteTreeLink.php index 87c1f590..9d992967 100644 --- a/src/Models/SiteTreeLink.php +++ b/src/Models/SiteTreeLink.php @@ -134,4 +134,19 @@ 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 getLinkTypeDefaultTitle(): string + { + $pageExist = $this->Page()->exists() && $this->getURL(); + + // If the page doesn't exist, we can't get the title + if (!$pageExist) { + return _t( + 'LinkField.DEFAULT_LINK_TITLE_WRONG_SITE_TREE_LINK', + 'Page missing', + ); + } + + return $this->getTitle(); + } } diff --git a/templates/SilverStripe/LinkField/Models/Link.ss b/templates/SilverStripe/LinkField/Models/Link.ss index 7b95b36b..cc0d1296 100644 --- a/templates/SilverStripe/LinkField/Models/Link.ss +++ b/templates/SilverStripe/LinkField/Models/Link.ss @@ -1 +1,4 @@ -target="_blank" rel="noopener noreferrer"<% end_if %>>$Title +target="_blank" rel="noopener noreferrer"<% end_if %>> + $Title + <% if $DefaultTitle %> $DefaultTitle <% end_if %> + 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..148d9041 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,112 @@ public function linkUrlCasesDataProvider(): array ], ]; } + + function linkDefaultTitleDataProvider(): array + { + return [ + 'page link' => [ + 'page-link-1', + SiteTreeLink::class, + true, + '' + ], + 'email link' => [ + 'email-link-with-email', + EmailLink::class, + true, + '' + ], + 'external link' => [ + 'external-link-with-url', + ExternalLink::class, + true, + '' + ], + 'phone link' => [ + 'phone-link-with-phone', + PhoneLink::class, + true, + '' + ], + 'file link' => [ + 'file-link-no-image', + FileLink::class, + true, + '' + ], + 'page link with default title' => [ + 'page-link-with-default-title', + SiteTreeLink::class, + true, + '' + ], + 'email link with default title' => [ + 'email-link-with-default-title', + EmailLink::class, + true, + 'maxime@silverstripe.com' + ], + 'external link with default title' => [ + 'external-link-with-default-title', + ExternalLink::class, + true, + 'External Link: https://google.com' + ], + 'phone link with default title' => [ + 'phone-link-with-default-title', + PhoneLink::class, + true, + '+64 4 978 7330' + ], + 'file link with default title' => [ + 'file-link-with-default-title', + FileLink::class, + true, + '600x400.png' + ], + 'page link default title not allowed' => [ + 'page-link-with-default-title', + SiteTreeLink::class, + false, + '' + ], + 'email link without default title not allowed' => [ + 'email-link-with-default-title', + EmailLink::class, + false, + '' + ], + 'external link without default title not allowed' => [ + 'external-link-with-default-title', + ExternalLink::class, + false, + '' + ], + 'phone link without default title not allowed' => [ + 'phone-link-with-default-title', + PhoneLink::class, + false, + '' + ], + 'file link without default title not allowed' => [ + 'file-link-with-default-title', + FileLink::class, + false, + '' + ], + ]; + } + + /** + * @dataProvider linkDefaultTitleDataProvider + */ + public function testDefaultLinkTitle(string $identifier, string $class, bool $useDefaultTitle, string $expected): void + { + /** @var Link $link */ + $link = $this->objFromFixture($class, $identifier); + $link->config()->set('use_default_title', $useDefaultTitle); + + $this->assertEquals($expected, $link->getDefaultTitle()); + } } 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