NEW Use autoscaffolding for SiteTree CMS fields (#2983)

This commit is contained in:
Guy Sartorelli 2024-08-15 13:14:57 +12:00 committed by GitHub
parent 63fd61716e
commit e58c388cb7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 202 additions and 163 deletions

View File

@ -3,13 +3,10 @@
namespace SilverStripe\CMS\Model; namespace SilverStripe\CMS\Model;
use Page; use Page;
use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\File; use SilverStripe\Assets\File;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\HeaderField; use SilverStripe\Forms\HeaderField;
use SilverStripe\Forms\OptionsetField; use SilverStripe\Forms\OptionsetField;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\TreeDropdownField;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
/** /**
@ -45,6 +42,13 @@ class RedirectorPage extends Page
"LinkToFile" => File::class, "LinkToFile" => File::class,
]; ];
private static array $scaffold_cms_fields_settings = [
'ignoreFields' => [
'RedirectionType',
'Content',
],
];
private static $table_name = 'RedirectorPage'; private static $table_name = 'RedirectorPage';
/** /**
@ -194,18 +198,19 @@ class RedirectorPage extends Page
public function getCMSFields() public function getCMSFields()
{ {
$this->beforeUpdateCMSFields(function (FieldList $fields) { $this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields->removeByName('Content', true);
// Remove all metadata fields, does not apply for redirector pages // Remove all metadata fields, does not apply for redirector pages
$fields->removeByName('Metadata'); $fields->removeByName('Metadata');
$fields->addFieldsToTab( $fields->addFieldsToTab(
'Root.Main', 'Root.Main',
[ [
new HeaderField('RedirectorDescHeader', _t(__CLASS__.'.HEADER', "This page will redirect users to another page")), HeaderField::create(
new OptionsetField( 'RedirectorDescHeader',
"RedirectionType", _t(__CLASS__.'.HEADER', "This page will redirect users to another page")
_t(__CLASS__.'.REDIRECTTO', "Redirect to"), ),
OptionsetField::create(
'RedirectionType',
$this->fieldLabel('RedirectionType'),
[ [
"Internal" => _t(__CLASS__.'.REDIRECTTOPAGE', "A page on your website"), "Internal" => _t(__CLASS__.'.REDIRECTTOPAGE', "A page on your website"),
"External" => _t(__CLASS__.'.REDIRECTTOEXTERNAL', "Another website"), "External" => _t(__CLASS__.'.REDIRECTTOEXTERNAL', "Another website"),
@ -213,14 +218,8 @@ class RedirectorPage extends Page
], ],
"Internal" "Internal"
), ),
new TreeDropdownField( ],
"LinkToID", 'ExternalURL'
_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"))
]
); );
}); });

View File

@ -247,8 +247,8 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
private static $namespace_map = null; private static $namespace_map = null;
private static $db = [ private static $db = [
"URLSegment" => "Varchar(255)",
"Title" => "Varchar(255)", "Title" => "Varchar(255)",
"URLSegment" => "Varchar(255)",
"MenuTitle" => "Varchar(100)", "MenuTitle" => "Varchar(100)",
"Content" => "HTMLText", "Content" => "HTMLText",
"MetaDescription" => "Text", "MetaDescription" => "Text",
@ -295,6 +295,25 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
"ShowInSearch" => 1, "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 $table_name = 'SiteTree';
private static $versioning = [ private static $versioning = [
@ -2105,147 +2124,135 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
*/ */
public function getCMSFields() public function getCMSFields()
{ {
$dependentNote = ''; $this->beforeUpdateCMSFields(function (FieldList $fields) {
$dependentTable = new LiteralField('DependentNote', '<p></p>'); $dependentNote = '';
$dependentTable = LiteralField::create('DependentNote', '<p></p>');
// Create a table for showing pages linked to this one // Create a table for showing pages linked to this one
$dependentPages = $this->DependentPages(); $dependentPages = $this->DependentPages();
$dependentPagesCount = $dependentPages->count(); $dependentPagesCount = $dependentPages->count();
if ($dependentPagesCount) { if ($dependentPagesCount) {
$dependentColumns = [ $dependentColumns = [
'Title' => $this->fieldLabel('Title'), 'Title' => $this->fieldLabel('Title'),
'DependentLinkType' => _t(__CLASS__.'.DependtPageColumnLinkType', 'Link type'), 'DependentLinkType' => _t(__CLASS__.'.DependtPageColumnLinkType', 'Link type'),
]; ];
if (class_exists(Subsite::class)) { if (class_exists(Subsite::class)) {
$dependentColumns['Subsite.Title'] = Subsite::singleton()->i18n_singular_name(); $dependentColumns['Subsite.Title'] = Subsite::singleton()->i18n_singular_name();
}
$dependentNote = LiteralField::create('DependentNote', '<p>' . _t(__CLASS__.'.DEPENDENT_NOTE', 'The following pages depend on this page. This includes virtual pages, redirector pages, and pages with content links.') . '</p>');
$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</%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', '<p>' . _t(__CLASS__.'.DEPENDENT_NOTE', 'The following pages depend on this page. This includes virtual pages, redirector pages, and pages with content links.') . '</p>'); $baseLink = Controller::join_links(
$dependentTable = GridField::create( Director::absoluteBaseURL(),
'DependentPages', (static::config()->get('nested_urls') && $this->ParentID ? $this->Parent()->RelativeLink(true) : null)
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</%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( $urlsegment = SiteTreeURLSegmentField::create("URLSegment", $this->fieldLabel('URLSegment'))
Director::absoluteBaseURL(), ->setURLPrefix($baseLink)
(static::config()->get('nested_urls') && $this->ParentID ? $this->Parent()->RelativeLink(true) : null) ->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')) $fields->dataFieldByName('Content')?->addExtraClass('stacked');
->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 = new FieldList( // Metadata fields
$rootTab = new TabSet( $fields->addFieldsToTab('Root.Main', [
"Root", ToggleCompositeField::create(
$tabMain = new Tab( 'Metadata',
'Main', _t(__CLASS__.'.MetadataToggle', 'Metadata'),
new TextField("Title", $this->fieldLabel('Title')), [
$urlsegment, $metaFieldDesc = TextareaField::create("MetaDescription", $this->fieldLabel('MetaDescription')),
new TextField("MenuTitle", $this->fieldLabel('MenuTitle')), $metaFieldExtra = TextareaField::create("ExtraMeta", $this->fieldLabel('ExtraMeta'))
$htmlField = HTMLEditorField::create("Content", _t(__CLASS__.'.HTMLEDITORTITLE', "Content", 'HTML editor title')), ]
ToggleCompositeField::create( )->setHeadingLevel(4),
'Metadata', ]);
_t(__CLASS__.'.MetadataToggle', 'Metadata'), // Help text for MetaData on page content editor
[ $metaFieldDesc
$metaFieldDesc = new TextareaField("MetaDescription", $this->fieldLabel('MetaDescription')), ->setRightTitle(
$metaFieldExtra = new TextareaField("ExtraMeta", $this->fieldLabel('ExtraMeta')) _t(
] 'SilverStripe\\CMS\\Model\\SiteTree.METADESCHELP',
)->setHeadingLevel(4) "Search engines use this content for displaying search results (although it will not influence their ranking)."
), )
$tabDependent = new Tab( )
'Dependent', ->addExtraClass('help');
$metaFieldExtra
->setRightTitle(
_t(
'SilverStripe\\CMS\\Model\\SiteTree.METAEXTRAHELP',
"HTML tags for additional meta information. For example <meta name=\"customName\" content=\"your custom content here\">"
)
)
->addExtraClass('help');
// Conditional dependent pages tab
if ($dependentPagesCount) {
$fields->addFieldsToTab('Root.Dependent', [
$dependentNote, $dependentNote,
$dependentTable $dependentTable
) ]);
) $tabDependent = $fields->findTab('Root.Dependent');
); $tabDependent->setTitle(_t(__CLASS__.'.TABDEPENDENT', "Dependent pages") . " ($dependentPagesCount)");
$htmlField->addExtraClass('stacked'); }
// Help text for MetaData on page content editor $fields->findTab('Root.Main')->setTitle(_t(__CLASS__ . '.TABCONTENT', 'Main content'));
$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 <meta name=\"customName\" content=\"your custom content here\">"
)
)
->addExtraClass('help');
// Conditional dependent pages tab if ($this->ObsoleteClassName) {
if ($dependentPagesCount) { $obsoleteWarning = _t(
$tabDependent->setTitle(_t(__CLASS__.'.TABDEPENDENT', "Dependent pages") . " ($dependentPagesCount)"); 'SilverStripe\\CMS\\Model\\SiteTree.OBSOLETECLASS',
} else { "This page is of obsolete type {type}. Saving will reset its type and you may lose data",
$fields->removeFieldFromTab('Root', 'Dependent'); ['type' => $this->ObsoleteClassName]
} );
$tabMain->setTitle(_t(__CLASS__.'.TABCONTENT', "Main content")); $fields->addFieldToTab(
"Root.Main",
LiteralField::create("ObsoleteWarningHeader", "<p class=\"alert alert-warning\">$obsoleteWarning</p>"),
"Title"
);
}
});
if ($this->ObsoleteClassName) { return parent::getCMSFields();
$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", "<p class=\"alert alert-warning\">$obsoleteWarning</p>"),
"Title"
);
}
if (SiteTree::$runCMSFieldsExtensions) {
$this->extend('updateCMSFields', $fields);
}
return $fields;
} }

View File

@ -7,6 +7,8 @@ use SilverStripe\Core\Convert;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\ReadonlyTransformation; use SilverStripe\Forms\ReadonlyTransformation;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\TreeDropdownField; use SilverStripe\Forms\TreeDropdownField;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ValidationResult; use SilverStripe\ORM\ValidationResult;
@ -77,8 +79,23 @@ class VirtualPage extends Page
private static $db = [ private static $db = [
"VersionID" => "Int", "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'; private static $table_name = 'VirtualPage';
/** /**
@ -216,21 +233,18 @@ class VirtualPage extends Page
public function getCMSFields() public function getCMSFields()
{ {
$this->beforeUpdateCMSFields(function (FieldList $fields) { $this->beforeUpdateCMSFields(function (FieldList $fields) {
// Setup the linking to the original page. $copyContentFromField = $fields->dataFieldByName('CopyContentFromID');
$copyContentFromField = TreeDropdownField::create( $fields->addFieldToTab('Root.Main', $copyContentFromField, 'Title');
'CopyContentFromID',
_t(VirtualPage::class . '.CHOOSE', "Linked Page"),
SiteTree::class
);
// Setup virtual fields // Setup virtual fields
if ($virtualFields = $this->getVirtualFields()) { if ($virtualFields = $this->getVirtualFields()) {
$roTransformation = new ReadonlyTransformation(); $roTransformation = new ReadonlyTransformation();
foreach ($virtualFields as $virtualField) { foreach ($virtualFields as $virtualFieldName) {
if ($fields->dataFieldByName($virtualField)) { $virtualField = $fields->dataFieldByName($virtualFieldName);
if ($virtualField) {
$fields->replaceField( $fields->replaceField(
$virtualField, $virtualFieldName,
$fields->dataFieldByName($virtualField)->transform($roTransformation) $virtualField->transform($roTransformation)
); );
} }
} }
@ -238,8 +252,6 @@ class VirtualPage extends Page
$msgs = []; $msgs = [];
$fields->addFieldToTab('Root.Main', $copyContentFromField, 'Title');
// Create links back to the original object in the CMS // Create links back to the original object in the CMS
if ($this->CopyContentFrom()->exists()) { if ($this->CopyContentFrom()->exists()) {
$link = HTML::createTag( $link = HTML::createTag(
@ -280,6 +292,25 @@ class VirtualPage extends Page
'VirtualPageMessage', 'VirtualPageMessage',
'<div class="alert alert-info">' . implode('. ', $msgs) . '.</div>' '<div class="alert alert-info">' . implode('. ', $msgs) . '.</div>'
), 'CopyContentFromID'); ), '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(); return parent::getCMSFields();

View File

@ -163,10 +163,10 @@ en:
REDIRECTTOPAGE: 'A page on your website' REDIRECTTOPAGE: 'A page on your website'
SINGULARNAME: 'Redirector Page' SINGULARNAME: 'Redirector Page'
YOURPAGE: 'Page on your website' YOURPAGE: 'Page on your website'
db_ExternalURL: 'External URL' db_ExternalURL: 'Other website URL'
db_RedirectionType: 'Redirection type' db_RedirectionType: 'Redirect to'
has_one_LinkTo: 'Link to' has_one_LinkTo: 'Page on your website'
has_one_LinkToFile: 'Link to file' has_one_LinkToFile: 'File'
SilverStripe\CMS\Model\RedirectorPageController: SilverStripe\CMS\Model\RedirectorPageController:
HASBEENSETUP: 'A redirector page has been set up without anywhere to redirect to.' HASBEENSETUP: 'A redirector page has been set up without anywhere to redirect to.'
SilverStripe\CMS\Model\SiteTree: SilverStripe\CMS\Model\SiteTree:
@ -341,8 +341,10 @@ en:
other: '{count} Base Pages' other: '{count} Base Pages'
PageTypNotAllowedOnRoot: 'Original page type "{type}" is not allowed on the root level for this virtual page' PageTypNotAllowedOnRoot: 'Original page type "{type}" is not allowed on the root level for this virtual page'
SINGULARNAME: 'Virtual Page' SINGULARNAME: 'Virtual Page'
db_CustomMetaDescription: 'Custom Meta Description'
db_CustomExtraMeta: 'Custom Meta Tags'
db_VersionID: 'Version ID' db_VersionID: 'Version ID'
has_one_CopyContentFrom: 'Copy content from' has_one_CopyContentFrom: 'Linked Page'
SilverStripe\CMS\Reports\BrokenFilesReport: SilverStripe\CMS\Reports\BrokenFilesReport:
BROKENFILES: 'Pages with broken files' BROKENFILES: 'Pages with broken files'
BrokenLinksGroupTitle: 'Broken links reports' BrokenLinksGroupTitle: 'Broken links reports'