Skip to content

Commit

Permalink
Merge pull request #31 from chrometoasters/feature/configurable-displ…
Browse files Browse the repository at this point in the history
…ay-name

Feature to make the presentation of a taxonomy term be configurable in CMS
  • Loading branch information
michalkleiner authored Oct 11, 2021
2 parents 65ac84d + f5d5ce2 commit e748e0a
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 11 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"silverstripe/framework": "^4",
"silverstripe/versioned": "^1",
"silverstripe/vendor-plugin": "^1",
"symbiote/silverstripe-gridfieldextensions": "^3.2.3"
"symbiote/silverstripe-gridfieldextensions": "^3.2.3",
"unclecheese/display-logic": "^2.0"
},
"extra": {
"expose": [
Expand Down
1 change: 1 addition & 0 deletions lang/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ en:
URLSegment: "A unique identifier used by the CMS (e.g. in URL filter parameters), which must be unique across all terms, taxonomies, concept classes. It will be automatically generated from <i><b>Name</b></i>, if left blank. Use lower case, URL-safe characters, no spaces. Avoid parentheses. Required."
Title: "This singular term is displayed to the public — often as a tag. The <i><b>Display name singular</b></i> will be the same or similar to the <i><b>Name</b></i> (though possibly longer) and will be automatically generated from the <i><b>Name</b></i>, if left blank. Avoid parentheses. Required."
TitlePlural: "This term is displayed to the public when the context requires a pluralised label. It will be automatically generated from <i><b>Name</b></i>, if left blank. Avoid parentheses. Required."
TitleCustom: "When provided, the custom display name overrides both singular and plural display names when displayed to the public."
Description: "The short reference description shown within the CMS"
AuthorDefinition: "Shown to authors and admins; a brief definition about the purpose of the term for those who create and edit taxonomies."
PublicDefinition: "Shown to users on the front-end; a brief definition of the term for those who view taxonomy terms as tags or filters."
Expand Down
10 changes: 8 additions & 2 deletions src/Models/BaseObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,21 @@ class BaseObject extends DataObject implements PermissionProvider
/**
* Get a text from the translations system for a given identifier
*
* Looks up the string for the extending/current class and uses this class strings as a fallback.
* Looks up the string for the extending/current class and recursively uses the parent class strings as a fallback.
* Supports sprintf evaluation of extra params to replace in the text.
*
* @param string $identifier
* @return string
*/
protected function _t(string $identifier, ...$params): string
{
$text = trim(trim(_t(static::class . '.' . $identifier)) ?: _t(self::class . '.' . $identifier));
$class = static::class;
$text = '';

while (!$text && $class !== DataObject::class) {
$text = trim(_t($class . '.' . $identifier));
$class = get_parent_class($class);
}

return sprintf($text, ...$params);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Models/BaseTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class BaseTerm extends BaseObject
private static $db = [
'Title' => 'Varchar(255)',
'TitlePlural' => 'Varchar(255)',
'TitleCustom' => 'Varchar(255)', // used from TaxonomyTerm, but data-wise belongs here
'Description' => 'Text',
'AuthorDefinition' => 'Text',
'PublicDefinition' => 'Text',
Expand Down Expand Up @@ -66,6 +67,7 @@ public function getCMSFields()
$this->i18nDisableWarning();

$fields = parent::getCMSFields();
$fields->removeByName(['TitleCustom']); // field is used from TaxonomyTerm level only

// Add description to fields
$fields->datafieldByName('Title')->setDescription($this->_t('Title'));
Expand Down
119 changes: 111 additions & 8 deletions src/Models/TaxonomyTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use SilverStripe\Forms\GridField\GridFieldPaginator;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\OptionsetField;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
Expand Down Expand Up @@ -51,10 +52,20 @@ class TaxonomyTerm extends BaseTerm

private static $plural_name = 'Taxonomies';

public const INHERIT = 'INHERIT';

public const SINGULAR = 'SINGULAR';

public const PLURAL = 'PLURAL';

public const CUSTOM = 'CUSTOM';

private static $db = [
'SingleSelect' => 'Boolean(0)',
'InternalOnly' => 'Boolean(0)',
'RequiredTypesInheritRoot' => 'Boolean(1)',
// configuration which field will be used as the source to display as the term on the front-end
'DisplayNameSourceFieldConf' => 'Varchar(20)',
];

private static $indexes = [
Expand Down Expand Up @@ -101,8 +112,9 @@ class TaxonomyTerm extends BaseTerm
];

private static $defaults = [
'InternalOnly' => 0,
'RequiredTypesInheritRoot' => 1,
'InternalOnly' => 0,
'RequiredTypesInheritRoot' => 1,
'DisplayNameSourceFieldConf' => self::INHERIT,
];

private static $field_labels = [
Expand Down Expand Up @@ -130,6 +142,13 @@ class TaxonomyTerm extends BaseTerm
'getAllAlternativeTermsNames' => 'Alternative terms',
];

private static $displayNameSourceFieldConfOptions = [
self::INHERIT => 'Is determined by the parent taxonomy type',
self::SINGULAR => 'Singlular',
self::PLURAL => 'Plural',
self::CUSTOM => 'Custom',
];


/**
* Helper method to determine if equivalent terms feature should be enabled
Expand Down Expand Up @@ -195,6 +214,24 @@ public function getCMSFields()
// Define a reusable literal field that represents an empty line
$lineBreak = LiteralField::create('LineBreak', '<br />');

// Exclude options that don't apply to taxonomy types (root-level terms)
$displayNameSourceFieldConfOptions = self::$displayNameSourceFieldConfOptions;
if (!$this->ParentID) {
unset($displayNameSourceFieldConfOptions[self::INHERIT]);
unset($displayNameSourceFieldConfOptions[self::CUSTOM]);
}

$fields->addFieldsToTab('Root.Main', [
OptionsetField::create('DisplayNameSourceFieldConf', 'Display name presented to the public', $displayNameSourceFieldConfOptions),
], 'Description');

if ($this->ParentID) {
$fields->addFieldsToTab('Root.Main', [
$customTitleField = TextField::create('TitleCustom', 'Display name custom')->setDescription($this->_t('TitleCustom'))
], 'Description');
$customTitleField->displayIf('DisplayNameSourceFieldConf')->isEqualTo(self::CUSTOM);
}

// Tweak InternalOnly
if ($this->ParentID) {
$fields->removeByName('InternalOnly');
Expand Down Expand Up @@ -966,20 +1003,25 @@ public function getAllAlternativeTermsGroupedByType(): array


/**
* Get a field from the most relevant Language Alternative term (either by the locale, the primary flag)
* Get a field from the most relevant Language Alternative term (either by the locale or the primary flag)
*
* When no suitable alt term is found this term is used as the fallback
* When no field name is provided, the term uses its preferred/configured display name (singular/plural/custom).
* When no suitable alt term is found this term is used as the fallback.
*
* Note: No return type is specified due to the nature of how Silverstripe works with db fields.
*
* @param string $field
* @param string $locale
* @param string|null $fieldName
* @param string|null $locale
* @return mixed|DataObject|DBField|null
*/
public function LanguageAltTermField(string $field, string $locale = '')
public function LanguageAltTermField(string $fieldName = null, string $locale = null)
{
$langTerms = $this->LanguageAltTerms();

if (!$fieldName) {
$fieldName = $this->getDisplayNameSourceField();
}

if ($locale) {
$filter = ['Locale' => $locale];
} else {
Expand All @@ -991,7 +1033,21 @@ public function LanguageAltTermField(string $field, string $locale = '')
$term = $this;
}

return $term && $term->hasField($field) ? $term->getField($field) : null;
return $term && $term->hasField($fieldName) ? $term->getField($fieldName) : null;
}


/**
* Get the display name of the most relevant Language Alternative term (either by the locale or the primary flag)
*
* Note: This is a shorthand for LanguageAltTermField method.
*
* @param string|null $locale
* @return mixed|DataObject|DBField|null
*/
public function LanguageAltTerm(string $locale = null)
{
return $this->LanguageAltTermField('', $locale);
}


Expand Down Expand Up @@ -1377,4 +1433,51 @@ public function getModelAdminEditLink(string $landingTab = 'Root_Main')

return sprintf('<a href="%s" target="_blank" class="at-link-external">%s</a>', $termEditURL, $this->Name);
}


/**
* Ensure a sensible default for DisplayNameSourceFieldConf
*
* @return string
*/
public function getDisplayNameSourceFieldConf(): string
{
if ($displayTitle = $this->getField('DisplayNameSourceFieldConf')) {
return $displayTitle;
}

if ($this->ParentID) {
return self::INHERIT;
}

return self::SINGULAR;
}


/**
* Get the name of the DB field that will be used to source the display title for the term/tag
*
* @return string
*/
public function getDisplayNameSourceField(): string
{
switch ($this->getDisplayNameSourceFieldConf()) {
case self::INHERIT:
$type = $this->Type();
// ID check to prevent infinite recursion since type returns itself as its type
if ($type && $type->exists() && $type->ID !== $this->ID) {
return $type->getDisplayNameSourceField();
}

return 'Title';
case self::SINGULAR:
return 'Title';
case self::PLURAL:
return 'TitlePlural';
case self::CUSTOM:
return 'TitleCustom';
default:
return 'Title';
}
}
}

0 comments on commit e748e0a

Please sign in to comment.