How To Force An Update To A Borked Plugin

Editorial Note
I originally wrote this post a couple of years ago when my, um… friend, was a little less clever than he is now. In hindsight, I wasn’t sure the technique included here was a good idea, so I never published it. I’m publishing it now just in case it helps anyone and because it was fun to solve. It’s definitely use at your own risk.

So… Let’s just say for a moment, that you borked your plugin by accidentally tagging the whole repo. Never going to happen, right, because we all use deployment scripts, don’t we?

But let’s just suspend our belief for a moment. You’ve borked your plugin and instead of downloading it and testing it once it’s live, you go to bed. And while you’re having those sweet sweet dreams after a job seemingly well done, users have started updating. Only once they update, there is no your-plugin.php file any more, so the plugin promptly disables itself. You awake to urgent messages.

Hmm. You fix it and upload a working version, so they can just update it again. Nope. The plugin won’t appear in the plugins list any more.

Okay, they can just install it again from the Add Plugins screen. Nope. They’ll get an error telling them the plugin is already installed because the folder is already there, even though it doesn’t have a valid plugin inside it.

Defeat… Time for them to break out the old FTP client and upload the fixed version manually. Only this isn’t one user. This is everyone using your plugin. At least those who updated while it was broken. And some of these users aren’t exactly comfortable with FTP.

Of course. This is never going to happen, is it? But just say it did, perhaps it would be good to come up with a solution that would allow users to update the plugin via the backend.

Saving The Day

First, it must be said this is horribly hacky. And not without risk. Backups please! Perhaps it’s better not to even try this, or to only use it as a very last resort. But here’s what you may possibly decide to do – create instructions telling users to add the following to functions.php:

[sourcecode language=”php”]
function fix_your_plugin_add_steps() {
echo ‘<div class="updated"><p><strong>Fix the Your Plugin plugin:</strong><ul>’;
echo ‘<li>Step 1: <a href="’ . wp_nonce_url(self_admin_url( ‘update.php?action=upgrade-plugin&plugin=your-plugin/your-plugin.php’ ), ‘upgrade-plugin_your-plugin/your-plugin.php’ ) . ‘">Force Update</a></li>’;
echo ‘<li>Step 2: Choose the Activate Plugin link from the resulting page</li>’;
echo ‘<li>Step 3: <a href="’ . self_admin_url( ‘theme-editor.php?file=functions.php&scrollto=100000’ ) . ‘">Return to functions.php</a> and delete the code you added to create this list</li>’;
echo ‘</ul></p></div>’;
}
add_action( ‘admin_footer’, ‘fix_your_plugin_add_steps’ );

function fix_your_plugin_force_update( $transient ) {
$obj = new stdClass();
$obj -> slug = ‘your-plugin’;
$obj -> new_version = ‘1.0.3’;
$obj -> url = ‘https://wordpress.org/plugins/your-plugin/’;
$obj -> package = ‘https://downloads.wordpress.org/plugin/your-plugin.1.0.3.zip’;
$transient -> response[ ‘your-plugin/your-plugin.php’ ] = $obj;
return $transient;
}
add_filter ( ‘pre_set_site_transient_update_plugins’, ‘fix_your_plugin_force_update’ );
[/sourcecode]

It (almost) goes without saying that you should replace all instances of your-plugin, your_plugin and Your Plugin, with the equivalent for your plugin, as well as replacing the two instances of 1.0.3 with the new version you want to upgrade to.

The Instructions

As mentioned above, this is horribly, horribly hacky. You’d probably want to provide users with some decent instructions to follow, so as to limit the chance that this will just make their day (and yours) worse. Maybe something like this:

The safest way to fix this is to manually FTP into your server and delete the your-plugin folder and then re-install the plugin.

If you are not comfortable with doing this, I have another option for you. However, it requires editing functions.php and if you make a mistake you may break your site, so please be very careful. In fact, I recommend doing a site backup before trying this.

To use this work around, please go to Appearance, then Editor and locate Theme Functions (functions.php) in the long list of files on the right. Click on it and that file will open.

Double check that it says Theme Functions (functions.php) above the code editor area. If so, click in the code editor and scroll right to the very bottom (you probably won’t be able to see it at first until you scroll all the way down). Make sure the cursor is flashing and none of the existing code is highlighted.

Open the attached file containing the code to fix this and copy the code. Return to the code editor and paste the code, checking that it is exactly the same.

Then click Update Plugin. The page will refresh and a list will appear at the top of the page with 3 steps for you to follow:

  1. Click the link in the first point to force the plugin to update itself to the latest version.
  2. That will take you to a new page. Once the plugin has finished updating, you will be give a link to Activate Plugin. Click it.
  3. That will take you back to the plugin screen. Click the link in the third point, which will take you back to editing functions.php, and remove the code we added above (taking care not to remove any other code).

If all has gone well, you should fixed the plugin, activated it and removed the temporary list of steps.

And of course you need to send them the code to go with this.

Interesting Bits

Whether this is a sensible thing to do or not, the code has some interesting stuff in there.

We are essentially mimicking what some premium plugins do – intercepting the call to the wordpress.org repository and adding our non-wordpress.org plugin to the list of plugins that WordPress has update information for. At this point, our plugin may as well be a non wordpress.org plugin, as the standard update mechanism is never going to allow our plugin to be updated.

We’re using the technique here, only instead of telling WordPress to download from our own server, we’re telling it to download from wordpress.org.

We do this by using the pre_set_site_transient_update_plugins filter to hook into the update_plugins transient and add our plugin back into the list of plugins WP is thinking about.

As well as this, we are adding a series of steps into a message at the top of every page in the admin area. These steps tell the user what they need to do to complete the process.

First, we link straight to the update link for the plugin. That won’t do anything without us hijacking the update_plugins transient. But with that other code block in place, WordPress will allow the update to proceed. Because it’s an update, not an installation, it won’t be put off by finding the folder in place. It will delete it (bye bye folder containing the entire plugin repo!), then install the plugin from .org (or whichever URL we added).

Next, we tell the user to Activate the plugin.

Finally, we need the user to get rid of the code added to functions.php. To help them do this, we provide a link to the Theme Editor, with the functions.php file open and the scroll to parameter set to 100000, which should place them at the bottom of the file (in all but the most extreme cases!), right where the code they need to remove is located. We need to make it easy for them, so that they actually remove it. Of course, the message will stay there forever unless they remove the code, which is a good incentive for them to remove it.

Final Thoughts

So, am I crazy? What would you do if you were in this situation: a) provide them the code above; b) tell them to use FTP; or c) something else?

Also, you should totally follow me on Twitter, so you can hear about more embarrassing stories that happen to, um, a friend of mine…