From 4ceb0b2d41e087396eae0d5dfbde15f4b4a1ffca Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Mon, 12 Aug 2024 13:00:04 +1200 Subject: [PATCH] DOC Document SiteTree form field scaffolding Also updates best practices around scaffolding form fields. --- .../00_Model/10_Versioning.md | 28 ++--- .../00_Model/11_Scaffolding.md | 12 +- .../03_Forms/01_Validation.md | 14 ++- .../03_Forms/Field_types/02_DateField.md | 16 +-- .../Field_types/03_HTMLEditorField.md | 27 +++-- .../03_Forms/Field_types/04_GridField.md | 107 ++++++++++-------- .../05_Extending/01_Extensions.md | 3 +- .../09_Security/00_Member.md | 14 ++- .../14_Files/01_File_Management.md | 8 +- en/02_Developer_Guides/14_Files/02_Images.md | 33 +++--- .../How_Tos/Extend_CMS_Interface.md | 29 +++-- en/08_Changelogs/6.0.0.md | 105 +++++++++++++++++ 12 files changed, 274 insertions(+), 122 deletions(-) diff --git a/en/02_Developer_Guides/00_Model/10_Versioning.md b/en/02_Developer_Guides/00_Model/10_Versioning.md index 5b2a72e60..c41ff493a 100644 --- a/en/02_Developer_Guides/00_Model/10_Versioning.md +++ b/en/02_Developer_Guides/00_Model/10_Versioning.md @@ -555,6 +555,7 @@ This can also be manually enabled for a single `GridField` by passing the `Versi namespace { use SilverStripe\CMS\Model\SiteTree; + use SilverStripe\Forms\FieldList; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor; use SilverStripe\Forms\GridField\GridFieldDetailForm; @@ -564,16 +565,15 @@ namespace { { public function getCMSFields() { - $fields = parent::getCMSFields(); - - $config = GridFieldConfig_RelationEditor::create(); - $config - ->getComponentByType(GridFieldDetailForm::class) - ->setItemRequestClass(VersionedGridFieldItemRequest::class); - $gridField = GridField::create('Items', 'Items', $this->Items(), $config); - $fields->addFieldToTab('Root.Items', $gridField); - - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $config = GridFieldConfig_RelationEditor::create(); + $config + ->getComponentByType(GridFieldDetailForm::class) + ->setItemRequestClass(VersionedGridFieldItemRequest::class); + $gridField = GridField::create('Items', 'Items', $this->Items(), $config); + $fields->addFieldToTab('Root.Items', $gridField); + }); + return parent::getCMSFields(); } } } @@ -1404,13 +1404,15 @@ Then you can add the [HistoryViewerField](api:SilverStripe\VersionedAdmin\Forms\ fields in the same way as any other form field: ```php +use SilverStripe\Forms\FieldList; use SilverStripe\VersionedAdmin\Forms\HistoryViewerField; public function getCMSFields() { - $fields = parent::getCMSFields(); - $fields->addFieldToTab('Root.History', HistoryViewerField::create('MyObjectHistory')); - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab('Root.History', HistoryViewerField::create('MyObjectHistory')); + }); + return parent::getCMSFields(); } ``` diff --git a/en/02_Developer_Guides/00_Model/11_Scaffolding.md b/en/02_Developer_Guides/00_Model/11_Scaffolding.md index a176974c9..88c8a0225 100644 --- a/en/02_Developer_Guides/00_Model/11_Scaffolding.md +++ b/en/02_Developer_Guides/00_Model/11_Scaffolding.md @@ -20,6 +20,7 @@ Note that the [`SiteTree`](api:SilverStripe\CMS\Model\SiteTree) edit form does n ```php namespace App\Model; +use SilverStripe\Forms\FieldList; use SilverStripe\ORM\DataObject; class MyDataObject extends DataObject @@ -32,17 +33,18 @@ class MyDataObject extends DataObject public function getCMSFields() { - // parent::getCMSFields() does all the hard work and creates the fields for Title, IsActive and Content. - $fields = parent::getCMSFields(); - $fields->dataFieldByName('IsActive')->setTitle('Is active?'); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->dataFieldByName('IsActive')->setTitle('Is active?'); + }); - return $fields; + // parent::getCMSFields() does all the hard work and creates the fields for Title, IsActive and Content. + return parent::getCMSFields(); } } ``` > [!TIP] -> It is typically considered a good practice to wrap your modifications in a call to [`beforeUpdateCMSFields()`](api:SilverStripe\ORM\DataObject::beforeUpdateCMSFields()) - the `updateCMSFields()` extension hook is already triggered by `parent::getCMSFields()`, so this is how you ensure any new fields are added before extensions update your fieldlist. +> It is typically considered a good practice to wrap your modifications in a call to [`beforeUpdateCMSFields()`](api:SilverStripe\ORM\DataObject::beforeUpdateCMSFields()) - the `updateCMSFields()` extension hook is triggered by `parent::getCMSFields()`, so this is how you ensure any new fields are added before extensions update your fieldlist. To define the form fields yourself without using scaffolding, use the `mainTabOnly` option in [`DataObject.scaffold_cms_fields_settings`](api:SilverStripe\ORM\DataObject->scaffold_cms_fields_settings). See [scaffolding options](#scaffolding-options) for details. diff --git a/en/02_Developer_Guides/03_Forms/01_Validation.md b/en/02_Developer_Guides/03_Forms/01_Validation.md index f1d997b5e..d60159fce 100644 --- a/en/02_Developer_Guides/03_Forms/01_Validation.md +++ b/en/02_Developer_Guides/03_Forms/01_Validation.md @@ -360,6 +360,7 @@ namespace App\PageType; use Page; use SilverStripe\Forms\CompositeValidator; +use SilverStripe\Forms\FieldList; use SilverStripe\Forms\RequiredFields; use SilverStripe\Forms\TextField; @@ -371,12 +372,13 @@ class MyPage extends Page public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->addFieldToTab( - 'Root.Main', - TextField::create('MyRequiredField')->setCustomValidationMessage('You missed me.') - ); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab( + 'Root.Main', + TextField::create('MyRequiredField')->setCustomValidationMessage('You missed me.') + ); + }); + return parent::getCMSFields(); } public function getCMSCompositeValidator(): CompositeValidator diff --git a/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md b/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md index 7740d397c..428d6cc2d 100644 --- a/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md +++ b/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md @@ -20,6 +20,7 @@ namespace App\PageType; use Page; use SilverStripe\Forms\DateField; +use SilverStripe\Forms\FieldList; class MyPage extends Page { @@ -29,14 +30,13 @@ class MyPage extends Page public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->addFieldToTab( - 'Root.Main', - DateField::create('MyDate', 'Enter a date') - ); - - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab( + 'Root.Main', + DateField::create('MyDate', 'Enter a date') + ); + }); + return parent::getCMSFields(); } } ``` diff --git a/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md b/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md index 0c91aa9e7..9f049da08 100644 --- a/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md +++ b/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md @@ -32,9 +32,12 @@ class MyObject extends DataObject public function getCMSFields() { - return FieldList::create( - HTMLEditorField::create('Content') - ); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + // Note that this field would be scaffolded automatically, + // we're only adding it here for demonstration purposes. + $fields->addFieldToTab('Root.Main', HTMLEditorField::create('Content')); + }); + return parent::getCMSFields(); } } ``` @@ -64,12 +67,22 @@ class MyObject extends DataObject 'OtherContent' => 'HTMLText', ]; + private static array $scaffold_cms_fields_settings = [ + 'ignoreFields' => [ + 'OtherContent', + ], + ]; + public function getCMSFields() { - return FieldList::create([ - HTMLEditorField::create('Content'), - HTMLEditorField::create('OtherContent', 'Other content', $this->OtherContent, 'myConfig'), - ]); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab( + 'Root.Main', + HTMLEditorField::create('OtherContent', 'Other content', $this->OtherContent, 'myConfig'), + 'Content' + ); + }); + return parent::getCMSFields(); } } ``` diff --git a/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md b/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md index 1e79b45c5..093bf7233 100644 --- a/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md +++ b/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md @@ -38,20 +38,23 @@ namespace App\PageType; use Page; use SilverStripe\CMS\Model\SiteTree; +use SilverStripe\Forms\FieldList; use SilverStripe\Forms\GridField\GridField; class MyPage extends Page { + // ... + public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->addFieldToTab( - 'Root.Pages', - GridField::create('Pages', 'All pages', SiteTree::get()) - ); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab( + 'Root.Pages', + GridField::create('Pages', 'All pages', SiteTree::get()) + ); + }); - return $fields; + return parent::getCMSFields(); } } ``` @@ -69,35 +72,38 @@ namespace App\PageType; use Page; use SilverStripe\CMS\Model\SiteTree; +use SilverStripe\Forms\FieldList; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldDataColumns; class MyPage extends Page { + // ... + public function getCMSFields() { - $fields = parent::getCMSFields(); - - $fields->addFieldToTab( - 'Root.Pages', - $grid = GridField::create('Pages', 'All pages', SiteTree::get()) - ); + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab( + 'Root.Pages', + $grid = GridField::create('Pages', 'All pages', SiteTree::get()) + ); - // GridField configuration - $config = $grid->getConfig(); + // GridField configuration + $config = $grid->getConfig(); - // Modification of existing components can be done by fetching that component. - // Consult the API documentation for each component to determine the configuration - // you can do. - $dataColumns = $config->getComponentByType(GridFieldDataColumns::class); + // Modification of existing components can be done by fetching that component. + // Consult the API documentation for each component to determine the configuration + // you can do. + $dataColumns = $config->getComponentByType(GridFieldDataColumns::class); - $dataColumns->setDisplayFields([ - 'Title' => 'Title', - 'Link' => 'URL', - 'LastEdited' => 'Changed', - ]); + $dataColumns->setDisplayFields([ + 'Title' => 'Title', + 'Link' => 'URL', + 'LastEdited' => 'Changed', + ]); + }); - return $fields; + return parent::getCMSFields(); } } ``` @@ -373,6 +379,7 @@ class Team extends DataObject ```php namespace App\Model; +use SilverStripe\Forms\FieldList; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor; use SilverStripe\Forms\GridField\GridFieldDataColumns; @@ -398,31 +405,31 @@ class Player extends DataObject public function getCMSFields() { - $fields = parent::getCMSFields(); - - if ($this->ID) { - $singletonTeam = singleton(Team::class); - $teamEditFields = $singletonTeam->getCMSFields(); - $teamEditFields->addFieldToTab( - 'Root.Main', - // The "ManyMany[]" convention is necessary here, because this will be passed - // into the GridFieldDetailForm - TextField::create('ManyMany[Position]', 'Current Position') - ); - - // For summary fields, the "ManyMany[]" convention won't work (and isn't necessary), - // since this isn't passed into the GridFieldDetailForm - $teamSummaryFields = array_merge($singletonTeam->summaryFields(), ['Position' => 'Current Position']); - - $config = GridFieldConfig_RelationEditor::create(); - $config->getComponentByType(GridFieldDetailForm::class)->setFields($teamEditFields); - $config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($teamSummaryFields); - - $gridField = GridField::create('Teams', 'Teams', $this->Teams(), $config); - $fields->findOrMakeTab('Root.Teams')->replaceField('Teams', $gridField); - } - - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + if ($this->ID) { + $singletonTeam = singleton(Team::class); + $teamEditFields = $singletonTeam->getCMSFields(); + $teamEditFields->addFieldToTab( + 'Root.Main', + // The "ManyMany[]" convention is necessary here, because this will be passed + // into the GridFieldDetailForm + TextField::create('ManyMany[Position]', 'Current Position') + ); + + // For summary fields, the "ManyMany[]" convention won't work (and isn't necessary), + // since this isn't passed into the GridFieldDetailForm + $teamSummaryFields = array_merge($singletonTeam->summaryFields(), ['Position' => 'Current Position']); + + $config = GridFieldConfig_RelationEditor::create(); + $config->getComponentByType(GridFieldDetailForm::class)->setFields($teamEditFields); + $config->getComponentByType(GridFieldDataColumns::class)->setDisplayFields($teamSummaryFields); + + $gridField = GridField::create('Teams', 'Teams', $this->Teams(), $config); + $fields->findOrMakeTab('Root.Teams')->replaceField('Teams', $gridField); + } + }); + + return parent::getCMSFields(); } } ``` diff --git a/en/02_Developer_Guides/05_Extending/01_Extensions.md b/en/02_Developer_Guides/05_Extending/01_Extensions.md index ba54289da..3bd80d6af 100644 --- a/en/02_Developer_Guides/05_Extending/01_Extensions.md +++ b/en/02_Developer_Guides/05_Extending/01_Extensions.md @@ -388,6 +388,7 @@ Example 2: User code can intervene in the process of extending CMS fields. ```php namespace App\Model; +use SilverStripe\Forms\FieldList; use SilverStripe\Forms\TextField; use SilverStripe\ORM\DataObject; @@ -397,7 +398,7 @@ class MyModel extends DataObject public function getCMSFields() { - $this->beforeUpdateCMSFields(function ($fields) { + $this->beforeUpdateCMSFields(function (FieldList $fields) { // Include field which must be present when updateCMSFields is called on extensions $fields->addFieldToTab('Root.Main', TextField::create('Detail', 'Details', null, 255)); }); diff --git a/en/02_Developer_Guides/09_Security/00_Member.md b/en/02_Developer_Guides/09_Security/00_Member.md index e1f4e56da..b609908f3 100644 --- a/en/02_Developer_Guides/09_Security/00_Member.md +++ b/en/02_Developer_Guides/09_Security/00_Member.md @@ -64,11 +64,12 @@ Note that if you want to look this class-name up, you can call `Injector::inst() If you override the built-in public function getCMSFields(), then you can change the form that is used to view & edit member details in the newsletter system. This function returns a [FieldList](api:SilverStripe\Forms\FieldList) object. You should generally start by calling -parent::getCMSFields() and manipulate the [FieldList](api:SilverStripe\Forms\FieldList) from there. +`$this->beforeUpdateCMSFields()` and manipulate the [FieldList](api:SilverStripe\Forms\FieldList) from there. ```php namespace App\Security; +use SilverStripe\Forms\FieldList; use SilverStripe\Forms\TextField; use SilverStripe\Security\Member; @@ -78,11 +79,12 @@ class MyMember extends Member public function getCMSFields() { - $fields = parent::getCMSFields(); - $fields->insertBefore('HTMLEmail', TextField::create('Age')); - $fields->removeByName('JobTitle'); - $fields->removeByName('Organisation'); - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->insertBefore('HTMLEmail', TextField::create('Age')); + $fields->removeByName('JobTitle'); + $fields->removeByName('Organisation'); + }); + return parent::getCMSFields(); } } ``` diff --git a/en/02_Developer_Guides/14_Files/01_File_Management.md b/en/02_Developer_Guides/14_Files/01_File_Management.md index 50dba024d..c29302ff2 100644 --- a/en/02_Developer_Guides/14_Files/01_File_Management.md +++ b/en/02_Developer_Guides/14_Files/01_File_Management.md @@ -31,6 +31,7 @@ namespace App\PageType; use Page; use SilverStripe\AssetAdmin\Forms\UploadField; use SilverStripe\Assets\Image; +use SilverStripe\Forms\FieldList; class LandingPage extends Page { @@ -40,9 +41,10 @@ class LandingPage extends Page public function getCMSFields() { - $fields = parent::getCMSFields(); - $fields->addFieldToTab('Root.Main', UploadField::create('Banner', 'Page Banner'), 'Content'); - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $fields->addFieldToTab('Root.Main', UploadField::create('Banner', 'Page Banner'), 'Content'); + }); + return parent::getCMSFields(); } } ``` diff --git a/en/02_Developer_Guides/14_Files/02_Images.md b/en/02_Developer_Guides/14_Files/02_Images.md index b846fa33b..e14f1e495 100644 --- a/en/02_Developer_Guides/14_Files/02_Images.md +++ b/en/02_Developer_Guides/14_Files/02_Images.md @@ -307,6 +307,7 @@ use Page; use SilverStripe\AssetAdmin\Forms\UploadField; use SilverStripe\Assets\Image; use SilverStripe\Forms\DropdownField; +use SilverStripe\Forms\FieldList; class HomePage extends Page { @@ -324,22 +325,22 @@ class HomePage extends Page public function getCMSFields() { - $fields = parent::getCMSFields(); - - $loadingSource = [ - true => 'Lazy (Default)', - false => 'Eager', - ]; - - $fields->addFieldsToTab( - 'Root.Main', - [ - UploadField::create('Logo'), - DropdownField::create('LogoLoading', 'Loading', $loadingSource), - ] - ); - - return $fields; + $this->beforeUpdateCMSFields(function (FieldList $fields) { + $loadingSource = [ + true => 'Lazy (Default)', + false => 'Eager', + ]; + + $fields->addFieldsToTab( + 'Root.Main', + [ + UploadField::create('Logo'), + DropdownField::create('LogoLoading', 'Loading', $loadingSource), + ] + ); + }); + + return parent::getCMSFields(); } } ``` diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md index 0e69b4a5f..9704e2a32 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md @@ -95,22 +95,37 @@ and insert the following code. ```php namespace App\Extension; -use SilverStripe\Forms\CheckboxField; -use SilverStripe\Forms\FieldList; use SilverStripe\ORM\DataExtension; class BookmarkedPageExtension extends DataExtension { - private static $db = [ + private static array $db = [ 'IsBookmarked' => 'Boolean', ]; + private static array $field_labels = [ + 'IsBookmarked' => 'Show in CMS bookmarks?', + ]; +} +``` + +By default, form fields in extension classes are automatically scaffolded in CMS edit forms. See [scaffolding](/developer_guides/model/scaffolding/) for more details about how that works. + +If you need to update those form fields, you can implement the `updateCMSFields()` extension hook method. + +```php +namespace App\Extension; + +use SilverStripe\Forms\FieldList; +use SilverStripe\ORM\DataExtension; + +class BookmarkedPageExtension extends DataExtension +{ + // ... + protected function updateCMSFields(FieldList $fields) { - $fields->addFieldToTab( - 'Root.Main', - new CheckboxField('IsBookmarked', 'Show in CMS bookmarks?') - ); + $fields->dataFieldByName('IsBookmarked')?->addExtraClass('special-css-class'); } } ``` diff --git a/en/08_Changelogs/6.0.0.md b/en/08_Changelogs/6.0.0.md index 2b71bbba6..e41460507 100644 --- a/en/08_Changelogs/6.0.0.md +++ b/en/08_Changelogs/6.0.0.md @@ -10,6 +10,7 @@ title: 6.0.0 (unreleased) - [Run `CanonicalURLMiddleware` in all environments by default](#url-middleware) - [Changes to default cache adapters](#caching) - [Changes to scaffolded form fields](#scaffolded-fields) + - [`SiteTree` uses form field scaffolding](#sitetree-scaffolding) - [Other new features](#other-new-features) - [Dependency changes](#dependency-changes) - [`intervention/image` has been upgraded from v2 to v3](#intervention-image) @@ -70,6 +71,110 @@ All other models used `SearchableDropdownField` for `has_one` relations and `Gri |[`Link`](api:SilverStripe\LinkField\Models\Link)|[`LinkField`](api:SilverStripe\LinkField\Form\LinkField)|[`MultiLinkField`](api:SilverStripe\LinkField\Form\MultiLinkField)|No change| |[`BlogCategory`](api:SilverStripe\Blog\Model\BlogCategory)|No change|[`TagField`](api:SilverStripe\TagField\TagField)|[`TagField`](api:SilverStripe\TagField\TagField)| |[`BlogTag`](api:SilverStripe\Blog\Model\BlogTag)|No change|[`TagField`](api:SilverStripe\TagField\TagField)|[`TagField`](api:SilverStripe\TagField\TagField)| +|[`Recipient`](api:SilverStripe\UserForms\Model\Recipient)|No change|Changed which `GridfieldComponent` classes are used|Changed which `GridfieldComponent` classes are used| + +### `SiteTree` uses form field scaffolding {#sitetree-scaffolding} + +[`SiteTree::getCMSFields()`](api:SilverStripe\CMS\Model\SiteTree::getCMSFields()) used to create its form fields from scratch, without calling `parent::getCMSFields()`. This meant that all subclasses of `SiteTree` (i.e. all of your `Page` classes) had to explicitly define all form fields. + +`SiteTree::getCMSFields()` now uses same form field scaffolding that all other `DataObject` subclasses use. + +Note that this means when you initially upgrade to Silverstripe CMS 6 you may have form fields being added to your CMS edit forms that you don't want to include, or tabs from relations that you don't want. You can use the [`scaffold_cms_fields_settings`](api:SilverStripe\ORM\DataObject->scaffold_cms_fields_settings) configuration property to change which fields are being scaffolded. + +For example, if you have a database column for which you don't want content authors to see or edit the value, you can use the `ignoreFields` option to stop the form field for that column from being scaffolded: + +```php +namespace App\PageTypes; + +use Page; + +class MyCustomPage extends Page +{ + // ... + private static array $db = [ + 'SecretToken' => 'Varchar', + ]; + + private static array $scaffold_cms_fields_settings = [ + 'ignoreFields' => [ + 'SecretToken', + ], + ]; +} +``` + +See the [scaffolding](/developer_guides/model/scaffolding/#scaffolding-options) section for more details about using these options. + +As part of your CMS 6 upgrade, you should check all of the page types in your project and in any modules you maintain to ensure the correct form fields are available in the appropriate tabs. You should also check [`Extension`](api:SilverStripe\Core\Extension) subclasses that you know get applied to pages to ensure fields aren't being scaffolded from those that you want to keep hidden. + +#### What if I don't have time to upgrade all of my page types? + +If you have a lot of complex page types and extensions, upgrading all of them to account for the new scaffolding might be a large task. If you want to avoid upgrading your `getCMSFields()` and `updateCMSFields()` implementations initially, you can use the `restrictRelations` and `restrictFields` scaffolding options in the `scaffold_cms_fields_settings` configuration property for your pages. You can then declare that only the fields introduced in parent classes should be scaffolded. + +The following configuration can be used as a base for this workaround. It will work for all page types available in commercially supported modules. If you use page types provided in third-party modules, you may need to add configuration for those as well. + +> [!WARNING] +> Note that this is explicitly intended as a temporary workaround, so that you can focus on other areas of the upgrade first, and come back to your page form fields later. +> +> As more community modules are upgraded to account for form field scaffolding in their page types and extension classes, you may +> need to add more fields to this list. To avoid having to continuously update these lists it's recommended that you take the time +> to update your `getCMSFields()` and `updateCMSFields()` implementations as soon as you have time to do so. + +```yml +SilverStripe\CMS\Model\SiteTree: + scaffold_cms_fields_settings: + restrictRelations: + # This will stop all has_many and many_many relations from being + # scaffolded except for new relations which are added to this list + - 'ThisRelationDoesntExist' + restrictFields: + # These fields are scaffolded from SiteTree, and are the bare minimum + # fields that we need to be scaffolded for all page types + - 'Title' + - 'MenuTitle' + - 'URLSegment' + - 'Content' + +SilverStripe\CMS\Model\VirtualPage: + scaffold_cms_fields_settings: + restrictFields: + - 'CopyContentFrom' + +SilverStripe\CMS\Model\RedirectorPage: + scaffold_cms_fields_settings: + restrictFields: + - 'ExternalURL' + - 'LinkTo' + - 'LinkToFile' + +SilverStripe\Blog\Model\BlogPost: + scaffold_cms_fields_settings: + restrictRelations: + - 'Categories' + - 'Tags' + restrictFields: + - 'Summary' + - 'FeaturedImage' + - 'PublishDate' + +SilverStripe\IFrame\IFramePage: + scaffold_cms_fields_settings: + restrictFields: + - 'ForceProtocol' + - 'IFrameURL' + - 'IFrameTitle' + - 'AutoHeight' + - 'AutoWidth' + - 'FixedHeight' + - 'FixedWidth' + - 'BottomContent' + - 'AlternateContent' + +SilverStripe\UserForms\Model\UserDefinedForm: + scaffold_cms_fields_settings: + restrictRelations: + - 'EmailRecipients' +``` ### Other new features