WordPress 7.1 plus WP Rocket plus Elementor Pro took 37% of our WP Rocket sites down. Core was fine. The combination was not. Hosts should be probing the next core against live plugins before it ships.
I think we have all gotten lazy about WordPress core.
Core updates are very stable. We have come to trust them. When something breaks after a core bump, it is almost never WordPress. It is almost always a third-party plugin hitting a new PHP type check, a renamed hook, or a filter that used to be sloppy and is not sloppy anymore.
That trust is earned. It is also how a sneaky PHP fatal ships on release day and takes a third of WP Rocket’s installs offline before anyone has a test for it.
WordPress 7.1 went out. Then 124 sites went down.
I do not like surprises from automatic background updates. When a new core update shows up I jump on it and deploy it everywhere. That is intentional. If anything happens, I can step in and fix it.
WordPress 7.1 was that day. A few minutes later a pile of WP Rocket sites were returning 500s. I patched the plugin and got every Anchor Hosting customer back online in a very timely manner. I posted the status page while I was still figuring out what happened. WordPress 7.1 + WP Rocket PHP Fatal.

Initially I thought it was “all WP Rocket sites.” It was not. It was sneakier than that.
Every fatal was the same line. WordPress 7.1, PHP 8, WP Rocket Cloudflare.php:562, with declare(strict_types=1).
A clean WordPress 7.1 site with WP Rocket did not fatal. The deleted_post hook had string keys. substr() was happy. Add Elementor Pro, or CF7 Redirection, and the next request blows up. Those plugins put integer keys on $wp_filter['deleted_post']. WP Rocket walked them with substr( $key, ... ). PHP 8 under strict types does not coerce that integer to a string. TypeError. Site down.
The loop looked like this.
foreach ( $original_wp_filter[ $priority ] as $key => $config ) {
if ( substr( $key, - strlen( $method ) ) !== $method ) {
continue;
}
}
The patch is a cast. substr( (string) $key, ... ). One line. WP Rocket shipped it as 3.23.2.2 the next day and said the diagnosis was right.

I feel for WP Rocket. This was an edge case.
Everyone wanted to blame them for missing a bug. We all miss bugs. They made a mistake. They fixed it. Let’s move on.
Complaining about WP Rocket is wasted effort. In that same amount of time, I had already patched every customer site and started building a test so that this can’t happen again.
I am calling this an edge case on purpose. You needed three things at once. WordPress 7.1. WP Rocket. Elementor Pro (or another plugin that registers integer filter keys). Miss any one of those and the site stays up. That is why a “test WP Rocket on 7.1” checklist does not catch it. The plugin is fine in isolation. Production sites are a different story.
The bigger reveal is that no web host caught it.
If a WordPress host had been probing core updates against live plugin stacks, someone would have filed this before 7.1 shipped. Nobody did. Not the big guys. Not the little guys. None.
To be fair, someone did post the issue on GitHub: https://github.com/wp-media/wp-rocket/issues/8596. However, without a clear path to reproduce I can see why it was missed. My point is, where are all of the web hosts? Why didn’t any of the web hosts find and report the PHP fatals? I’ll tell you why. They are not testing WordPress future releases on actual customer websites.
Hosts have the one thing plugin vendors do not. Thousands of real production combinations. WP Rocket plus Elementor Pro plus a specific theme plus PHP 8.3. That is not a matrix you reconstruct in CI. That’s real-world usage.
We have all been treating core as so boring that we stopped testing it where it actually runs. Or maybe we’ve never run tests?
This idea started as a voice memo.
I was driving. The idea was simple. Sideload the next WordPress core into a sibling directory. Point it at the live database, the live plugins, and the live theme. Boot it. Hunt for PHP fatals. If it blows up, leave production alone.
That became a bash script in CaptainCore. I tested it on a normal Kinsta site, a Rocket.net site, and a WP Freighter tenant. Then we recreated the exact 7.1 bug. WP Rocket 3.23.2.1 plus Elementor Pro, site still on 7.0.4. Live stayed 200. Sideload 7.1. Same TypeError. Same file. Same line. The live core never swapped. No users would have seen the check.
Will it catch everything? No. Would it have caught this one? Yes. The fatal runs on init. The first gate is a WP-CLI boot of the new core with plugins loaded. That is enough.
Sideload the next core. Do not swap until it boots.
The trick is the inverse of what I’m doing with my WP Freighter plugin. Same database, same plugins, same theme. Different core files, sitting in $HOME/tmp so PHP-FPM can read them without putting a second WordPress on the public web root.
Point WP_CONTENT_DIR at the live content. Boot it. Render /. Hit the homepage over the host’s localhost loopback. If anything 500s, leave production on the old core.
Then I deployed it. Monthly checkup across production. When the run finishes I get one email. How many updated, how many skipped, how many failed, and a table of every site that blew up.

For the crontab I added a --version=next argument. It allows the cron to be dumb and just auto-select a new WordPress release. The script asks wordpress.org for the current stable. Then it walks channels in order and only keeps an offer that is a prerelease and not the same as stable.
- RC first. Closest thing to what will actually ship.
- Else beta.
- Else the development build, which we download as nightly.
Right now there is no 7.2 beta and no 7.2 RC. Both of those channels just echo 7.1. So next resolves to nightly, which is 7.2-alpha. When RC1 shows up, the same command starts probing RC1. No crontab change.
The fleet command looks like this.
captaincore ssh @production --script=update-core --version=next --probe-only --parallel=40
The script is public. Kinsta and Rocket.net both work. captaincore/lib/remote-scripts/update-core. Steal it. Adapt for your provider.
WP Rocket walked $wp_filter callbacks and called substr() on the key. Elementor Pro (and a couple of others) put integers in that array. PHP 8 with strict_types fataled. WordPress 7.1 made the combination show up on release day.
Plugin vendors test their plugin. Core tests core. Hosts roll core because it has been safe. The hole is the live combination. 124 sites of 332 is not a default-install bug. It is a production-matrix bug.
Voice memo, then a bash script, then a monthly production checkup. CaptainCore sideloads the next core next to live plugins, boots it, and curls the homepage. Fatals abort. Live files do not move. I get one recap email of everything that failed.
I still trust WordPress core updates. I’m bummed no other web host caught the bug. Next time I’ll be prepared.