Improved plugin security and compatibility
This commit is contained in:
@ -8,10 +8,16 @@
|
|||||||
* License: GPL-2.0+
|
* License: GPL-2.0+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
class Plugin_Reference_Cleaner {
|
class Plugin_Reference_Cleaner {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
// Hook into admin notices to modify plugin error messages
|
// Hook into admin notices to modify plugin error messages
|
||||||
add_action('admin_notices', array($this, 'inject_remove_button'), 100);
|
add_action('admin_notices', array($this, 'inject_remove_button'), 100);
|
||||||
|
add_action('network_admin_notices', array($this, 'inject_remove_button'), 100); // Ensure notices in network admin
|
||||||
// Handle the AJAX request to remove the plugin reference
|
// Handle the AJAX request to remove the plugin reference
|
||||||
add_action('wp_ajax_remove_plugin_reference', array($this, 'remove_plugin_reference'));
|
add_action('wp_ajax_remove_plugin_reference', array($this, 'remove_plugin_reference'));
|
||||||
}
|
}
|
||||||
@ -21,7 +27,7 @@ class Plugin_Reference_Cleaner {
|
|||||||
global $pagenow;
|
global $pagenow;
|
||||||
|
|
||||||
// Only run on plugins.php or network admin plugins page
|
// Only run on plugins.php or network admin plugins page
|
||||||
if (!in_array($pagenow, array('plugins.php', 'network/plugins.php'))) {
|
if (!in_array($pagenow, array('plugins.php', 'plugins.php'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,18 +36,20 @@ class Plugin_Reference_Cleaner {
|
|||||||
$has_error_notice = false;
|
$has_error_notice = false;
|
||||||
$plugin_files = array();
|
$plugin_files = array();
|
||||||
|
|
||||||
foreach ($notices as $notice) {
|
if (!empty($notices)) {
|
||||||
if (strpos($notice, 'has been deactivated due to an error: Plugin file does not exist') !== false) {
|
foreach ($notices as $notice) {
|
||||||
// Extract plugin file from notice
|
if (strpos($notice, 'has been deactivated due to an error: Plugin file does not exist') !== false) {
|
||||||
if (preg_match('/The plugin ([^ ]+)/', $notice, $match)) {
|
// Extract plugin file from notice
|
||||||
$plugin_files[] = $match[1];
|
if (preg_match('/The plugin ([^ ]+)/', $notice, $match)) {
|
||||||
$has_error_notice = true;
|
$plugin_files[] = $match[1];
|
||||||
|
$has_error_notice = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only proceed if a relevant notice was found
|
// Only proceed if a relevant notice was found
|
||||||
if (!$has_error_notice) {
|
if (!$has_error_notice || empty($plugin_files)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +57,13 @@ class Plugin_Reference_Cleaner {
|
|||||||
?>
|
?>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
var pluginFiles = <?php echo json_encode($plugin_files); ?>;
|
var pluginFiles = <?php echo wp_json_encode($plugin_files); ?>;
|
||||||
var notices = document.querySelectorAll('.notice-error p');
|
var notices = document.querySelectorAll('.notice-error p');
|
||||||
|
|
||||||
|
if (notices.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
notices.forEach(function(notice) {
|
notices.forEach(function(notice) {
|
||||||
pluginFiles.forEach(function(pluginFile) {
|
pluginFiles.forEach(function(pluginFile) {
|
||||||
if (notice.textContent.includes('The plugin ' + pluginFile)) {
|
if (notice.textContent.includes('The plugin ' + pluginFile)) {
|
||||||
@ -70,16 +83,29 @@ class Plugin_Reference_Cleaner {
|
|||||||
var pluginFile = this.dataset.plugin;
|
var pluginFile = this.dataset.plugin;
|
||||||
if (confirm('Are you sure you want to remove the reference to ' + pluginFile + '?')) {
|
if (confirm('Are you sure you want to remove the reference to ' + pluginFile + '?')) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', '<?php echo admin_url('admin-ajax.php'); ?>', true);
|
xhr.open('POST', '<?php echo esc_url(admin_url('admin-ajax.php')); ?>', true);
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
xhr.onload = function() {
|
xhr.onload = function() {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
alert('Plugin reference removed successfully.');
|
try {
|
||||||
location.reload();
|
var response = JSON.parse(xhr.responseText);
|
||||||
|
if (response.success) {
|
||||||
|
alert('Plugin reference removed successfully.');
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Failed to remove plugin reference: ' + (response.data || 'Unknown error'));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert('Failed to parse server response.');
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert('Failed to remove plugin reference.');
|
alert('Failed to remove plugin reference. Server returned status ' + xhr.status);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
xhr.onerror = function() {
|
||||||
|
alert('Network error occurred while trying to remove plugin reference.');
|
||||||
|
};
|
||||||
xhr.send('action=remove_plugin_reference&plugin=' + encodeURIComponent(pluginFile) + '&nonce=<?php echo wp_create_nonce('remove_plugin_reference'); ?>');
|
xhr.send('action=remove_plugin_reference&plugin=' + encodeURIComponent(pluginFile) + '&nonce=<?php echo wp_create_nonce('remove_plugin_reference'); ?>');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -93,48 +119,67 @@ class Plugin_Reference_Cleaner {
|
|||||||
private function get_admin_notices() {
|
private function get_admin_notices() {
|
||||||
ob_start();
|
ob_start();
|
||||||
do_action('admin_notices');
|
do_action('admin_notices');
|
||||||
|
do_action('network_admin_notices');
|
||||||
$output = ob_get_clean();
|
$output = ob_get_clean();
|
||||||
|
|
||||||
|
if (empty($output)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
return array_filter(explode("\n", $output));
|
return array_filter(explode("\n", $output));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the AJAX request to remove the plugin reference
|
// Handle the AJAX request to remove the plugin reference
|
||||||
public function remove_plugin_reference() {
|
public function remove_plugin_reference() {
|
||||||
|
// Verify nonce
|
||||||
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'remove_plugin_reference')) {
|
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'remove_plugin_reference')) {
|
||||||
wp_send_json_error('Invalid nonce');
|
wp_send_json_error('Invalid security token. Please refresh the page and try again.');
|
||||||
wp_die();
|
wp_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check user permissions
|
||||||
if (!current_user_can('activate_plugins')) {
|
if (!current_user_can('activate_plugins')) {
|
||||||
wp_send_json_error('Insufficient permissions');
|
wp_send_json_error('You do not have sufficient permissions to perform this action.');
|
||||||
wp_die();
|
wp_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get and validate plugin file parameter
|
||||||
$plugin_file = isset($_POST['plugin']) ? sanitize_text_field($_POST['plugin']) : '';
|
$plugin_file = isset($_POST['plugin']) ? sanitize_text_field($_POST['plugin']) : '';
|
||||||
if (empty($plugin_file)) {
|
if (empty($plugin_file)) {
|
||||||
wp_send_json_error('No plugin specified');
|
wp_send_json_error('No plugin specified.');
|
||||||
wp_die();
|
wp_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
|
||||||
|
// Handle multisite network admin
|
||||||
if (is_multisite() && is_network_admin()) {
|
if (is_multisite() && is_network_admin()) {
|
||||||
$active_plugins = get_site_option('active_sitewide_plugins', array());
|
$active_plugins = get_site_option('active_sitewide_plugins', array());
|
||||||
if (isset($active_plugins[$plugin_file])) {
|
if (isset($active_plugins[$plugin_file])) {
|
||||||
unset($active_plugins[$plugin_file]);
|
unset($active_plugins[$plugin_file]);
|
||||||
update_site_option('active_sitewide_plugins', $active_plugins);
|
$success = update_site_option('active_sitewide_plugins', $active_plugins);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
$site_id = get_current_blog_id();
|
// Handle single site or multisite subsite
|
||||||
$active_plugins = get_blog_option($site_id, 'active_plugins', array());
|
else {
|
||||||
|
$active_plugins = get_option('active_plugins', array());
|
||||||
$key = array_search($plugin_file, $active_plugins);
|
$key = array_search($plugin_file, $active_plugins);
|
||||||
if ($key !== false) {
|
if ($key !== false) {
|
||||||
unset($active_plugins[$key]);
|
unset($active_plugins[$key]);
|
||||||
$active_plugins = array_values($active_plugins);
|
$active_plugins = array_values($active_plugins); // Re-index array
|
||||||
update_blog_option($site_id, 'active_plugins', $active_plugins);
|
$success = update_option('active_plugins', $active_plugins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_send_json_success('Plugin reference removed');
|
if ($success) {
|
||||||
|
wp_send_json_success('Plugin reference removed successfully.');
|
||||||
|
} else {
|
||||||
|
wp_send_json_error('Plugin reference not found or could not be removed.');
|
||||||
|
}
|
||||||
|
|
||||||
wp_die();
|
wp_die();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the plugin
|
||||||
new Plugin_Reference_Cleaner();
|
new Plugin_Reference_Cleaner();
|
Reference in New Issue
Block a user