Version 4 supported
This version of Silverstripe CMS is still supported though will not receive any additional features. Go to documentation for the most recent stable version.



  • DataList::column() now returns all values and not just "distinct" values from a column as per the API docs
  • DataList, ArrayList and UnsavedRalationList all have columnUnique() method for fetching distinct column values
  • Take care with stageChildren() overrides. Hierarchy::numChildren() results will only make use of stageChildren() customisations that are applied to the base class and don't include record-specific behaviour.
  • New React-based search UI for the CMS, Asset-Admin, GridFields and ModelAdmins.
  • A new GridFieldLazyLoader component can be added to GridField. This will delay the fetching of data until the user access the container Tab of the GridField.
  • SilverStripe\VersionedAdmin\Controllers\CMSPageHistoryViewerController is now the default CMS history controller and SilverStripe\CMS\Controllers\CMSPageHistoryController has been deprecated.
  • PHPUnit tests no longer auto-flush, requiring manual flush parameters when changing YAML config or certain PHP code


Fetching distinct column values on DataList

Prior to this release DataList would erroneously return a distinct list of values from a column on an object. If this behaviour is still required, please use columnUnique() instead.

Using legacy GridField search API

GridFields now default to using the new search UI which uses Silverstripe's FormSchema API.

If you would rather continue using the old search API, you can remove the default GridFieldFilterHeader from your GridField configuration and replace with one whose legacy flag has been enabled.

To enable the legacy search API on a GridFieldFilterHeader, you can either:

  • set the useLegacyFilterHeader property to true,
  • or pass true to the first argument of its constructor.

To force the legacy search API on all instances of GridFieldFilterHeader, you can set it in your configuration file:

  force_legacy: true
namespace App\Model;

use SilverStripe\ORM\DataObject;

class MyObject extends DataObject
    // ...

    public function getCMSFields()
        $fields = parent::getCMSFields();

        // Configure grid field to use legacy search API
        $config = new GridFieldConfig_RecordEditor();
        $config->getComponentsByType(GridFieldFilterHeader::class)->useLegacyFilterHeader = true;

        $grid = GridField::create('Companies', 'Companies', DataList::create(Company::class), $config);
        $fields->addFieldToTab('Root.Company', $grid);

        return $fields;

Keep using the legacy CMSPageHistoryController

To keep using the old CMS history controller for every page type, add the following entry to your YAML config.

    class: SilverStripe\CMS\Controllers\CMSPageHistoryController

If you want to use both CMS history controllers in different contexts, you can implement your own Factory class.


Implementing a Factory with the Injector

PHPUnit tests no longer auto-flush

Silverstripe caches certain metadata in manifests, for example YAML configuration and certain PHP class structures (e.g. ClassInfo::implementorsOf()). This is also the case for CLI executions such as PHPUnit.

Starting with Silverstripe 4.0, PHPUnit executions flushed the cache automatically. While this meant less work for developers in manually flushing caches, it significantly increased the time to run each test (from sub-second to multi-second). In order to allow for efficient test execution and Test Driven Development (TDD), we have decided to treat this as a performance regression.

In order to flush manifests on test execution, please use the following command (note the empty quoted string):

vendor/bin/phpunit vendor/silverstripe/framework/tests '' flush=1

See our testing guide for more details.

Change log


