Let’s face it, not all of us work in ideal situations. Some of us can create a site for a client, create only one administrator, and leave the client with lower privileges so that they are always at our mercy.
Other times you decide to throw up Multisite just so the client can technically be an administrator, but cannot update, add, or edit plugins and themes (much less update WordPress).
Admins, admins, everywhere!
The world I live in, everybody’s an admin. Sure, it’s not an ideal solution at all, but you have to work with what you have, right?
Today I created a snippet (with a lot of borrowed code) that will disable the plugin/theme editors, and will also disable updates from showing. All you have to do is throw it into your theme’s functions.php file.
I would guess that most of the clients, copywriters, etc, do not know the power that they hold when they are administrators. This snippet simply “hides” some of that power.
Disable by default, but allow enabling
Now if an admin really knows what they’re doing, they can “opt-in” to the plugin/theme editor and WordPress upgrade notices.
All the admin has to do is go to their user profile and select which options to opt-in on.
So in a nutshell, this snippet (by default) disables:
- The ability to edit, delete, install, or update plugins.
- The ability to edit, delete, install, or update themes.
- The ability to upgrade WordPress. All notices are hidden.

Here be the code!
View it on GitHub or browse below.
<?php | |
//Tested in a theme's functions.php, but not in a plugin | |
//Allow overriding of editor | |
class opubco_user_optin { | |
public function __construct() { | |
add_action( 'personal_options', array( &$this, 'add_interface' ) ); | |
//User update action | |
add_action( 'edit_user_profile_update', array( &$this, 'save_user_profile' ) ); | |
add_action( 'personal_options_update', array( &$this, 'save_user_profile' ) ); | |
//Override caps | |
add_filter( 'map_meta_cap', array( &$this, 'map_meta_cap' ), 11, 4 ); | |
} | |
public function map_meta_cap( $caps, $cap, $user_id, $args ) { | |
if ( $cap == 'edit_plugins' || $cap == 'install_plugins' || $cap == 'delete_plugins' ) { | |
if ( current_user_can( 'administrator' ) && 'on' == get_user_option( 'opubco_plugin_editor', $user_id ) ) { | |
return array(); | |
} else { | |
return array( 'do_not_allow' ); | |
} | |
} | |
if ( $cap == 'edit_themes' || $cap == 'install_themes' || $cap == 'delete_themes') { | |
if ( current_user_can( 'administrator' ) && 'on' == get_user_option( 'opubco_theme_editor', $user_id ) ) { | |
return array(); | |
} else { | |
return array( 'do_not_allow' ); | |
} | |
} | |
return $caps; | |
} | |
public function add_interface() { | |
if ( !current_user_can( 'administrator' ) ) return; | |
$user_id = $this->get_user_id(); | |
?> | |
</table> | |
<h3>Administrator Opt-in</h3> | |
<table class="form-table"> | |
<tr valign="top"> | |
<th scope="row"><?php esc_html_e( "Allow Editors", "opubco" ); ?></th> | |
<td> | |
<input type="checkbox" name="opt-in-plugin-editor" id="opt-in-plugin-editor" value="on" <?php checked( 'on', get_user_option( 'opubco_plugin_editor', $user_id ) ); ?> /><label for="opt-in-plugin-editor"> Allow plugin editor?</label> | |
<br /><br /> | |
<input type="checkbox" name="opt-in-theme-editor" id="opt-in-theme-editor" value="on" <?php checked( 'on', get_user_option( 'opubco_theme_editor', $user_id ) ); ?> /><label for="opt-in-theme-editor"> Allow theme editor?</label> | |
</td> | |
</tr> | |
<tr valign="top"> | |
<th scope="row"><?php esc_html_e( "WordPress Updates", "opubco" ); ?></th> | |
<td> | |
<input type="checkbox" name="opt-in-updates" id="opt-in-updates" value="on" <?php checked( 'on', get_user_option( 'opubco_wordpress_updates', $user_id ) ); ?> /><label for="opt-in-updates"> Show WordPress updates?</label> | |
</td> | |
</tr> | |
</table> | |
<?php | |
} //end add_interface | |
/** | |
* get_user_id | |
* | |
* Gets a user ID for the user | |
* | |
*@return int user_id | |
* | |
@return int post_id | |
*/ | |
private function get_user_id() { | |
//Get user ID | |
$user_id = isset( $_GET[ 'user_id' ] ) ? absint( $_GET[ 'user_id' ] ) : 0; | |
if ( $user_id == 0 && IS_PROFILE_PAGE ) { | |
$current_user = wp_get_current_user(); | |
$user_id = $current_user->ID; | |
} | |
return $user_id; | |
} //end get_user_id | |
public function save_user_profile( $user_id ) { | |
check_admin_referer( 'update-user_' . $user_id ); | |
if ( !current_user_can( 'administrator' ) ) return; | |
$user_meta = array(); | |
$user_meta[ 'opubco_plugin_editor' ] = isset( $_POST[ 'opt-in-plugin-editor' ] ) ? 'on' : 'off'; | |
$user_meta[ 'opubco_theme_editor' ] = isset( $_POST[ 'opt-in-theme-editor' ] ) ? 'on' : 'off'; | |
$user_meta[ 'opubco_wordpress_updates' ] = isset( $_POST[ 'opt-in-updates' ] ) ? 'on' : 'off'; | |
foreach( $user_meta as $meta_key => $meta_value ) { | |
update_user_option( $user_id, $meta_key, $meta_value ); | |
} | |
} | |
} | |
//From https://wordpress.org/plugins/disable-wordpress-updates/ | |
class opubco_disable_updates { | |
/** | |
* The OS_Disable_WordPress_Updates class constructor | |
* initializing required stuff for the plugin | |
* | |
* PHP 5 Constructor | |
* | |
* @since 1.3 | |
* @author scripts@schloebe.de | |
*/ | |
function __construct() { | |
if ( current_user_can( 'administrator' ) ) { | |
$current_user = wp_get_current_user(); | |
$user_id = $current_user->ID; | |
if ( 'on' == get_user_option( 'opubco_wordpress_updates', $user_id ) ) { | |
return; | |
} | |
} | |
add_action('admin_init', array(&$this, 'admin_init')); | |
/* | |
* Disable Theme Updates | |
* 2.8 to 3.0 | |
*/ | |
add_filter( 'pre_transient_update_themes', array($this, 'last_checked_now') ); | |
/* | |
* 3.0 | |
*/ | |
add_filter( 'pre_site_transient_update_themes', array($this, 'last_checked_now') ); | |
/* | |
* Disable Plugin Updates | |
* 2.8 to 3.0 | |
*/ | |
add_action( 'pre_transient_update_plugins', array(&$this, 'last_checked_now') ); | |
/* | |
* 3.0 | |
*/ | |
add_filter( 'pre_site_transient_update_plugins', array($this, 'last_checked_now') ); | |
/* | |
* Disable Core Updates | |
* 2.8 to 3.0 | |
*/ | |
add_filter( 'pre_transient_update_core', array($this, 'last_checked_now') ); | |
/* | |
* 3.0 | |
*/ | |
add_filter( 'pre_site_transient_update_core', array($this, 'last_checked_now') ); | |
/* | |
* Disable All Automatic Updates | |
* 3.7+ | |
* | |
* @author sLa NGjI's @ slangji.wordpress.com | |
*/ | |
add_filter( 'auto_update_translation', '__return_false' ); | |
add_filter( 'automatic_updater_disabled', '__return_true' ); | |
add_filter( 'allow_minor_auto_core_updates', '__return_false' ); | |
add_filter( 'allow_major_auto_core_updates', '__return_false' ); | |
add_filter( 'allow_dev_auto_core_updates', '__return_false' ); | |
add_filter( 'auto_update_core', '__return_false' ); | |
add_filter( 'wp_auto_update_core', '__return_false' ); | |
add_filter( 'auto_core_update_send_email', '__return_false' ); | |
add_filter( 'send_core_update_notification_email', '__return_false' ); | |
add_filter( 'auto_update_plugin', '__return_false' ); | |
add_filter( 'auto_update_theme', '__return_false' ); | |
add_filter( 'automatic_updates_send_debug_email', '__return_false' ); | |
add_filter( 'automatic_updates_is_vcs_checkout', '__return_true' ); | |
} | |
/** | |
* The OS_Disable_WordPress_Updates class constructor | |
* initializing required stuff for the plugin | |
* | |
* PHP 4 Compatible Constructor | |
* | |
* @since 1.3 | |
* @author scripts@schloebe.de | |
*/ | |
function opubco_disable_updates() { | |
$this->__construct(); | |
} | |
/** | |
* Initialize and load the plugin stuff | |
* | |
* @since 1.3 | |
* @author scripts@schloebe.de | |
*/ | |
function admin_init() { | |
if ( !function_exists("remove_action") ) return; | |
/* | |
* Disable Theme Updates | |
* 2.8 to 3.0 | |
*/ | |
remove_action( 'load-themes.php', 'wp_update_themes' ); | |
remove_action( 'load-update.php', 'wp_update_themes' ); | |
remove_action( 'admin_init', '_maybe_update_themes' ); | |
remove_action( 'wp_update_themes', 'wp_update_themes' ); | |
wp_clear_scheduled_hook( 'wp_update_themes' ); | |
/* | |
* 3.0 | |
*/ | |
remove_action( 'load-update-core.php', 'wp_update_themes' ); | |
wp_clear_scheduled_hook( 'wp_update_themes' ); | |
/* | |
* Disable Plugin Updates | |
* 2.8 to 3.0 | |
*/ | |
remove_action( 'load-plugins.php', 'wp_update_plugins' ); | |
remove_action( 'load-update.php', 'wp_update_plugins' ); | |
remove_action( 'admin_init', '_maybe_update_plugins' ); | |
remove_action( 'wp_update_plugins', 'wp_update_plugins' ); | |
wp_clear_scheduled_hook( 'wp_update_plugins' ); | |
/* | |
* 3.0 | |
*/ | |
remove_action( 'load-update-core.php', 'wp_update_plugins' ); | |
wp_clear_scheduled_hook( 'wp_update_plugins' ); | |
/* | |
* Disable Core Updates | |
* 2.8 to 3.0 | |
*/ | |
remove_action( 'wp_version_check', 'wp_version_check' ); | |
remove_action( 'admin_init', '_maybe_update_core' ); | |
wp_clear_scheduled_hook( 'wp_version_check' ); | |
/* | |
* 3.0 | |
*/ | |
wp_clear_scheduled_hook( 'wp_version_check' ); | |
/* | |
* 3.7+ | |
*/ | |
remove_action( 'wp_maybe_auto_update', 'wp_maybe_auto_update' ); | |
remove_action( 'admin_init', 'wp_maybe_auto_update' ); | |
remove_action( 'admin_init', 'wp_auto_update_core' ); | |
wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); | |
} | |
/** | |
* Get version check info | |
* | |
* @since 1.3.1 | |
* @author flynsarmy (props & kudos!) | |
* @link http://wordpress.org/support/topic/patch-incorrect-disabling-of-updates | |
*/ | |
public function last_checked_now( $transient ) { | |
include ABSPATH . WPINC . '/version.php'; | |
$current = new stdClass; | |
$current->updates = array(); | |
$current->version_checked = $wp_version; | |
$current->last_checked = time(); | |
return $current; | |
} | |
} | |
new opubco_user_optin(); | |
new opubco_disable_updates(); |