How to Prevent Deactivation of Important Plugins?

Often when writing additional functionality for a website, we use plugins to speed up development. Those who create custom websites have probably encountered a situation where an overly meticulous and curious client would disable a necessary plugin, causing the site to lose essential functionality or simply stop working.

To avoid such issues, you can simply remove the "deactivate" button for the plugins that are essential for the site to function. You can also remove the checkbox to prevent deactivation of plugins through bulk actions.

The screenshot shows:

  • The absence of the "deactivate" button and checkbox for the plugins: Advanced Custom Fields PRO, Contact Form 7.

  • The removal of the "Edit" button for all plugins. This button can also be removed by defining the constant DISALLOW_FILE_EDIT, thereby completely prohibiting file editing.

All of this is done simply through the plugin_action_links hook:

add_filter( 'plugin_action_links', 'disable_plugin_deactivation', 10, 2 );
function disable_plugin_deactivation( $actions, $plugin_file ) {

	// Removes the "Edit" action for all plugins
	unset( $actions['edit'] );

	// Removes the "Deactivate" action for important plugins for the site
	$important_plugins = array(
		'advanced-custom-fields-pro/acf.php',
		'contact-form-7/wp-contact-form-7.php',
	);
	if ( in_array( $plugin_file, $important_plugins ) ) {
		unset( $actions['deactivate'] );
		$actions[ 'info' ] = '<b class="musthave_js">Essential for the site</b>';
	}

	return $actions;
}

// Remove bulk actions: deactivate and delete
add_filter( 'admin_print_footer_scripts-plugins.php', 'disable_plugin_deactivation_hide_checkbox' );
function disable_plugin_deactivation_hide_checkbox( $actions ){
	?>
	<script>
	document.querySelectorAll( '.musthave_js' ).forEach( function( element ){
		element.closest( 'tr' ).querySelector( 'input[type="checkbox"]' ).remove();
	} );
	</script>
	<?php
}

By the way, note that for unset(), there is no need to check for the existence of the key in the array. If the key is absent, we will not see a PHP notice level error! This is a peculiarity of unset().

Thus, from the array of all links that should be displayed, we have removed the link for editing the plugin and its deactivation. For a better understanding, let's take a look at the contents of the variables passed to the hook.

  • $actions - array of links:

    Array (
    	[0] => <a href="http://skinali.dev/wp-admin/admin.php?page=wpcf7">Settings</a>
    	[deactivate] => <a href="plugins.php?action=deactivate&plugin=contact-form-7%2Fwp-contact-form-7.php&plugin_status=active&paged=1&s&_wpnonce=5fe6035ae5" aria-label="Deactivate Contact Form 7">Deactivate</a>
    	[edit] => <a href="plugin-editor.php?file=contact-form-7%2Fwp-contact-form-7.php" class="edit" aria-label="Edit Contact Form 7">Edit</a>
    )
  • $plugin_file - path to the main plugin file in the format plugin-folder/file-name, i.e., from the plugins folder.

    contact-form-7/wp-contact-form-7.php

    A simple way to get this path is to copy it from the data-plugin attribute by viewing the page source:

-

Change the list of important plugins in the variable $important_plugins and forget about unnecessary problems from the client.