API changes

  • 2018-10-05 5276b6cbb Add FieldList::getContainerField (Maxime Rainville)
  • 2018-10-04 dba237e Allow Gridfield to be lazy loadable. (Maxime Rainville)
  • 2018-10-04 bdb53979a Create a new GridFieldLazyLoader GridField component (Maxime Rainville)
  • 2018-09-28 cb2b9498f Deprecate updateSearchContextCallback and updateSearchFormCallback (Robbie Averill)
  • 2018-09-03 f48ab77 Add show_file_link_tracking config to FileLinkTracking extension to control visibility of the File Tracking tab (bergice)
  • 2018-08-31 01db5c9e9 Add Link Tracking section to Relations developer guide and describe show_sitetree_link_tracking, show_file_link_tracking. (bergice)
  • 2018-08-31 115ed92e Add show_sitetree_link_tracking config to SiteTreeLinkTracking extension to control visibility of the Link Tracking tab (bergice)
  • 2018-08-05 02be4cc Multi-schema support (#169) (Aaron Carlino)
  • 2018-07-12 0343203 Add new RestoreAction and canRestoreToDraft method (#168) (Luke Edwards)

Features and enhancements

  • 2018-11-01 2f2fb2b Improve loading screen and indicator (#582) (Luke Edwards)
  • 2018-10-29 e51be58 Move Remove button into preview-image message (#859) (Sacha Judd)
  • 2018-10-29 2440432 Move the replace file into the more options action set (#848) (Sacha Judd)
  • 2018-10-29 952f37a Adding an HOC to provide DragDropContext for consumers of ReactDND (#711) (Guy Marriott)
  • 2018-10-26 2c3665d Adding a component for a generic popover filled with buttons (#684) (Guy Marriott)
  • 2018-10-19 e88b8e7 Expose TabsActions (#703) (Raissa North)
  • 2018-10-18 761a6f7 Reverse argument signature of methods using path (#698) (Aaron Carlino)
  • 2018-10-17 902fec0 Extensible readFiles query (#847) (Aaron Carlino)
  • 2018-10-17 437e53f2f Some minor refactoring of the PDO and MySQLi connectors (Robbie Averill)
  • 2018-10-15 3e2ce31 Add nested fields, args, distribute args to fields (#683) (Aaron Carlino)
  • 2018-10-08 2775895d0 Adding a helper to find a form field by label content (Guy Marriott)
  • 2018-10-05 6e66c48 Add CMS community help menu to cms-menu (#615) (Sacha Judd)
  • 2018-10-04 9ea7b58a8 Add memory cache to ThemeResourceLoader::findTemplate() (Robbie Averill)
  • 2018-10-03 90afb2037 TabSet react component is no longer structural (Raissa North)
  • 2018-10-03 0be4a9a Adding an extension point to FormBuilderLoader after redux form is initialised (Raissa North)
  • 2018-10-02 cba5d30 Connect Tabs component to redux-form to handle activeTab state (Raissa North)
  • 2018-10-02 e1f2f89d3 Add test for PHP 7.3 support (SS4 version) (Sam Minnee)
  • 2018-09-28 bd37b90a Add CMSMain.enable_archive_warning_message config (Sam Minnee)
  • 2018-09-27 4b155b9 Add getSortableFields to return sortable fields for query (#185) (Robbie Averill)
  • 2018-09-27 25759ffc5 Show file path on PHP parser exceptions (Ingo Schommer)
  • 2018-09-25 5b7a84141 Add Hierarchy::prepopulate_numchildren_cache() (#8380) (Sam Minnée)
  • 2018-09-21 e2701a4 TinyMCE inline toolbar for images and embeds (Luke Edwards)
  • 2018-09-20 c928e83 Backport of DataList for list of versions, for SS 4.3.x (Robbie Averill)
  • 2018-09-19 d9a6c10 Form state & schema persists across form remounting (Guy Marriott)
  • 2018-09-19 40dde226f Add ?showqueries=backtrace (Sam Minnee)
  • 2018-09-19 6de12e1 TinyMCE inline toolbar for images and embeds (Luke Edwards)
  • 2018-09-17 588bf83e1 Add hideNav flag to schema defaults (Raissa North)
  • 2018-09-17 a800ce7 Add hideNav flag to allow hiding of navigation in Tabs (Raissa North)
  • 2018-09-12 d8bf873 Use bootstrap modal footer, use our icon font for close icon (Luke Edwards)
  • 2018-09-12 c03c685 Use bootstrap modal footer, use our icon font for close icon (Luke Edwards)
  • 2018-09-03 2394194 HtmlEditorField component for react rich text (Dylan Wagstaff)
  • 2018-08-22 a257c1c Add toggleCallback function (Raissa North)
  • 2018-08-22 8153d12 Add dropdownToggleClassName prop to ActionMenu (Raissa North)
  • 2018-08-20 26262ea Insert link shortcut for HTMLEditorField (#599) (Luke Edwards)
  • 2018-08-12 8d3b022 Support setting quality on a per-image basis (#153) (Loz Calver)
  • 2018-08-05 9d0ae97 ViewModeToggle states are now stored in constants (Robbie Averill)
  • 2018-08-01 4213eeb Use the new general purpose search component. (#812) (Maxime Rainville)
  • 2018-08-01 5a00d84 General purpose search form component (#572) (Maxime Rainville)
  • 2018-07-30 163ca65 DataObjectScaffolder instantiation is now handled through Injector (Robbie Averill)
  • 2018-07-30 24d3023 Allow non-internal input types passed as args (#168) (Aaron Carlino)
  • 2018-07-25 79a5ea3 Add versioned-admin (Luke Edwards)
  • 2018-07-17 337da78 Update webpack-config constraint (Raissa North)
  • 2018-07-16 786446fb Use Injector to create new class instances and pass $params (Robbie Averill)
  • 2018-07-12 f2ebdb7f add SiteTree::updateAnchorsOnPage() for user defining additional page anchors (Will Rossiter)
  • 2018-07-12 114b0a5ea Option for secure "remember me" cookie (Ingo Schommer)
  • 2018-07-12 3292a8b77 Add columnUnique API SS_List classes. (Al Twohill)
  • 2018-07-06 6c1a34c Make use of ViewModeToggle component. (Raissa North)
  • 2018-04-15 5108734 Add ViewModeToggle component (Raissa North)
  • 2018-01-30 1857f00 Add tests for Form component (Robbie Averill)
  • 2018-01-30 cc945f0 Add tests for CompositeField (Robbie Averill)


  • 2018-12-10 11970d5 Ensure httpMethod context is applied to all controller actions (#194) (Aaron Carlino)
  • 2018-12-04 a0bb79b Ensure the container exists before unmounting React/removing it (Guy Marriott)
  • 2018-12-02 c28f5ad4 CMSPageHistoryControllerTest now uses a stub controller to avoid URL conflicts with versioned-admin (Robbie Averill)
  • 2018-11-30 7567488 Fix new page form clearing when selecting a Under another page option (bergice)
  • 2018-11-19 1946aca Correct the entwine match for the loading animation (Maxime Rainville)
  • 2018-11-13 fa14ecd Ensure that the PasswordValidator is registered with Injector (Robbie Averill)
  • 2018-11-08 2f896b1 Move password complexity requirements into framework (Robbie Averill)
  • 2018-11-05 7fd4a4e Fix duplicate plugins on HTML editor fields (#721) (Luke Edwards)
  • 2018-11-05 4a65d59 Fix form changes triggered, GridField add existing (#743) (Luke Edwards)
  • 2018-11-02 97180c261 Fix readonly grid state always being truthy (#8562) (Luke Edwards)
  • 2018-11-02 12e2cc3 Fix duplicate plugins on HTML editor fields (#861) (Luke Edwards)
  • 2018-11-02 d9b1721a Fix duplicate plugins on HTML editor fields (#2307) (Luke Edwards)
  • 2018-11-01 8866e7674 Fix duplicate plugins on HTML editor fields (#8559) (Luke Edwards)
  • 2018-11-01 55f95b7bc many many through not sorting by join table (#8534) (Michael Strong)
  • 2018-10-31 af7086a Remove outdated CSS Safari hack interfering with the search panel and submit button (Serge Latyntcev)
  • 2018-10-31 2ef7bd29 IE11+Edge17 Pages tree List View button (Serge Latyntcev)
  • 2018-10-30 3f4d5ae0 Bypass cached versions to prevent stale state (Aaron Carlino)
  • 2018-10-30 4b0e69a Add aria-expanded to help menu toggle for screenreader accessibility (Sacha Judd)
  • 2018-10-30 2900ac6 Remove text-align start with IE supported left (Raissa North)
  • 2018-10-29 f2467d3 Fix search filtering and clearing (#687) (Luke Edwards)
  • 2018-10-26 3284bf48d Fix search filtering relations and clear filters (#8477) (Luke Edwards)
  • 2018-10-22 df86335 Fix decimal search filter not showing up (bergice)
  • 2018-10-20 7f6f5c9ec Flush extra methods cache on DataObjects after each unit test class has finished (Robbie Averill)
  • 2018-10-19 311fd62d9 getExtensionInstance can return null, add a case to handle that (Robbie Averill)
  • 2018-10-19 a6855ec Remove deprecated help_link definition in testGetHelpLinks (Robbie Averill)
  • 2018-10-19 a28e2e183 Fix enum filter in Search component from adding Any as a filter (bergice)
  • 2018-10-18 e3d0bcb Change one tab not all tabs (Raissa North)
  • 2018-10-17 87a5d07 Fix body overflow causing scroll bars (Loz Calver)
  • 2018-10-16 a3d611f Fix ENTER not triggering form save button (bergice)
  • 2018-10-16 c35e18110 Gridfield pagination detected as form change (Luke Edwards)
  • 2018-10-16 5d626fa Don’t track gridstate changes as form edits (Luke Edwards)
  • 2018-10-16 3d3c407 Fix long gridfield actions overflowing (Luke Edwards)
  • 2018-10-15 ab259af Move phpcs to composer dependency, update Travis for it, add 7.2 to Travis (Robbie Averill)
  • 2018-10-15 ab0d7d9 Fix codesniffer runs in Travis (Robbie Averill)
  • 2018-10-11 0aa2d66 Use correct lazy loadable class names for GridFieldLazyLoader (Robbie Averill)
  • 2018-10-11 ee21c4201 Re-instate missing SS_DATABASE_SUFFIX functionality (fixes #7966) (Loz Calver)
  • 2018-10-11 4702a22 Defensively programming some possible failure points (Guy Marriott)
  • 2018-10-11 0db2f84ad Persist TinyMCE updates when writing with Behat (Guy Marriott)
  • 2018-10-10 e941a56 Changing the value of a TinyMCE field will correctly trigger a change in the React component (Guy Marriott)
  • 2018-10-09 56d562193 Flush extra_methods statics between test runs (Robbie Averill)
  • 2018-10-09 d1281a571 Escape HTML in PHPDoc to fix API docs from rendering incorrectly (Robbie Averill)
  • 2018-10-09 522b288 ModelAdmin pagination with a filter (Luke Edwards)
  • 2018-10-08 4766cae Retain polyfill for display block style in with Bootstrap 4.1.x (Robbie Averill)
  • 2018-10-08 6e649b57 CMSMain::duplicate() now checks canCreate() but not canEdit() (Robbie Averill)
  • 2018-10-08 c4788803e Remove unused cacheData prop from #8451 (Robbie Averill)
  • 2018-10-08 884a12c Add fix for potential tabnabbing on community help links (Sacha Judd)
  • 2018-10-08 979dd38 Fix migrating files with an incorrect class (Luke Edwards)
  • 2018-10-08 fdb53311b Fix linting issue. (Maxime Rainville)
  • 2018-10-08 e06bb05 Ensure TinyMCE field changes are persisted before updating redux state (Guy Marriott)
  • 2018-10-06 8c7459a70 Fix CompositeField test that relied on a DropdownField bug (Sam Minnee)
  • 2018-10-05 e5d3b28a4 Don’t break validation on selects without a source. (Sam Minnee)
  • 2018-10-05 98568262f Fixed phpcs violations (Robbie Averill)
  • 2018-10-04 fafd9dad6 fixing name of constant ASSETS_PATH (Philipp Staender)
  • 2018-10-04 0fc06e51e Drop seconds from DBDatetime::Nice() to restore SS3 behaviour. (Sam Minnee)
  • 2018-10-03 19af1ac Add codesniffer as a dev dependency and use it in Travis (Robbie Averill)
  • 2018-10-03 4668fab Shortcode provider does not always request a protected asset grant, add tests for FlysystemAssetStore (Robbie Averill)
  • 2018-10-03 ce9496d Quote injector alias references, deprecated and removed support for in Symfony 4 (Robbie Averill)
  • 2018-10-03 d535e71 Quote injector alias references, deprecated and removed support for in Symfony 4 (Robbie Averill)
  • 2018-10-03 4740346ed Make ArrayList::limit() consistent with DataList::limit() (Sam Minnee)
  • 2018-10-03 0cc72c91a Use DELETE FROM instead of TRUNCATE for clearTable (Sam Minnee)
  • 2018-10-02 5970fc241 Moving test to correct director (Guy Marriott)
  • 2018-10-02 79c2b5ad4 Use DELETE FROM instead of TRUNCATE for clearTable (Sam Minnee)
  • 2018-10-01 f2cbc1dfb Don’t use USE_FRM in MySQL repair. Fixes #6300. (Sam Minnee)
  • 2018-10-01 638e6ec28 Throw deprecation notice on limit=0 (Sam Minnee)
  • 2018-10-01 ad87890b2 Don’t change state in ArrayList::getIterator() (Sam Minnee)
  • 2018-10-01 63cabc7 Keep folder Name and Title in sync on update (Luke Edwards)
  • 2018-10-01 5c7b0da Searching now allows + symbols, use own method over jQuery serialisation (Robbie Averill)
  • 2018-10-01 71dad5f68 Append any fields that don’t match name in insertBefore/insertAfter (Sam Minnee)
  • 2018-10-01 b0c4c5a1 Updating SiteTree search fields to work with new search namespacing (Guy Marriott)
  • 2018-10-01 81292c5 Fix outdated data in Apollo GraphQL cache when deleting/moving files (bergice)
  • 2018-09-28 ac1fe5e9d joinClass's default_sort is used when nothing else has been set already (Robbie Averill)
  • 2018-09-27 fa4e031 Update field names in Behat tests for new namespaces (Robbie Averill)
  • 2018-09-27 44b92c90 Update field names in Behat tests for new search form namespacing (Robbie Averill)
  • 2018-09-27 c54e7317d Avoid having search fields with the same names as form elements (Guy Marriott)
  • 2018-09-27 2e41ea8 Avoid having search fields with the same name as form elements (Guy Marriott)
  • 2018-09-25 dc59bd8 Published GraphQL field now correctly indicates whether the record's version is published (Robbie Averill)
  • 2018-09-25 05b372c Use Hierarchy::prepopulateTreeDataCache() in CMS. (#183) (Sam Minnée)
  • 2018-09-25 5bfc37ff Use Hierarchy::prepopulateTreeDataCache() in CMS (#2266) (Sam Minnée)
  • 2018-09-24 0276f6c08 Revert semver break in adding GridField type hint to method signature (Robbie Averill)
  • 2018-09-24 f76fb26 fix psr (Thomas Portelange)
  • 2018-09-24 5e069ec fix inferReciprocalComponent called on unsaved (Thomas Portelange)
  • 2018-09-24 9b5425d Incorrect parameter order of (Guy Marriott)
  • 2018-09-24 a2bb70c46 Don't flush manifests in tests by default (Ingo Schommer)
  • 2018-09-20 9a89aad Whitelist nonce parameters from JS resources to be loaded. (Luke Edwards)
  • 2018-09-20 16b3d18 FlysystemAssetStore::getAsURL() only grant for protected filesystems (Christopher Darling)
  • 2018-09-20 a9b2443 Revert changes to default dropdownToggleClassNames on ActionMenu (Sacha Judd)
  • 2018-09-19 b98c87a6c Ensure existing session can be accessed if headers_sent() (Sam Minnee)
  • 2018-09-17 d597166 Performance optimisation for draft pages in treeview (Sam Minnee)
  • 2018-09-12 41c0b8fb Fix 'Insert links into a page' test (Luke Edwards)
  • 2018-09-10 fb0d81d Remove action menu toggle styles (Sacha Judd)
  • 2018-09-04 fbd8843 Remove unnecessary UploadTest\Validator (Sam Minnee)
  • 2018-09-04 40c7a0a Better error message for invalid upload (Sam Minnee)
  • 2018-09-03 641208dc Text collector translations now compile without errors (Robbie Averill)
  • 2018-09-03 225445931 Text collector translations now compile without errors (Robbie Averill)
  • 2018-08-31 f5869a5 Do not render view mode toggle on campaign toolbar if the campaign is empty (bergice)
  • 2018-08-30 5488b31 Add explicit 0 z-index to cms-content so the menu toggle can render above it (#620) (Andre Kiste)
  • 2018-08-30 463fdef Remove "more" action icon size, add btn-sm and fix icon alignment in gridfield (Sacha Judd)
  • 2018-08-28 dbfc25302 Fix incorrect version number in 4.3.0 changelog (Loz Calver)
  • 2018-08-28 d1951c94 Sort history viewer versions in descending order (Robbie Averill)
  • 2018-08-28 10ef38f Hide 1px left border in preview component if we are in 'Preview Only' mode (bergice)
  • 2018-08-27 2ab622f Fix Add mock store to the loadComponent AppolloProvider (Maxime Rainville)
  • 2018-08-24 e196475 Graceful validation of image shortcode (Aaron Carlino)
  • 2018-08-24 2b16e2a GridField delete button to offer archive action if possible (#602) (Luke Edwards)
  • 2018-08-24 6164d01d6 GridField delete button to offer archive action if possible (#8325) (Luke Edwards)
  • 2018-08-22 1b67bb08c Fix failing HTML button test step (Luke Edwards)
  • 2018-08-17 160d595e2 fix trailing whitespace (maks)
  • 2018-08-17 16217f365 fix accidentally deleted comma (maks)
  • 2018-08-16 61c046c If archive's possible switch GridField delete button with archive (Luke Edwards)
  • 2018-08-15 d9154bffb text/json is not a valid mimetype (Daniel Hensby)
  • 2018-08-15 d18b5ee text/json is not a valid mimetype (Daniel Hensby)
  • 2018-08-15 41a2a0c text/json is not a mimetype (Daniel Hensby)
  • 2018-08-14 fcaa9ba Restore and archive action improvements (Luke Edwards)
  • 2018-08-14 fc7f712 Modal response animation appearing outside the modal (#601) (Luke Edwards)
  • 2018-08-07 c2b54c7 graphql route getting overwritten (Aaron Carlino)
  • 2018-08-06 e7cb0156 Use LatestDraftVersion in GraphQL query to determine latest draft version (Robbie Averill)
  • 2018-08-06 13372f9a3 Installer redirect to home/ (without domain) (Michael Strong)
  • 2018-08-02 24927c5 Ensure only toolbar buttons that are immediate descendants of toolbars are given margins (Robbie Averill)
  • 2018-08-01 a981584 Remove rogue CSS margin on toolbar buttons. Implemented in campaign-admin preview instead. (Robbie Averill)
  • 2018-08-01 405d8a3 Toolbar button margins are constrained to campaign previews, and update ViewModeActions name (Robbie Averill)
  • 2018-08-01 6889a1a ViewModeToggle now uses BEM class naming convention (Robbie Averill)
  • 2018-07-30 420c3f8 Editor should ignore drag-and-drop files (#814) (Luke Edwards)
  • 2018-07-30 fde7b9ddc Specify minimum composer version (Maxime Rainville)
  • 2018-07-27 67254da1 Apply missing class to report header. (Maxime Rainville)
  • 2018-07-26 900ca9c8d Recommend install of upgrader with PHAR exec. (Maxime Rainville)
  • 2018-07-25 0035f4a90 Fix backtick in changelog breaking sentence formatting (Michal Kleiner)
  • 2018-07-13 d1024ee Add HTMLFragment casting to $Tag (#148) (Jake Bentvelzen)
  • 2018-07-12 a8e5616 Update GridField.js so it works with new Archive View (#559) (Luke Edwards)
  • 2018-07-12 599a4420b Improve GridFieldViewButton to work with new Archive Admin (#8240) (Luke Edwards)
  • 2018-07-11 c2347310 URLSegment field styling fixes #2193 (Maxime Rainville)
  • 2018-07-05 91068c23b Make column query not distinct (Al Twohill)
  • 2018-07-05 730fc42 Fix test for password recovery (Ingo Schommer)
  • 2018-07-01 3262665b2 Fix link and turn of phrase. (Maxime Rainville)
  • 2018-06-29 cc9b36e01 fix link (Lukas)
  • 2018-06-22 f9de357 - Grid field headers misaligned (Petar Simic)
  • 2018-06-18 2f1c2992f Default cache state should be no-cache (Daniel Hensby)
  • 2018-06-17 25b0a18 Fix display of GridField link existing button (Luke Edwards)
  • 2018-06-15 5e4ad34 Fix incorrect base recipe dependency (Damian Mooyman)