When WordPress Treats an Administrator Like a Contributor

The first sign that something was wrong was when I tried to create a new page on the client’s site. The blue Publish button I normally see was replaced with Submit for Review. What the…? That’s what WordPress users with the lowly Contributor role usually see. But I’m an Administrator — the most mighty role known to the world of (single-site) WordPress. (Yes, multi-site installations also confer the fearsome title of Super Admin upon a select few.)

Worse still, if I tried to click Submit for Review, it wouldn’t actually save!

Other problems abounded — I tried to create a new user with Administrator privileges, just to see if my own user account was corrupt. Couldn’t save that, either.

I had Debug Bar installed, and I noticed it was giving an error:

WARNING: wp-admin/includes/post.php:641 - Creating default object from empty value
get_default_post_to_edit

Well, that’s not good. Googling the error didn’t lead to anything immediately helpful, besides this comment that led me to explore the database structure in phpMyAdmin for any problems.

Yes, there were problems. Many of the tables, including wp_options, wp_posts, wp_postmeta and wp_users were missing their primary keys. A bit more digging into the WordPress core showed that, for complex reasons (i.e. I don’t totally get it), without primary keys on these tables, WordPress can’t determine the post type of a new post, and if it can’t determine the post type, it can’t determine the user’s capabilities with regard to that post type, which all comes back to…

WARNING: wp-admin/includes/post.php:641 - Creating default object from empty value
get_default_post_to_edit

Googling on the matter of WordPress tables missing their primary keys (or, perhaps more pertinently, their auto-increments), led me to a solution!!

Fixing WordPress indexes, foreign keys and auto_increment fields

Well, a partial solution. Because the database I was working with was not damaged in exactly the same way as the one the OP was working with, I couldn’t use the sample code directly. I had to go through the database and manually create a few primary keys, delete a bunch of auto-draft posts that all had an ID of 0, etc. Then I had to skip a few lines of the OP’s SQL code because they referred to tables that hadn’t lost their keys in my case, for whatever reason. But this is the… key… to solving the problem.

Now then, how did the database get this way? Well, the site lives on a fairly creaky old Fatcow (ugh, that name) shared hosting account, running an old version of MySQL and an almost unrecognizably ancient version of phpMyAdmin. We were undertaking major content changes on the site, so I copied it over to my own sleek, modern staging server running the latest and greatest of everything. The idea was that we’d get all of our changes in place just the way we wanted on the staging server, rather than mess up the live site for 2-3 weeks, and when we were done, we’d just copy everything back over.

Slick. Right? Sure, if both servers are running reasonably identical software versions. Which of course is never the case. Ever.

Apparently when I copied the site back to Fatcow, due to the older MySQL (or possibly phpMyAdmin) version, certain things like the primary keys and auto-increments — and, I’d be willing to bet, but I’m not sure it matters, the collation as well — got lost along the way.

How not to update a WordPress plugin

The meaning of this post’s title is twofold: 1) how, as a WordPress user, to avoid having a plugin show up in the built-in updater; and 2) how, as a developer, you probably should not approach releasing a major update to your plugin that is incompatible with earlier versions.

The scapegoat here is Elliot Condon’s excellent Advanced Custom Fields, which has become one of my essential go-to plugins for building highly customized WordPress websites for my clients. I don’t mean to pick on Elliot Condon. He’s clearly a tremendously talented developer and I have a ton of respect for his work and what it has allowed me to do in my work.

But I do feel that he handled the 4.0 release of Advanced Custom Fields poorly. I’m not sure the fault is really his, however, as it is just as much or more the fault of how the built-in updater in WordPress works. (Especially since at least some of the changes he made in version 4 were done solely to conform to changes in the official WordPress plugin requirements.)

Here’s the problem: WordPress has a central Plugin Directory that makes it easy to install and update approved plugins. Perhaps too easy. Because if an update of a plugin is made available, and it’s newer than the version you have installed, it appears as an option in the updater. Yes, there are links to information about the update, which you really should read before doing anything else, but it’s all too easy with a few clicks to just run the update and move on.

Most of the time, it just works. Which can be dangerous. Because users — even “experts” like me — come to assume it will always “just work.”

As it happens, the version 4.0 release of Advanced Custom Fields was made available while I was on a weeklong vacation out west with my family, with only my iPad (and SLP’s MacBook Air) along for the ride. And, based on my own recommendations, a client with a relatively newly-launched website went ahead and ran the update. This particular site is heavily dependent on ACF, and the update broke it.

The official ACF website offers a migration guide that makes it (somewhat) easy to convert your existing version 3 implementation to work with version 4. But it’s not a “click-it-and-you’re-done” kind of process. It takes time, and you need to know what you’re doing. Which is nothing like the general experience of using the built-in WordPress updater.

