Single Blog

WordPress 7.1 Breaks WP Rocket on Elementor Pro Sites: What Happened and How to Spot It

August 20, 2026, Written by 0 comment

WordPress 7.1 was released on 19 August 2026. On sites running WP Rocket alongside Elementor Pro, updating to it produces a fatal error that takes down the front end, wp-admin, the REST API, cron and WP-CLI at the same time. Three sites we manage were affected this week. As of 20 August, neither WP Rocket nor Elementor Pro has shipped a fix.

It landed on the same day Elementor disclosed a critical file upload vulnerability in Elementor Pro, fixed in 4.2.2. The two are unrelated, but they hit the same sites in the same 24 hours.

What Changed in 7.1

WordPress identifies every hook callback with an internal ID generated by _wp_filter_build_unique_id(). Up to 7.0.x, a closure’s ID came from spl_object_hash(), a 32-character hex string with leading zeros. In 7.1 it comes from spl_object_id(), a small integer cast to a string.

In 7.0.x a closure was routed through the object branch and keyed by its object hash. In 7.1 the object check comes first and returns the object ID directly.

Those leading zeros were doing quiet work. PHP converts a string array key to an integer only when it is a canonical integer — “00000000000000012a3f” never qualifies, “4149” does. So from 7.1, callback keys in wpfilter[hook]->callbacks can be integers where they had always been strings.

This only affects bare closures. Named functions, static methods and object methods all produce keys containing letters (my_function, MyClass::method, 4149method). A closure has no method name to append, so its key is purely numeric.

Registered as Key produced Type
‘my_function’ my_function string
[‘MyClass’, ‘method’] MyClass::method string
[$obj, ‘method’] 4149method string
function() {…} 4149 integer

The change is not mentioned in the WordPress 7.1 Field Guide, which covers jQuery UI 1.14.2, the iframed editor, block pseudo-states, multisite URLs and admin bar navigation. There was no vendor-readiness list to check because nobody knew to make one.

Why WP Rocket Fatals

WP Rocket’s Cloudflare compatibility module (inc/ThirdParty/Plugins/CDN/Cloudflare.php) unhooks callbacks belonging to the Cloudflare plugin by walking the callback list and comparing the tail of each key to a method name. That comparison is a substr() call on the key, and it is the line that fails.

The file declares strict_types=1. Under PHP 8’s default coercive mode, substr(4149, …) is legal and PHP converts the integer. Under strict types it throws:

Uncaught TypeError: substr(): Argument #1 ($string) must be of type string, int given
in wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/CDN/Cloudflare.php:562

The plugins most likely to hard-crash on this are the ones that adopted strict typing. Looser code coerces and carries on.

The module runs whether or not the Cloudflare add-on is enabled, and it fires on init, which is why every entry point dies together. The usual recovery route — log in and deactivate the plugin — is not available because wp-admin is one of the casualties.

The Trigger Is Narrow

WP Rocket only walks two hooks at two specific priorities: deleted_post at priority 10 and transition_post_status at PHP_INT_MAX. A closure anywhere else on the site is harmless. All four conditions are required:

  1. WP Rocket 3.16 or later (earlier versions predate the module)
  2. WordPress 7.1
  3. PHP 8 (PHP 7 coerces silently)
  4. A closure registered on one of those two hook/priority pairs

Elementor Pro registers a closure on deleted_post at priority 10. Free Elementor does not — it uses object methods there, and its one closure on a post-lifecycle hook is on before_delete_post, which WP Rocket never inspects.

That is not a difference in code quality. We counted: free Elementor registers 189 of 791 hooks via closure (23.9%), Pro registers 164 of 692 (23.7%). Same team, same conventions, same rate. Of Pro’s three post-lifecycle closures (deleted_post, trashed_post, untrashed_post), only the first lands in a bucket WP Rocket looks at. Free Elementor missed this by one hook name, and that can change with any release on either side.

A Cached Homepage Hides a Dead Site

This is the part that matters operationally. WP Rocket serves static HTML written before the update. When PHP fatals, the homepage keeps returning HTTP 200 from those files while everything behind it is down. Two of our three affected sites presented exactly that way: normal-looking front page, no admin access, no monitoring alert. One was still reporting the pre-update WordPress version in its generator meta tag hours after 7.1 had been installed.

A site in that state goes fully dark on its own as the cache files expire.

The reliable check is GET /wp-json/. It is never cached, it executes PHP, and it needs no credentials. A healthy site returns 200; a site in this state returns 500.

A plain request to /wp-json/ with a browser User-Agent is enough to check it, and it can be scripted across a list of sites.

Two things to get right if you do script it: use a browser User-Agent, because WAFs and CDNs block unfamiliar ones and produce false 403s; and do not trust generator tags, since many sites strip them and cached pages report the old version anyway.

Working Out Which Sites Are Exposed

Detecting the plugin combination from the outside does not work. Reading homepage markup misses plugins that load no front-end assets. Probing plugin file paths gives false positives, because many servers return 200 or 403 for paths that do not exist, and files on disk do not mean a plugin is active.

The control test that fixes the second method: request a plugin path that cannot exist. If that also returns 200, the server says 200 to everything and the probe is meaningless. In our case that test cleared three sites flagged as at-risk and confirmed one that was affected.

What actually works is the hosting control panel’s plugin status — active versus merely installed.

Recovery and Interim Fix

With wp-admin down, deactivate WP Rocket by renaming wp-content/plugins/wp-rocket over SFTP or your host’s file manager. The site recovers immediately.

Updating either plugin does nothing as of 20 August. We checked: the current Elementor Pro release is byte-for-byte identical to the previous one on the relevant file, and the current WP Rocket release is unchanged. The upstream bug reports have been open and unassigned since the 7.1 beta.

The interim fix is a one-line cast in Cloudflare.php, before the string function:

if ( substr( (string) $key, - strlen( $method ) ) !== $method ) {

The next WP Rocket update will overwrite it, which is fine — that update should carry the real fix.

What Our Clients Need to Do

Nothing. The three affected sites were patched with the cast above and are running normally. Every other site we manage with WP Rocket and Elementor Pro is being held on 7.0.4 until a fixed WP Rocket ships, and we are checking /wp-json/ across the full book rather than relying on homepage monitoring.

Holding back is defensible here in a way it usually is not. WordPress.org classifies 7.0.4 as outdated, not insecure — there are no known unpatched vulnerabilities in it, because the security fixes all landed earlier in the 7.0.x line. 7.1 is a feature release.

Self-Managed Sites

If you run WP Rocket and Elementor Pro on PHP 8, do not update to 7.1 yet. If you already have and the site is down, rename the WP Rocket folder to get back in, then either apply the cast or leave WP Rocket off until a fix ships.

If you have updated and the site looks fine, check /wp-json/ anyway. A cached homepage is not evidence the site is working.

The Quieter Failure

The fatal is the loud version of this change. Any plugin that compares a hook key against a stored spl_object_hash() value, or caches hook keys in the database, now silently fails to match. No error, no 500, no log entry — it just stops doing what it thinks it is doing. That shows up weeks later as “the cache stopped clearing” or “that setting doesn’t stick any more”, and nobody connects it to a core update.

The pattern to watch is any plugin that unhooks other plugins’ callbacks: caching and optimisation plugins, security plugins, “disable X” plugins, page builders removing theme hooks, and hand-rolled remove_action() snippets in functions.php.

For a once-over on whether your site is ready for 7.1, get in touch or see our managed WordPress care plans.

Sources

Andrew

Andrew is a Wordpress enthusiast, web developer and founder of WP Care.