fromholdio / silverstripe-cms-fields-scaffolder
Installs: 329
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:silverstripe-vendormodule
pkg:composer/fromholdio/silverstripe-cms-fields-scaffolder
Requires
- silverstripe/framework: ^4.1 || ^5.0 || ^6.0
README
A SilverStripe module for scaffolding CMS field tab structures and placement via YAML configuration. This module simplifies the process of organizing CMS fields into custom tab structures across different contexts (CMS edit forms, Settings forms, custom forms).
Features
- Section-based configuration: Define different tab structures for different contexts (cms, settings, or custom sections)
- Declarative tab structure: Define your entire tab hierarchy in YAML
- Automatic tab creation: TabSets and Tabs are created automatically based on configuration
- Field label integration: Tab titles automatically use your DataObject's
field_labels
configuration - Content field relocation: Move the default Content field to a custom tab location
- Root.Main tab relocation: Move fields from the default Root.Main tab to a custom location
- Empty tab cleanup: Automatically remove empty tabs and tabsets
- Field removal: Remove unwanted fields by name
Installation
composer require fromholdio/silverstripe-cms-fields-scaffolder
Requirements
- SilverStripe ^4.1 || ^5.0 || ^6.0
Usage
Basic Setup
- Apply the extension to your DataObject:
Page: extensions: - Fromholdio\CMSFieldsScaffolder\CMSFieldsScaffolder
- Configure your tab structure:
Page: scaffolder: cms: tabs: MainTabSet: - MainTab - DetailsTab ContentTabSet: - ContentMainTab - ContentBlocksTab field_labels: MainTabSet: Main MainTab: Main DetailsTab: Details ContentTabSet: Content ContentMainTab: Main ContentBlocksTab: Blocks
- Integrate into your getCMSFields() method:
public function getCMSFields() { $this->beforeUpdateCMSFields(function (FieldList $fields) { return $this->runCMSFieldsScaffolderBeforeUpdate($fields); }); $this->afterUpdateCMSFields(function (FieldList $fields) { return $this->runCMSFieldsScaffolderAfterUpdate($fields, 'cms', false); }); $fields = parent::getCMSFields(); // Your custom field additions here $fields = $this->clearCMSFieldsScaffolderEmptyTabs($fields, 'cms'); $fields = $this->removeCMSFieldsScaffolderFields($fields, 'cms'); return $fields; }
Section Keys
The module supports section-based configuration, allowing you to define different tab structures for different contexts. Common section keys include:
cms
- For the main CMS edit form (getCMSFields)settings
- For the Settings tab (getSettingsFields)- Custom keys - For any other form context you define
Each section can have its own independent configuration.
Configuration Options
Each section supports the following configuration options:
tabs
Defines the tab structure. Can be a simple array of tab names, or a nested structure for TabSets:
Page: scaffolder: cms: tabs: # Simple TabSet with child Tabs MainTabSet: - MainTab - DetailsTab # Another TabSet ContentTabSet: - ContentMainTab
do_clear_empty_tabs
Boolean. When true
, automatically removes empty tabs and tabsets after all fields have been added. Default: true
Page: scaffolder: cms: do_clear_empty_tabs: true
content_field_tab_path
Specifies where to move the default Content
field. Set to false
to remove it entirely, or provide a tab path:
Page: scaffolder: cms: content_field_tab_path: 'Root.ContentTabSet.ContentMainTab' # Or to remove it: # content_field_tab_path: false
root_main_tab_path
Specifies where to move fields from the default Root.Main
tab:
Page: scaffolder: cms: root_main_tab_path: 'Root.MainTabSet.MainTab'
fields_to_remove
Array of field names to remove from the form:
Page: scaffolder: cms: fields_to_remove: - UnwantedField - AnotherField
Complete Example
Here's a complete example showing multiple sections:
Page: extensions: - Fromholdio\CMSFieldsScaffolder\CMSFieldsScaffolder scaffolder: cms: do_clear_empty_tabs: true content_field_tab_path: 'Root.ContentTabSet.ContentMainTab' root_main_tab_path: 'Root.MainTabSet.MainTab' tabs: MainTabSet: - MainTab - DetailsTab ContentTabSet: - ContentMainTab - ContentBlocksTab SEOTabSet: - SEOMainTab settings: do_clear_empty_tabs: true root_main_tab_path: 'Root.MainTabSet.MainTab' tabs: MainTabSet: - MainTab AccessTabSet: - AccessMainTab field_labels: MainTabSet: Main MainTab: Main DetailsTab: Details ContentTabSet: Content ContentMainTab: Main ContentBlocksTab: Blocks SEOTabSet: SEO SEOMainTab: SEO AccessTabSet: Access AccessMainTab: Main
Integration Patterns
For getCMSFields()
public function getCMSFields() { $this->beforeUpdateCMSFields(function (FieldList $fields) { return $this->runCMSFieldsScaffolderBeforeUpdate($fields); // Or with explicit section: $this->runCMSFieldsScaffolderBeforeUpdate($fields, 'cms'); }); $this->afterUpdateCMSFields(function (FieldList $fields) { return $this->runCMSFieldsScaffolderAfterUpdate($fields, 'cms', false); }); $fields = parent::getCMSFields(); // Add your custom fields here $fields = $this->clearCMSFieldsScaffolderEmptyTabs($fields, 'cms'); $fields = $this->removeCMSFieldsScaffolderFields($fields, 'cms'); return $fields; }
For getSettingsFields()
public function getSettingsFields() { $this->beforeExtending('updateSettingsFields', function (FieldList $fields) { return $this->runCMSFieldsScaffolderBeforeUpdate($fields, 'settings'); }); $this->afterExtending('updateSettingsFields', function (FieldList $fields) { return $this->runCMSFieldsScaffolderAfterUpdate($fields, 'settings', false); }); $fields = parent::getSettingsFields(); // Add your custom fields here $fields = $this->clearCMSFieldsScaffolderEmptyTabs($fields, 'settings'); $fields = $this->removeCMSFieldsScaffolderFields($fields, 'settings'); return $fields; }
API Methods
runCMSFieldsScaffolderBeforeUpdate(FieldList $fields, string $key = 'cms'): FieldList
Runs before extensions update fields. Creates tabs and relocates the Content field.
runCMSFieldsScaffolderAfterUpdate(FieldList $fields, string $key = 'cms', bool $doClearTabs = true): FieldList
Runs after extensions update fields. Relocates Root.Main tab fields and optionally clears empty tabs.
clearCMSFieldsScaffolderEmptyTabs(FieldList $fields, string $key = 'cms'): FieldList
Removes empty tabs and tabsets based on the section's do_clear_empty_tabs
setting.
removeCMSFieldsScaffolderFields(FieldList $fields, string $key = 'cms'): FieldList
Removes fields specified in the section's fields_to_remove
configuration.
getCMSFieldsScaffolderSetting(string $name, string $key = 'cms')
Retrieves a specific configuration setting for a section.
applyCMSFieldsScaffolderTabs(FieldList $fields, string $key = 'cms'): FieldList
Creates the tab structure defined in the section's tabs
configuration.
applyCMSFieldsScaffolderContentFieldTabPath(FieldList $fields, string $key = 'cms'): FieldList
Relocates or removes the Content field based on the section's content_field_tab_path
configuration.
applyCMSFieldsScaffolderRootMainTabPath(FieldList $fields, string $key = 'cms'): FieldList
Relocates fields from Root.Main (or Root.Settings) to the path specified in root_main_tab_path
.
Version History & Breaking Changes
Version 2.x (Current - With Section Keys)
The current version uses section-based configuration where each context (cms, settings, etc.) has its own configuration block.
Configuration structure:
Page: scaffolder: cms: # Section key tabs: ... do_clear_empty_tabs: true settings: # Another section key tabs: ...
Method signatures:
runCMSFieldsScaffolderBeforeUpdate(FieldList $fields, string $key = 'cms'): FieldList runCMSFieldsScaffolderAfterUpdate(FieldList $fields, string $key = 'cms', bool $doClearTabs = true): FieldList clearCMSFieldsScaffolderEmptyTabs(FieldList $fields, string $key = 'cms'): FieldList removeCMSFieldsScaffolderFields(FieldList $fields, string $key = 'cms'): FieldList getCMSFieldsScaffolderSetting(string $name, string $key = 'cms')
Default section configurations:
private static $scaffolder = [ 'cms' => [ 'tabs' => null, 'do_clear_empty_tabs' => true, 'content_field_tab_path' => 'Root.ContentTabSet.ContentMainTab', 'root_main_tab_path' => 'Root.MainTabSet.MainTab', 'fields_to_remove' => null, ], 'settings' => [ 'tabs' => null, 'do_clear_empty_tabs' => true, 'content_field_tab_path' => 'Root.ContentTabSet.ContentMainTab', 'root_main_tab_path' => 'Root.MainTabSet.MainTab', 'fields_to_remove' => null, ], ];
Version 1.x (Legacy - Without Section Keys)
The legacy version used a flat configuration structure without section keys.
Configuration structure:
Page: scaffolder: tabs: ... # Direct configuration, no section key do_clear_empty_tabs: true
Method signatures:
runCMSFieldsScaffolderBeforeUpdate(FieldList $fields): FieldList runCMSFieldsScaffolderAfterUpdate(FieldList $fields): FieldList clearCMSFieldsScaffolderEmptyTabs(FieldList $fields): FieldList removeCMSFieldsScaffolderFields(FieldList $fields): FieldList getCMSFieldsScaffolderSetting(string $key)
Default configuration:
private static $scaffolder = [ 'tabs' => null, 'do_clear_empty_tabs' => true, 'content_field_tab_path' => 'Root.ContentTabSet.ContentMainTab', 'root_main_tab_path' => 'Root.MainTabSet.MainTab', 'fields_to_remove' => null ];
Migrating from 1.x to 2.x
If you're upgrading from version 1.x, you'll need to:
- Update your YAML configuration to nest settings under section keys:
# Old (1.x) Page: scaffolder: tabs: MainTabSet: - MainTab # New (2.x) Page: scaffolder: cms: # Add section key tabs: MainTabSet: - MainTab
- Update method calls to include the section parameter:
// Old (1.x) $this->runCMSFieldsScaffolderBeforeUpdate($fields); $this->runCMSFieldsScaffolderAfterUpdate($fields); $this->clearCMSFieldsScaffolderEmptyTabs($fields); // New (2.x) $this->runCMSFieldsScaffolderBeforeUpdate($fields, 'cms'); $this->runCMSFieldsScaffolderAfterUpdate($fields, 'cms', false); $this->clearCMSFieldsScaffolderEmptyTabs($fields, 'cms');
Note: The section parameter defaults to 'cms'
, so you can omit it for CMS forms if desired.
License
BSD-3-Clause
Maintainer
Luke Fromhold - https://fromhold.io