I was able to temporarily solve the problem for this website by rolling back to an earlier version (which required some hunting to locate, given the limited Internet access I had with hotel WiFi). Which leads to my first tip:

How to prevent a WordPress plugin from updating

How does WordPress know when a plugin has an update available? Well, it’s easy for it to check the Plugin Directory to see what the latest version of any given plugin is. But how does it know which version you have installed? Also easy. Each plugin’s main PHP file includes a comment block at the top, with information WordPress parses both to display in the Plugins area of the admin interface and for added functionality (e.g. knowing when there’s an update available). For Advanced Custom Fields, the comment block looks like this:

/*
Plugin Name: Advanced Custom Fields
Plugin URI: http://www.advancedcustomfields.com/
Description: Fully customise WordPress edit screens with powerful fields. Boasting a professional interface and a powerfull API, it’s a must have for any web developer working with WordPress. Field types include: Wysiwyg, text, textarea, image, file, select, checkbox, page link, post object, date picker, color picker, repeater, flexible content, gallery and more!
Version: 3.5.8.2
Author: Elliot Condon
Author URI: http://www.elliotcondon.com/
License: GPL
Copyright: Elliot Condon
*/

This is essentially a set of key/value pairs. Version is what WordPress reads to see which version you’re running, and compares it against the master version in the Plugin Directory to see if updates are available.

So how do you keep it from running the update? Simple: Change the version number to something higher. I like to prepend it with “999” so I still know what the “real” version number is that I’m running, like this: 999.3.5.8.2. This way the WordPress updater thinks the major version is “999”, which is almost certainly higher than whatever the real current version is.

Simply change this version number, save the PHP file on your server, and you’re done. The updater will never trigger for this plugin (as long as its real version number is less than 999). You may also want to update Description with an explanation of what you’ve done.

Bear in mind this is a temporary solution. You really should do whatever you need to do to get your site compatible with the latest version, then restore the original version number and let the updater do its magic.

How, as a developer, not to create this mess for your users

I have submitted a few, very simple, plugins and themes to the official WordPress repositories, so I have a bit of experience with this, but I’m no expert on the process. However, what is clear to me is that if you submit changes to a plugin as an update, the built-in updater will pick it up and make it available to any users who have an older version installed. This is dangerous. If your new version includes such radical changes as to make it incompatible with earlier versions, you have to assume that most users will not read your notes, and will believe they can just run the updater with no problems… especially if you’ve made a habit of releasing frequent incremental updates to the plugin in the past that “just worked.”

The only real solution I see to this is to submit the new, incompatible version to the Plugin Directory as an altogether new plugin, instead of an update to the existing plugin. The risk here is that you lose visibility. Your download count and ratings/reviews reset to zero, and anyone who’s using an older version may never know about the new version. So, it’s bad for marketing.

But an incompatible update breaking sites for unsuspecting users is bad for marketing too. It’s going to cause your ratings to take a hit, cause a lot of bad publicity, and turn off your loyal users. The migration is going to be work for them anyway; making them do it after they clean up a mess created when they unsuspectingly ran the update is even worse.

A few specifics as pertains to Advanced Custom Fields

Again, I don’t mean to pick on Elliot Condon for his work with Advanced Custom Fields. I will continue to be a loyal (and, yes, paid) user of this plugin. It’s brilliant. Nonetheless, it’s created a hassle for me this week. After returning from my trip, the first work-related thing I did was go through every client site that’s running ACF and apply my “version 999” trick so those clients won’t run the updater until I have a chance to migrate their sites to version 4.

The biggest challenge I had in rolling back was simply getting my hands on the old version. Sure, I had it on some of my other sites, but I access almost every client site via SSH/SFTP, and the hotel I was staying at had port 22 blocked. Luckily the site I needed to fix was one of the few I access via regular FTP, and port 21 was open. But I still needed to get a copy of version 3.x to reinstall on that client’s site.

As I found along the way, the WordPress Plugin Directory hides old versions under the “Developers” tab, where every previous version can be downloaded as a ZIP file or checked out with Subversion. Previous versions of ACF are available here.

A fix for a fix in WordPress 2.1

One thing that surprised me when I started using WordPress again is that its search function only searches on blog posts, not on static pages. I suppose if most WordPress sites are 99.9% blog posts, then it probably makes sense, but I have enough static pages on my site that I’d like to make searchable to warrant changing this.

Fortunately, someone has. Unfortunately this “Search Pages” plug-in is out of date and no longer works with current versions of WordPress. I dug in a bit and figured out why: the plug-in alters the SQL query that performs the search, but the substring it replaces in the query no longer exists! So I hunted down the place where the query occurs in the WordPress core, adjusted the plug-in as needed, and it works!

Here, then, is my hack of the Search Pages plug-in, modified to work with WordPress 2.1. (I’m not sure which other versions of WordPress it will or will not work with.)

[ search_pages.php.tar.gz ] [ search_pages.php.zip ]