
In June 2025 Silverstripe 6 was released. A new major version, cool. Some cool new features and many small changes under the hood for an up-to-date codebase.
The most significant changes are that it bumped the minimum Version of PHP to 8.3 and many classes got renamed. So updating could be cumbersome? Not really. As many people face the problems of upgrading code, some clever folks invented Rector, a tool for upgrading PHP with defined and tested rules, so-called rectors. This can help us to e.g. rename classes automatically or to convert code to newer constructs, e.g. match
instead of switch
, string_starts_with
instead of checking str_pos
, etc...
This document will lead you through the progress of upgrading a site from Silverstripe 5 to Silverstripe 6 and will explain the steps and tools I recommend for doing this task.
Before upgrading you should update your project, including all modules to the latest version of Silverstripe CMS 5. Your IDE will complain about a lot of deprecations, most of them can be handled automatically.
For upgrading PHP code, I use a tool called Rector. It uses PHP's abstract syntax tree (AST) to analyse your code and can change code much more precisely than any search-and-replace can ever do, cause it knows if it's changing a class name or a variable name, etc. Therefor you can write pretty specific rules, rectors, to change code in certain circumstances.
I started to collect some rectors specifically for Silverstripe CMS. Feel free to suggest enhancements or to PR your own rectors.
We'll use this tool to upgrade our code.
Rector should be installed as a developer dependency:
composer require wernerkrauss/silverstripe-rector:^1 --dev
It will automatically install Rector, PHPStan and other required packages.
Next, you'll need to add a rector.php to your project root. Here is my boilerplate:
<?php
declare(strict_types=1);
use Netwerkstatt\SilverstripeRector\Set\SilverstripeLevelSetList;
use Netwerkstatt\SilverstripeRector\Set\SilverstripeSetList;
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/app/_config.php',
__DIR__ . '/app/src',
])
// uncomment to reach your current PHP version
->withPhpSets()
->withSets([
SilverstripeSetList::CODE_STYLE,
SilverstripeLevelSetList::UP_TO_SS_6_0
])
->withTypeCoverageLevel(0)
->withDeadCodeLevel(0)
->withCodeQualityLevel(0);
in the withPaths()
method we can configure all the paths of our code, Rector should check. withPHPSets()
automatically updates your code to the currently used PHP version. In withSets()
we can define some sets of rectors, in this case for Silverstripe code style (e.g. use ::create()
where possible) and for upgrading to the latest and greatest version of Silverstripe.
The remaining directives help you to improve your code step by step with better type coverage, code quality or less unneeded code.
For a deeper dive into configuring Rector, you can check its documentation.
Running Rector on an old code base will change a lot. Too much for checking if everything is still right. So it's recommended that you change one thing at a time, commit the changes to git and then change the next thing. So first, you can comment out the Silverstripe sets and only update your code to PHP8.3.
Now let's run Rector the first time. Make sure that your last code changes are checked into git, so you can roll back at any time. You can now run
vendor/bin/rector --dry-run
in your CLI.
With --dry-run
we tell Rector to show us, what it would like to change. If we're happy with the changes, we can remove that parameter and let Rector change our code.
Then you can commit the changes, enable another Rector or setlist and repeat.
As we're still on SS5, you might use the setlist SilverstripeLevelSetList::UP_TO_SS_5_4
.
Now that our project's code is improved and hopefully all deprecations are fixed (we'll rename classes in Step 4.2), we need to update composer's requirements when switching to Silverstripe's new major version.
Most Silverstripe projects use a lot of modules, some of them might be already updated, others not. So the next step is to check the required modules in your composer.json for updates. I do this manually on packagist.
If a module doesn't have a SS6 compatible release, I also go to its GitHub page and check on "Insights → Network" if there are any recent forks that already updated that module. Sometimes this saves duplicate work.
Modules that are already compatible with SS6 can be updated, others need to be removed for now.
So now that you installed SS6 to your project, running dev/build will throw a bunch of errors. That's the time to upgrade your code. Enable SilverstripeLevelSetList::UP_TO_SS_6_0
in your rector.php and run Rector.
Once dev/build works, we're one step further, but still not done. Make sure your code works as expected and use tools for linting or static analysis to find errors in your code and raise its quality.
Note: build tasks have massive changes, and I don't have (yet) Rector rules for them. As Tasks are now full Symfony CLI scripts, you need to spend some time to think about input parameters etc.
So there are some modules still not available for SS6? You can either complain or remember what open source is all about: collaboration. So feel free to update those modules. It's not really harder than upgrading your own code.
For changing code in a third-party module, you need to fork it on GitHub.
I tend to clone the module in my project root so that I can reach the code more comfortably.
In the cloned module, create a branch, e.g. 'silverstripe6', for upgrading the module.
You can add a module (with all its dependencies) to your project with Composer's path directive. This is cool for upgrading. For delivering the project, I prefer to install a branch from my repository's VCS directly until the upgrade is released.
"repositories": [
{
"type": "path",
"url": "./module-to-update"
},
Add the module's path to your rector.php and update its code step by step. Make sure to commit after each iteration.
Once you're happy with your results, push the code to your fork on GitHub and let's go on to the next step.
Let's change the repository in composer.json to
"repositories": [
{
"type": "git",
"url": "https://github.com/myhandle/module.git"
},
and change the requirement to
"vendor/module": "dev-silverstripe6 as 6.0",
Here, dev-silverstripe6
needs to match the name of your branch, in this example silverstripe6
. The as x.y.z
tells Composer to treat your fork as version x.y.z of the module. If the current version of the module is 5.4, and I have breaking changes (e.g. classes got renamed), I choose to treat my fork as a new major version.
By the way:
What do you get when you throw a piano onto an army base? A flat major.
Sorry. Not.
Now that the module works fine, it's essential that you create a pull request on the original module, so others can also upgrade their projects to Silverstripe 6.
- Test your code
Of course, you already have unit tests that can guarantee everything works as expected. - Add more code quality tools like linting or static analysis.
This annoys a lot in the beginning, but once you're through the first frustrations, those tools help you find buggy code more easily. It's really worth the work! - If you find some recurring changes while updating, feel free to raise an issue or create your own Rector and submit a PR to silverstripe-rector.
The new major version 6 of our good ol' friend Silverstripe CMS comes with a lot of changes, but there are tools that help us to update our code as much as possible. With Rector, we can automate many parts of the upgrade task and get better code quality for free.