From e58c388cb7231e921f4649b0819351e7dedcd7d5 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli <36352093+GuySartorelli@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:14:57 +1200 Subject: [PATCH] NEW Use autoscaffolding for SiteTree CMS fields (#2983) --- code/Model/RedirectorPage.php | 33 ++--- code/Model/SiteTree.php | 265 +++++++++++++++++----------------- code/Model/VirtualPage.php | 55 +++++-- lang/en.yml | 12 +- 4 files changed, 202 insertions(+), 163 deletions(-) diff --git a/code/Model/RedirectorPage.php b/code/Model/RedirectorPage.php index bb4ea2b7..97124f32 100644 --- a/code/Model/RedirectorPage.php +++ b/code/Model/RedirectorPage.php @@ -3,13 +3,10 @@ namespace SilverStripe\CMS\Model; use Page; -use SilverStripe\AssetAdmin\Forms\UploadField; use SilverStripe\Assets\File; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\HeaderField; use SilverStripe\Forms\OptionsetField; -use SilverStripe\Forms\TextField; -use SilverStripe\Forms\TreeDropdownField; use SilverStripe\Versioned\Versioned; /** @@ -45,6 +42,13 @@ class RedirectorPage extends Page "LinkToFile" => File::class, ]; + private static array $scaffold_cms_fields_settings = [ + 'ignoreFields' => [ + 'RedirectionType', + 'Content', + ], + ]; + private static $table_name = 'RedirectorPage'; /** @@ -194,18 +198,19 @@ class RedirectorPage extends Page public function getCMSFields() { $this->beforeUpdateCMSFields(function (FieldList $fields) { - $fields->removeByName('Content', true); - // Remove all metadata fields, does not apply for redirector pages $fields->removeByName('Metadata'); $fields->addFieldsToTab( 'Root.Main', [ - new HeaderField('RedirectorDescHeader', _t(__CLASS__.'.HEADER', "This page will redirect users to another page")), - new OptionsetField( - "RedirectionType", - _t(__CLASS__.'.REDIRECTTO', "Redirect to"), + HeaderField::create( + 'RedirectorDescHeader', + _t(__CLASS__.'.HEADER', "This page will redirect users to another page") + ), + OptionsetField::create( + 'RedirectionType', + $this->fieldLabel('RedirectionType'), [ "Internal" => _t(__CLASS__.'.REDIRECTTOPAGE', "A page on your website"), "External" => _t(__CLASS__.'.REDIRECTTOEXTERNAL', "Another website"), @@ -213,14 +218,8 @@ class RedirectorPage extends Page ], "Internal" ), - new TreeDropdownField( - "LinkToID", - _t(__CLASS__.'.YOURPAGE', "Page on your website"), - SiteTree::class - ), - new UploadField('LinkToFile', _t(__CLASS__.'.FILE', "File")), - new TextField("ExternalURL", _t(__CLASS__.'.OTHERURL', "Other website URL")) - ] + ], + 'ExternalURL' ); }); diff --git a/code/Model/SiteTree.php b/code/Model/SiteTree.php index 41e2ded7..5d33539a 100755 --- a/code/Model/SiteTree.php +++ b/code/Model/SiteTree.php @@ -247,8 +247,8 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi private static $namespace_map = null; private static $db = [ - "URLSegment" => "Varchar(255)", "Title" => "Varchar(255)", + "URLSegment" => "Varchar(255)", "MenuTitle" => "Varchar(100)", "Content" => "HTMLText", "MetaDescription" => "Text", @@ -295,6 +295,25 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi "ShowInSearch" => 1, ]; + private static array $scaffold_cms_fields_settings = [ + 'ignoreFields' => [ + 'ShowInMenus', + 'ShowInSearch', + 'Sort', + 'HasBrokenFile', + 'HasBrokenLink', + 'ReportClass', + 'Parent', + // The metadata fields will be added back with explicit fields + 'MetaDescription', + 'ExtraMeta', + ], + 'ignoreRelations' => [ + 'VirtualPages', + 'BackLinks', + ], + ]; + private static $table_name = 'SiteTree'; private static $versioning = [ @@ -2105,147 +2124,135 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi */ public function getCMSFields() { - $dependentNote = ''; - $dependentTable = new LiteralField('DependentNote', '

'); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $dependentNote = ''; + $dependentTable = LiteralField::create('DependentNote', '

'); - // Create a table for showing pages linked to this one - $dependentPages = $this->DependentPages(); - $dependentPagesCount = $dependentPages->count(); - if ($dependentPagesCount) { - $dependentColumns = [ - 'Title' => $this->fieldLabel('Title'), - 'DependentLinkType' => _t(__CLASS__.'.DependtPageColumnLinkType', 'Link type'), - ]; - if (class_exists(Subsite::class)) { - $dependentColumns['Subsite.Title'] = Subsite::singleton()->i18n_singular_name(); + // Create a table for showing pages linked to this one + $dependentPages = $this->DependentPages(); + $dependentPagesCount = $dependentPages->count(); + if ($dependentPagesCount) { + $dependentColumns = [ + 'Title' => $this->fieldLabel('Title'), + 'DependentLinkType' => _t(__CLASS__.'.DependtPageColumnLinkType', 'Link type'), + ]; + if (class_exists(Subsite::class)) { + $dependentColumns['Subsite.Title'] = Subsite::singleton()->i18n_singular_name(); + } + + $dependentNote = LiteralField::create('DependentNote', '

' . _t(__CLASS__.'.DEPENDENT_NOTE', 'The following pages depend on this page. This includes virtual pages, redirector pages, and pages with content links.') . '

'); + $dependentTable = GridField::create( + 'DependentPages', + false, + $dependentPages + ); + $dataColumns = $dependentTable->getConfig()->getComponentByType(GridFieldDataColumns::class); + $dataColumns + ->setDisplayFields($dependentColumns) + ->setFieldFormatting([ + 'Title' => function ($value, &$item) { + $title = $item->Title; + $untitled = _t( + __CLASS__ . '.UntitledDependentObject', + 'Untitled {instanceType}', + ['instanceType' => $item->i18n_singular_name()] + ); + $tag = $item->hasMethod('CMSEditLink') ? 'a' : 'span'; + return sprintf( + '<%s%s class="dependent-content__edit-link %s">%s', + $tag, + $tag === 'a' ? sprintf(' href="%s"', $item->CMSEditLink()) : '', + $title ? '' : 'dependent-content__edit-link--untitled', + $title ? Convert::raw2xml($title) : $untitled, + $tag + ); + } + ]); + $dependentTable->getConfig()->addComponent(Injector::inst()->create(GridFieldLazyLoader::class)); } - $dependentNote = new LiteralField('DependentNote', '

' . _t(__CLASS__.'.DEPENDENT_NOTE', 'The following pages depend on this page. This includes virtual pages, redirector pages, and pages with content links.') . '

'); - $dependentTable = GridField::create( - 'DependentPages', - false, - $dependentPages + $baseLink = Controller::join_links( + Director::absoluteBaseURL(), + (static::config()->get('nested_urls') && $this->ParentID ? $this->Parent()->RelativeLink(true) : null) ); - $dataColumns = $dependentTable->getConfig()->getComponentByType(GridFieldDataColumns::class); - $dataColumns - ->setDisplayFields($dependentColumns) - ->setFieldFormatting([ - 'Title' => function ($value, &$item) { - $title = $item->Title; - $untitled = _t( - __CLASS__ . '.UntitledDependentObject', - 'Untitled {instanceType}', - ['instanceType' => $item->i18n_singular_name()] - ); - $tag = $item->hasMethod('CMSEditLink') ? 'a' : 'span'; - return sprintf( - '<%s%s class="dependent-content__edit-link %s">%s', - $tag, - $tag === 'a' ? sprintf(' href="%s"', $item->CMSEditLink()) : '', - $title ? '' : 'dependent-content__edit-link--untitled', - $title ? Convert::raw2xml($title) : $untitled, - $tag - ); - } - ]); - $dependentTable->getConfig()->addComponent(Injector::inst()->create(GridFieldLazyLoader::class)); - } - $baseLink = Controller::join_links( - Director::absoluteBaseURL(), - (static::config()->get('nested_urls') && $this->ParentID ? $this->Parent()->RelativeLink(true) : null) - ); + $urlsegment = SiteTreeURLSegmentField::create("URLSegment", $this->fieldLabel('URLSegment')) + ->setURLPrefix($baseLink) + ->setURLSuffix('?stage=Stage') + ->setDefaultURL($this->generateURLSegment(_t( + 'SilverStripe\\CMS\\Controllers\\CMSMain.NEWPAGE', + 'New {pagetype}', + ['pagetype' => $this->i18n_singular_name()] + ))) + ->addExtraClass(($this->isHomePage() ? 'homepage-warning' : '')); + $helpText = (static::config()->get('nested_urls') && $this->numChildren()) + ? $this->fieldLabel('LinkChangeNote') + : ''; + if (!URLSegmentFilter::create()->getAllowMultibyte()) { + $helpText .= _t('SilverStripe\\CMS\\Forms\\SiteTreeURLSegmentField.HelpChars', ' Special characters are automatically converted or removed.'); + } + $urlsegment->setHelpText($helpText); + $fields->replaceField('URLSegment', $urlsegment); - $urlsegment = SiteTreeURLSegmentField::create("URLSegment", $this->fieldLabel('URLSegment')) - ->setURLPrefix($baseLink) - ->setURLSuffix('?stage=Stage') - ->setDefaultURL($this->generateURLSegment(_t( - 'SilverStripe\\CMS\\Controllers\\CMSMain.NEWPAGE', - 'New {pagetype}', - ['pagetype' => $this->i18n_singular_name()] - ))) - ->addExtraClass(($this->isHomePage() ? 'homepage-warning' : '')); - $helpText = (static::config()->get('nested_urls') && $this->numChildren()) - ? $this->fieldLabel('LinkChangeNote') - : ''; - if (!URLSegmentFilter::create()->getAllowMultibyte()) { - $helpText .= _t('SilverStripe\\CMS\\Forms\\SiteTreeURLSegmentField.HelpChars', ' Special characters are automatically converted or removed.'); - } - $urlsegment->setHelpText($helpText); + $fields->dataFieldByName('Content')?->addExtraClass('stacked'); - $fields = new FieldList( - $rootTab = new TabSet( - "Root", - $tabMain = new Tab( - 'Main', - new TextField("Title", $this->fieldLabel('Title')), - $urlsegment, - new TextField("MenuTitle", $this->fieldLabel('MenuTitle')), - $htmlField = HTMLEditorField::create("Content", _t(__CLASS__.'.HTMLEDITORTITLE', "Content", 'HTML editor title')), - ToggleCompositeField::create( - 'Metadata', - _t(__CLASS__.'.MetadataToggle', 'Metadata'), - [ - $metaFieldDesc = new TextareaField("MetaDescription", $this->fieldLabel('MetaDescription')), - $metaFieldExtra = new TextareaField("ExtraMeta", $this->fieldLabel('ExtraMeta')) - ] - )->setHeadingLevel(4) - ), - $tabDependent = new Tab( - 'Dependent', + // Metadata fields + $fields->addFieldsToTab('Root.Main', [ + ToggleCompositeField::create( + 'Metadata', + _t(__CLASS__.'.MetadataToggle', 'Metadata'), + [ + $metaFieldDesc = TextareaField::create("MetaDescription", $this->fieldLabel('MetaDescription')), + $metaFieldExtra = TextareaField::create("ExtraMeta", $this->fieldLabel('ExtraMeta')) + ] + )->setHeadingLevel(4), + ]); + // Help text for MetaData on page content editor + $metaFieldDesc + ->setRightTitle( + _t( + 'SilverStripe\\CMS\\Model\\SiteTree.METADESCHELP', + "Search engines use this content for displaying search results (although it will not influence their ranking)." + ) + ) + ->addExtraClass('help'); + $metaFieldExtra + ->setRightTitle( + _t( + 'SilverStripe\\CMS\\Model\\SiteTree.METAEXTRAHELP', + "HTML tags for additional meta information. For example " + ) + ) + ->addExtraClass('help'); + + // Conditional dependent pages tab + if ($dependentPagesCount) { + $fields->addFieldsToTab('Root.Dependent', [ $dependentNote, $dependentTable - ) - ) - ); - $htmlField->addExtraClass('stacked'); + ]); + $tabDependent = $fields->findTab('Root.Dependent'); + $tabDependent->setTitle(_t(__CLASS__.'.TABDEPENDENT', "Dependent pages") . " ($dependentPagesCount)"); + } - // Help text for MetaData on page content editor - $metaFieldDesc - ->setRightTitle( - _t( - 'SilverStripe\\CMS\\Model\\SiteTree.METADESCHELP', - "Search engines use this content for displaying search results (although it will not influence their ranking)." - ) - ) - ->addExtraClass('help'); - $metaFieldExtra - ->setRightTitle( - _t( - 'SilverStripe\\CMS\\Model\\SiteTree.METAEXTRAHELP', - "HTML tags for additional meta information. For example " - ) - ) - ->addExtraClass('help'); + $fields->findTab('Root.Main')->setTitle(_t(__CLASS__ . '.TABCONTENT', 'Main content')); - // Conditional dependent pages tab - if ($dependentPagesCount) { - $tabDependent->setTitle(_t(__CLASS__.'.TABDEPENDENT', "Dependent pages") . " ($dependentPagesCount)"); - } else { - $fields->removeFieldFromTab('Root', 'Dependent'); - } + if ($this->ObsoleteClassName) { + $obsoleteWarning = _t( + 'SilverStripe\\CMS\\Model\\SiteTree.OBSOLETECLASS', + "This page is of obsolete type {type}. Saving will reset its type and you may lose data", + ['type' => $this->ObsoleteClassName] + ); - $tabMain->setTitle(_t(__CLASS__.'.TABCONTENT', "Main content")); + $fields->addFieldToTab( + "Root.Main", + LiteralField::create("ObsoleteWarningHeader", "

$obsoleteWarning

"), + "Title" + ); + } + }); - if ($this->ObsoleteClassName) { - $obsoleteWarning = _t( - 'SilverStripe\\CMS\\Model\\SiteTree.OBSOLETECLASS', - "This page is of obsolete type {type}. Saving will reset its type and you may lose data", - ['type' => $this->ObsoleteClassName] - ); - - $fields->addFieldToTab( - "Root.Main", - LiteralField::create("ObsoleteWarningHeader", "

$obsoleteWarning

"), - "Title" - ); - } - - if (SiteTree::$runCMSFieldsExtensions) { - $this->extend('updateCMSFields', $fields); - } - - return $fields; + return parent::getCMSFields(); } diff --git a/code/Model/VirtualPage.php b/code/Model/VirtualPage.php index a973aab8..a65cd1f2 100644 --- a/code/Model/VirtualPage.php +++ b/code/Model/VirtualPage.php @@ -7,6 +7,8 @@ use SilverStripe\Core\Convert; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\ReadonlyTransformation; +use SilverStripe\Forms\TextareaField; +use SilverStripe\Forms\TextField; use SilverStripe\Forms\TreeDropdownField; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\ValidationResult; @@ -77,8 +79,23 @@ class VirtualPage extends Page private static $db = [ "VersionID" => "Int", + 'CustomMetaDescription' => 'Text', + 'CustomExtraMeta' => 'HTMLText' ]; + private static array $scaffold_cms_fields_settings = [ + 'ignoreFields' => [ + 'VersionID', + 'CustomMetaDescription', + 'CustomExtraMeta', + ], + ]; + + /** + * Whether to allow overriding the meta description and extra meta tags. + */ + private static bool $allow_meta_overrides = true; + private static $table_name = 'VirtualPage'; /** @@ -216,21 +233,18 @@ class VirtualPage extends Page public function getCMSFields() { $this->beforeUpdateCMSFields(function (FieldList $fields) { - // Setup the linking to the original page. - $copyContentFromField = TreeDropdownField::create( - 'CopyContentFromID', - _t(VirtualPage::class . '.CHOOSE', "Linked Page"), - SiteTree::class - ); + $copyContentFromField = $fields->dataFieldByName('CopyContentFromID'); + $fields->addFieldToTab('Root.Main', $copyContentFromField, 'Title'); // Setup virtual fields if ($virtualFields = $this->getVirtualFields()) { $roTransformation = new ReadonlyTransformation(); - foreach ($virtualFields as $virtualField) { - if ($fields->dataFieldByName($virtualField)) { + foreach ($virtualFields as $virtualFieldName) { + $virtualField = $fields->dataFieldByName($virtualFieldName); + if ($virtualField) { $fields->replaceField( - $virtualField, - $fields->dataFieldByName($virtualField)->transform($roTransformation) + $virtualFieldName, + $virtualField->transform($roTransformation) ); } } @@ -238,8 +252,6 @@ class VirtualPage extends Page $msgs = []; - $fields->addFieldToTab('Root.Main', $copyContentFromField, 'Title'); - // Create links back to the original object in the CMS if ($this->CopyContentFrom()->exists()) { $link = HTML::createTag( @@ -280,6 +292,25 @@ class VirtualPage extends Page 'VirtualPageMessage', '
' . implode('. ', $msgs) . '.
' ), 'CopyContentFromID'); + + if (static::config()->get('allow_meta_overrides')) { + $fields->addFieldToTab( + 'Root.Main', + TextareaField::create( + 'CustomMetaDescription', + $this->fieldLabel('CustomMetaDescription') + )->setDescription(_t(__CLASS__ . '.OverrideNote', 'Overrides inherited value from the source')), + 'MetaDescription' + ); + $fields->addFieldToTab( + 'Root.Main', + TextField::create( + 'CustomExtraMeta', + $this->fieldLabel('CustomExtraMeta') + )->setDescription(_t(__CLASS__ . '.OverrideNote', 'Overrides inherited value from the source')), + 'ExtraMeta' + ); + } }); return parent::getCMSFields(); diff --git a/lang/en.yml b/lang/en.yml index 610afc91..c2ba9f82 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -163,10 +163,10 @@ en: REDIRECTTOPAGE: 'A page on your website' SINGULARNAME: 'Redirector Page' YOURPAGE: 'Page on your website' - db_ExternalURL: 'External URL' - db_RedirectionType: 'Redirection type' - has_one_LinkTo: 'Link to' - has_one_LinkToFile: 'Link to file' + db_ExternalURL: 'Other website URL' + db_RedirectionType: 'Redirect to' + has_one_LinkTo: 'Page on your website' + has_one_LinkToFile: 'File' SilverStripe\CMS\Model\RedirectorPageController: HASBEENSETUP: 'A redirector page has been set up without anywhere to redirect to.' SilverStripe\CMS\Model\SiteTree: @@ -341,8 +341,10 @@ en: other: '{count} Base Pages' PageTypNotAllowedOnRoot: 'Original page type "{type}" is not allowed on the root level for this virtual page' SINGULARNAME: 'Virtual Page' + db_CustomMetaDescription: 'Custom Meta Description' + db_CustomExtraMeta: 'Custom Meta Tags' db_VersionID: 'Version ID' - has_one_CopyContentFrom: 'Copy content from' + has_one_CopyContentFrom: 'Linked Page' SilverStripe\CMS\Reports\BrokenFilesReport: BROKENFILES: 'Pages with broken files' BrokenLinksGroupTitle: 'Broken links reports'