This post originally appeared on the blog for my ICS Calendar plugin.
I’m not just a WordPress plugin developer… I’m also a WordPress user.
This very website, which sells a WordPress plugin, runs WordPress. And a bunch of other WordPress plugins, most of which I didn’t develop.
This morning, I found I suddenly was unable to log into the WordPress admin. Well… I could log in. But I couldn’t access any admin pages. At first I worried the site had been hacked. Although I’m aware of most of the typical hack vectors and have taken reasonable standard precautions to prevent that.
What happened today was unlike anything I had ever encountered before. It started with a fatal error in Gravity SMTP — the plugin I use for sending emails. I’m not throwing Gravity under the bus. What happened was totally not their fault; their plugin just happened to be the canary in the coalmine.
Specifically, I got this error:
Fatal error: Uncaught Error: Call to a member function add_cap() on null in /wp-content/plugins/gravitysmtp/includes/users/class-roles.php:105
That led me on a wild goose chase of deactivating plugins, reinstalling WordPress core, rebooting my server, manually editing records in the database… the stuff they tell you you “shouldn’t” do, but I know how to do because I’ve been doing this since before the rules existed. (In fact, some of my youthful mistakes in the late 1990s and early 2000s probably helped define the rules.)
None of that got me anywhere. One thing I did find that I thought would solve the problem was my discovery that the record in the wp_options
data table that stores all of the roles and capabilities was missing. How does that happen?
A hack was unlikely. Data records do get corrupted or accidentally deleted from time to time. It’s possible that it was an obscure bug in a plugin, or more specifically a plugin conflict. I may never know.
Anyway, I tried to fix that by copying the corresponding record from the database of another WordPress site. But even though the {$table_prefix}_user_roles
option was back, WordPress wasn’t reading it.
At least I knew the realm of the problem at this point, so I searched for another answer, and that’s when I found this helpful tutorial from Hostinger.
This requires using WP-CLI to run some commands over SSH. I didn’t have WP-CLI installed, but fortunately that’s easy to do.
Once I had it installed I ran the wp role list
command, and was alarmed to get back an empty list. So maybe there was a second option I would have needed to restore in the database, but that didn’t matter because by now I was at the command line and could just do the rest of what I needed right there.
First, I needed to restore all of the core WordPress roles. That required a few simple commands:
wp role reset administrator
wp role reset editor
wp role reset author
wp role reset contributor
wp role reset subscriber
With the roles reset, I was actually able to access the WP admin area again, and I could proceed to the next step: the e-commerce portion of this site, unsurprisingly, is built on WooCommerce, so I needed to get Woo’s custom roles reset. The WP-CLI stuff only works for WordPress default roles, not custom roles created by plugins.
I checked my Users list, and sure enough all of the customers just had “None” listed as their role. I was reasonably confident the data was intact, and it was just that the “Customer” role was undefined.
Most plugins that make these kinds of data modifications have special functions that run on activation, so I just deactivated and reactivated all of my plugins, and that seems to have reset everything.
In conclusion, this post is intended to serve two purposes:
- To help other WordPress site admins who might encounter this weird and alarming problem.
- To explain to ICS Calendar Pro customers what was going on if they had any trouble accessing the site earlier today.
While this problem is certainly weird and alarming, it is also exceedingly rare. I have built, literally, hundreds of WordPress websites in the past 18 years. This is the first time I have ever encountered this issue. Let’s hope it’s the last. But if not, at least now I know what to do, and can jump straight to a 2-minute solution using WP-CLI, instead of fumbling around in the dark for 2 hours like I did this morning.