Protect My Plugins, Please

The following posts are coming up!

Recent Posts



I have a site that literally requires a specific plugin always be active for things to work. It has a lot of very complicated code, and two things must never ever happen to this:

  1. It should never be disabled
  2. It should never be updated by WordPress

Well. Okay. Let’s do that.

A Caveat

If you don’t have a way in place to update and secure the plugin you’re hiding, DON’T DO THIS. Once you hide it, people won’t know to update it and, in fact, won’t be able to. Because you’re also preventing traditional updates. In my case, I have a git repository that triggers a push (plus some other magic).

Again. Unless you’ve got something set up to handle updates, don’t do this.

Now let’s do this.

Never Disable Me (by Hiding)

To do this, we need to know the folder name and filename of the plugin, such as ‘my-plugin/my-plugin.php. If you want to hide the plugin you've put the code in, you can useplugin_basename( FILE )` instead, which is what I’ve done.

add_action( 'pre_current_active_plugins', 'mysite_hide_my_plugins' );
function mysite_hide_my_plugins() {
	global $wp_list_table;

	$hide_plugins = array(
		plugin_basename( __FILE__ ),
	);
	$curr_plugins = $wp_list_table->items;
	foreach ( $curr_plugins as $plugin => $data ) {
		if (in_array( $plugin, $hide_plugins ) ) {
			unset( $wp_list_table->items[$plugin] );
		}
	}
}

If you were writing a plugin to hide a lot of things, you would change the array to list all of them. But since this is a ‘hide myself’ deal, it’s easier to put it in the plugin itself.

The added bonus to making the file path dynamic is that if someone gets clever and renamed the folder or file, it would still work. Neener.

Stop My Updates

Now this one again is easier if you put it in the plugin you’re disabling updates for, because again you can use plugin_basename( __FILE__ ) to detect the plugin. If you’re not, then you’ll need to make an array of names. But that should get you started.

add_filter( 'http_request_args', 'mysite_disable_my_plugin_update', 10, 2 );
function mysite_disable_my_plugin_update( $return, $url ) {
	if ( 0 === strpos( $url, 'https://api.wordpress.org/plugins/update-check/' ) ) {
		$my_plugin = plugin_basename( __FILE__ );
		$plugins   = json_decode( $return['body']['plugins'], true );
		unset( $plugins['plugins'][$my_plugin] );
		unset( $plugins['active'][array_search( $my_plugin, $plugins['active'] )] );
		$return['body']['plugins'] = json_encode( $plugins );
	}
	return $return;
}

What Does It Look Like?

Nothing, really. You’ve hidden everything. Congratulations. Now you don’t have to worry about admins or WordPress updating your plugin. Or worse.


Posted

in

by

Comments

4 responses to “Protect My Plugins, Please”

  1. Brajesh Singh Avatar

    Hi Mika,
    Nice strategy. Another strategy will be to use MU Plugins
    https://codex.wordpress.org/Must_Use_Plugins
    It will need a bit adjustment to the plugin(for loading the main file) but it does work with both of your conditions. I have been using mu-plugins for a scenario like this and It has worked great for me.

    1. Ipstenu (Mika Epstein) Avatar

      An MU plugin isn’t tied directly to this plugin, which makes it appropriate for preventing updates on multiple plugins and not really one single plugin. If you were, say, deploying your plugin to clients, making it self contained is the wiser option.

    2. Brajesh Singh Avatar

      Completely agree with you about mu plugin for multiple plugins. Do you see any advantage of this approach other than being self contained over the plugin(Say I am using a loader like https://github.com/bueltge/must-use-loader to keep things more streamlined). This is a very interesting approach, I am a bit curious as it sends the plugin in incognito mode which may be a cause of concern for future developer.
      Btw, I do see that your approach is way better on a multisite when only activating for some of the sites.

    3. Ipstenu (Mika Epstein) Avatar

      I wouldn’t use a loader. I write a main ‘mu-plugin’ file (call it my-site-name.php) and in there I include the files in a folder I want to use. Basically I treat it like a giant, single plugin. Loaders make assumptions that may not fit with how other people are using MU plugins, so there’s a higher probability of conflicts.

      This site is a multisite and I have a check “If site 1, load this. If site 2, this. ALL sites, these.” Yes in an MU plugin 🙂

%d bloggers like this: