mirror of
https://github.com/WPMultisite/multisite-plugin-control.git
synced 2025-08-03 21:49:47 +08:00
742 lines
No EOL
38 KiB
PHP
742 lines
No EOL
38 KiB
PHP
<?php
|
|
/*
|
|
* Plugin Name: Multisite Plugin Control
|
|
* Plugin URI: https://wpmultisite.com/plugins/multisite-plugin-control
|
|
* Description: Manage plugin access permissions across your entire WordPress multisite network with enhanced UI and statistics.
|
|
* Version: 1.9.1
|
|
* Author: WPMultisite.com
|
|
* Author URI: https://wpmultisite.com
|
|
* Network: true
|
|
* Requires at least: 6.7.2
|
|
* License: GPL v2 or later
|
|
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
|
* Text Domain: multisite-plugin-control
|
|
* Domain Path: /languages
|
|
*/
|
|
|
|
if (!defined('WPINC')) {
|
|
die;
|
|
}
|
|
|
|
define('MULTISITE_PLUGIN_CONTROL_VERSION', '1.9.1');
|
|
define('MULTISITE_PLUGIN_CONTROL_PATH', plugin_dir_path(__FILE__));
|
|
define('MULTISITE_PLUGIN_CONTROL_URL', plugin_dir_url(__FILE__));
|
|
|
|
|
|
require_once plugin_dir_path(__FILE__) . 'class-plugin-report.php';
|
|
|
|
class MultisitePluginControl {
|
|
private $stats;
|
|
private $plugin_report;
|
|
|
|
public function __construct() {
|
|
$this->stats = get_site_option('mpc_stats', [
|
|
'total_sites' => 0,
|
|
'total_activations' => 0,
|
|
'total_deactivations' => 0,
|
|
'last_action_time' => null
|
|
]);
|
|
$this->plugin_report = new RT_Plugin_Report($this);
|
|
$this->plugin_report->init();
|
|
|
|
add_action('network_admin_menu', [$this, 'add_menu']);
|
|
add_action('wpmu_new_blog', [$this, 'new_blog'], 50);
|
|
if (!(defined('WP_CLI') && WP_CLI)) {
|
|
add_filter('all_plugins', [$this, 'remove_plugins']);
|
|
}
|
|
add_filter('plugin_action_links', [$this, 'action_links'], 10, 4);
|
|
add_action('admin_notices', [$this, 'supporter_message']);
|
|
add_action('plugins_loaded', [$this, 'localization']);
|
|
add_action('wpmueditblogaction', [$this, 'blog_options_form']);
|
|
add_action('wpmu_update_blog_options', [$this, 'blog_options_form_process']);
|
|
add_filter('plugin_row_meta', [$this, 'remove_plugin_meta'], 10, 2);
|
|
add_action('admin_init', [$this, 'remove_plugin_update_row']);
|
|
add_action('wp_ajax_mpc_save_settings', [$this, 'ajax_save_settings']);
|
|
add_action('wp_ajax_mpc_mass_activate', [$this, 'ajax_mass_activate']);
|
|
add_action('wp_ajax_mpc_mass_deactivate', [$this, 'ajax_mass_deactivate']);
|
|
}
|
|
|
|
public function localization() {
|
|
load_plugin_textdomain('multisite-plugin-control', false, dirname(plugin_basename(__FILE__)) . '/languages/');
|
|
}
|
|
|
|
public function add_menu() {
|
|
add_submenu_page(
|
|
'plugins.php',
|
|
__('Plugin Control', 'multisite-plugin-control'),
|
|
__('Plugin Control', 'multisite-plugin-control'),
|
|
'manage_network_options',
|
|
'multisite-plugin-control',
|
|
[$this, 'admin_page']
|
|
);
|
|
}
|
|
|
|
public function admin_page() {
|
|
if (!current_user_can('manage_network_options')) {
|
|
wp_die(__('You do not have sufficient permissions to access this page.', 'multisite-plugin-control'));
|
|
}
|
|
|
|
$active_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'management';
|
|
?>
|
|
<div class="wrap">
|
|
<h1><?php echo esc_html__('Multisite Plugin Control', 'multisite-plugin-control'); ?>
|
|
<span style="font-size: 13px; padding-left: 10px;"><?php printf(esc_html__('Version: %s', 'multisite-plugin-control'), esc_html(MULTISITE_PLUGIN_CONTROL_VERSION)); ?></span>
|
|
<a href="https://wpmultisite.com/document/multisite-plugin-control" target="_blank" class="button button-secondary" style="margin-left: 10px;"><?php esc_html_e('Document', 'multisite-plugin-control'); ?></a>
|
|
<a href="https://wpmultisite.com/forums/" target="_blank" class="button button-secondary"><?php esc_html_e('Support', 'multisite-plugin-control'); ?></a>
|
|
</h1>
|
|
<div class="card">
|
|
<h2><?php _e('Plugin Dashboard', 'multisite-plugin-control'); ?></h2>
|
|
<span id="save-status" class="notice" style="display:none; margin-top: 10px;"></span>
|
|
<p><?php _e('Manage plugin access permissions across your multisite network.', 'multisite-plugin-control'); ?></p>
|
|
|
|
<div class="styles-sync-tabs">
|
|
<button type="button" class="styles-tab <?php echo $active_tab === 'management' ? 'active' : ''; ?>" data-tab="management"><?php _e('Plugin Management', 'multisite-plugin-control'); ?></button>
|
|
<button type="button" class="styles-tab <?php echo $active_tab === 'usage' ? 'active' : ''; ?>" data-tab="usage"><?php _e('Plugin Usage', 'multisite-plugin-control'); ?></button>
|
|
<button type="button" class="styles-tab <?php echo $active_tab === 'report' ? 'active' : ''; ?>" data-tab="report"><?php _e('Plugin Report', 'multisite-plugin-control'); ?></button>
|
|
<button type="button" class="styles-tab <?php echo $active_tab === 'help' ? 'active' : ''; ?>" data-tab="help"><?php _e('Help', 'multisite-plugin-control'); ?></button>
|
|
</div>
|
|
|
|
<div class="styles-sync-content">
|
|
<div class="tab-section" data-section="management" style="<?php echo $active_tab !== 'management' ? 'display: none;' : ''; ?>">
|
|
<div style="margin-bottom: 20px;">
|
|
<input type="text" id="plugin-search" placeholder="<?php _e('Search plugins by name...', 'multisite-plugin-control'); ?>" style="width: 300px;">
|
|
<select id="plugin-filter" style="margin-left: 10px;">
|
|
<option value="all"><?php _e('All Statuses', 'multisite-plugin-control'); ?></option>
|
|
<option value="none"><?php _e('None', 'multisite-plugin-control'); ?></option>
|
|
<option value="all"><?php _e('All Users', 'multisite-plugin-control'); ?></option>
|
|
<option value="auto"><?php _e('Auto-Activate', 'multisite-plugin-control'); ?></option>
|
|
<?php if (function_exists('is_pro_site')): ?>
|
|
<option value="supporters"><?php _e('Pro Sites', 'multisite-plugin-control'); ?></option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<form id="plugin-control-form" method="post">
|
|
<?php wp_nonce_field('multisite_plugin_control_nonce', 'control_nonce'); ?>
|
|
<table class="wp-list-table widefat fixed striped">
|
|
<thead>
|
|
<tr>
|
|
<th><input type="checkbox" id="select-all-plugins"></th>
|
|
<th><?php _e('Name', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Version', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Author', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('User Control', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Mass Activate', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Mass Deactivate', 'multisite-plugin-control'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php
|
|
$plugins = get_plugins();
|
|
$auto_activate = (array) get_site_option('mpc_auto_activate_list', []);
|
|
$user_control = (array) get_site_option('mpc_user_control_list', []);
|
|
$supporter_control = (array) get_site_option('mpc_supporter_control_list', []);
|
|
|
|
foreach ($plugins as $file => $p) {
|
|
if (is_network_only_plugin($file) || is_plugin_active_for_network($file)) {
|
|
continue;
|
|
}
|
|
$selected = 'none';
|
|
if (in_array($file, $user_control)) $selected = 'all';
|
|
elseif (in_array($file, $auto_activate)) $selected = 'auto';
|
|
elseif (in_array($file, $supporter_control)) $selected = 'supporters';
|
|
?>
|
|
<tr data-status="<?php echo esc_attr($selected); ?>">
|
|
<td><input type="checkbox" name="selected_plugins[]" value="<?php echo esc_attr($file); ?>" class="plugin-checkbox"></td>
|
|
<td><?php echo esc_html($p['Name']); ?></td>
|
|
<td><?php echo esc_html($p['Version']); ?></td>
|
|
<td><?php echo wp_kses_post($p['Author']); ?></td>
|
|
<td>
|
|
<select name="control[<?php echo esc_attr($file); ?>]" class="control-select">
|
|
<?php
|
|
$options = [
|
|
'none' => __('None', 'multisite-plugin-control'),
|
|
'all' => __('All Users', 'multisite-plugin-control'),
|
|
'auto' => __('Auto-Activate (All Users)', 'multisite-plugin-control'),
|
|
];
|
|
if (function_exists('is_pro_site')) {
|
|
$options['supporters'] = __('Pro Sites', 'multisite-plugin-control');
|
|
}
|
|
foreach ($options as $value => $label) {
|
|
$is_selected = ($selected === $value) ? ' selected="selected"' : '';
|
|
echo '<option value="' . esc_attr($value) . '"' . $is_selected . '>' . esc_html($label) . '</option>';
|
|
}
|
|
?>
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<button type="button" class="button mass-activate" data-plugin="<?php echo esc_attr($file); ?>">
|
|
<?php _e('Activate All', 'multisite-plugin-control'); ?>
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<button type="button" class="button mass-deactivate" data-plugin="<?php echo esc_attr($file); ?>">
|
|
<?php _e('Deactivate All', 'multisite-plugin-control'); ?>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
?>
|
|
</tbody>
|
|
</table>
|
|
<p class="submit">
|
|
<select id="bulk-action" style="margin-right: 10px;">
|
|
<option value=""><?php _e('Bulk Actions', 'multisite-plugin-control'); ?></option>
|
|
<option value="set-none"><?php _e('Set to None', 'multisite-plugin-control'); ?></option>
|
|
<option value="set-all"><?php _e('Set to All Users', 'multisite-plugin-control'); ?></option>
|
|
<option value="set-auto"><?php _e('Set to Auto-Activate', 'multisite-plugin-control'); ?></option>
|
|
<?php if (function_exists('is_pro_site')): ?>
|
|
<option value="set-supporters"><?php _e('Set to Pro Sites', 'multisite-plugin-control'); ?></option>
|
|
<?php endif; ?>
|
|
</select>
|
|
<button type="button" id="apply-bulk" class="button"><?php _e('Apply', 'multisite-plugin-control'); ?></button>
|
|
<button type="button" id="save-settings" class="button button-primary"><?php _e('Save Settings', 'multisite-plugin-control'); ?></button>
|
|
</p>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="tab-section" data-section="usage" style="<?php echo $active_tab !== 'usage' ? 'display: none;' : ''; ?>">
|
|
<p><?php _e('View plugin usage across the network.', 'multisite-plugin-control'); ?></p>
|
|
<?php
|
|
$usage_stats = $this->get_plugin_usage_stats();
|
|
if (isset($usage_stats['error'])) {
|
|
echo '<p class="description">' . esc_html($usage_stats['error']) . '</p>';
|
|
} else {
|
|
?>
|
|
<table class="wp-list-table widefat fixed striped">
|
|
<thead>
|
|
<tr>
|
|
<th><?php _e('Plugin Name', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Active Sites', 'multisite-plugin-control'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($usage_stats as $stats): ?>
|
|
<tr>
|
|
<td><?php echo esc_html($stats['name']); ?></td>
|
|
<td><?php echo esc_html($stats['active_sites']); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php
|
|
}
|
|
?>
|
|
</div>
|
|
|
|
<div class="tab-section" data-section="report" style="<?php echo $active_tab !== 'report' ? 'display: none;' : ''; ?>">
|
|
<?php $this->plugin_report->render_report(); ?>
|
|
</div>
|
|
|
|
<div class="tab-section" data-section="help" style="<?php echo $active_tab !== 'help' ? 'display: none;' : ''; ?>">
|
|
<p><strong><?php _e('Auto Activation', 'multisite-plugin-control'); ?></strong><br>
|
|
<?php _e('When enabled, new blogs will have the plugin activated automatically.', 'multisite-plugin-control'); ?></p>
|
|
<p><strong><?php _e('User Control', 'multisite-plugin-control'); ?></strong><br>
|
|
<?php
|
|
if (function_exists('is_pro_site')) {
|
|
_e('Choose who can activate/deactivate plugins: all users, Pro Sites only, or none.', 'multisite-plugin-control');
|
|
} else {
|
|
_e('Enable to allow all users to activate/deactivate plugins.', 'multisite-plugin-control');
|
|
}
|
|
?></p>
|
|
<p><strong><?php _e('Mass Activation/Deactivation', 'multisite-plugin-control'); ?></strong><br>
|
|
<?php _e('Activate or deactivate plugins across all existing blogs.', 'multisite-plugin-control'); ?></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2><?php _e('Statistics', 'multisite-plugin-control'); ?></h2>
|
|
<p><?php _e('View plugin control activity across the network.', 'multisite-plugin-control'); ?></p>
|
|
<table class="wp-list-table widefat fixed">
|
|
<thead>
|
|
<tr>
|
|
<th><?php _e('Metric', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Value', 'multisite-plugin-control'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<th><?php _e('Total Sites', 'multisite-plugin-control'); ?></th>
|
|
<td><?php echo esc_html($this->stats['total_sites']); ?></td>
|
|
</tr>
|
|
<tr>
|
|
<th><?php _e('Total Activations', 'multisite-plugin-control'); ?></th>
|
|
<td><?php echo esc_html($this->stats['total_activations']); ?></td>
|
|
</tr>
|
|
<tr>
|
|
<th><?php _e('Total Deactivations', 'multisite-plugin-control'); ?></th>
|
|
<td><?php echo esc_html($this->stats['total_deactivations']); ?></td>
|
|
</tr>
|
|
<tr>
|
|
<th><?php _e('Last Action Time', 'multisite-plugin-control'); ?></th>
|
|
<td><?php echo esc_html($this->stats['last_action_time'] ?: __('Never', 'multisite-plugin-control')); ?></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
jQuery(document).ready(function($) {
|
|
$('.styles-tab').on('click', function() {
|
|
var tab = $(this).data('tab');
|
|
window.history.pushState({}, document.title, '<?php echo admin_url('network/plugins.php?page=multisite-plugin-control'); ?>&tab=' + tab);
|
|
$('.styles-tab').removeClass('active');
|
|
$(this).addClass('active');
|
|
$('.tab-section').hide();
|
|
$('.tab-section[data-section="' + tab + '"]').show();
|
|
});
|
|
|
|
function filterPlugins() {
|
|
var search = $('#plugin-search').val().toLowerCase();
|
|
var filter = $('#plugin-filter').val();
|
|
$('.wp-list-table tbody tr').each(function() {
|
|
var name = $(this).find('td:eq(1)').text().toLowerCase();
|
|
var status = $(this).data('status');
|
|
var matchesSearch = search === '' || name.includes(search);
|
|
var matchesFilter = filter === 'all' || status === filter;
|
|
$(this).toggle(matchesSearch && matchesFilter);
|
|
});
|
|
}
|
|
$('#plugin-search').on('input', filterPlugins);
|
|
$('#plugin-filter').on('change', filterPlugins);
|
|
|
|
$('#select-all-plugins').on('change', function() {
|
|
$('.plugin-checkbox').prop('checked', $(this).prop('checked'));
|
|
});
|
|
|
|
$('#apply-bulk').on('click', function() {
|
|
var action = $('#bulk-action').val();
|
|
if (!action) return;
|
|
var selected = $('.plugin-checkbox:checked');
|
|
if (selected.length === 0) {
|
|
alert('<?php _e('Please select at least one plugin.', 'multisite-plugin-control'); ?>');
|
|
return;
|
|
}
|
|
selected.each(function() {
|
|
var plugin = $(this).val();
|
|
$('select[name="control[' + plugin + ']"]').val(action.replace('set-', ''));
|
|
});
|
|
});
|
|
|
|
$('#save-settings').on('click', function() {
|
|
var $button = $(this);
|
|
var formData = $('#plugin-control-form').serializeArray();
|
|
var settings = { control: {}, nonce: '' };
|
|
|
|
formData.forEach(function(item) {
|
|
if (item.name.startsWith('control[')) {
|
|
var plugin = item.name.replace('control[', '').replace(']', '');
|
|
settings.control[plugin] = item.value;
|
|
} else if (item.name === 'control_nonce') {
|
|
settings.nonce = item.value;
|
|
}
|
|
});
|
|
|
|
$button.prop('disabled', true);
|
|
$('#save-status').text('<?php _e('Saving...', 'multisite-plugin-control'); ?>').show();
|
|
|
|
$.ajax({
|
|
url: ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'mpc_save_settings',
|
|
settings: settings,
|
|
_ajax_nonce: settings.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#save-status')
|
|
.removeClass('notice-error')
|
|
.addClass('notice-success')
|
|
.text('<?php _e('Settings saved successfully!', 'multisite-plugin-control'); ?>')
|
|
.show()
|
|
.delay(3000)
|
|
.fadeOut();
|
|
$('.wp-list-table tbody tr').each(function() {
|
|
var plugin = $(this).find('.plugin-checkbox').val();
|
|
$(this).data('status', settings.control[plugin]);
|
|
});
|
|
} else {
|
|
$('#save-status')
|
|
.removeClass('notice-success')
|
|
.addClass('notice-error')
|
|
.text(response.data || '<?php _e('Failed to save settings.', 'multisite-plugin-control'); ?>')
|
|
.show();
|
|
}
|
|
$button.prop('disabled', false);
|
|
},
|
|
error: function() {
|
|
$('#save-status')
|
|
.removeClass('notice-success')
|
|
.addClass('notice-error')
|
|
.text('<?php _e('An error occurred while saving.', 'multisite-plugin-control'); ?>')
|
|
.show();
|
|
$button.prop('disabled', false);
|
|
}
|
|
});
|
|
});
|
|
|
|
$('.mass-activate, .mass-deactivate').on('click', function() {
|
|
var $button = $(this);
|
|
var plugin = $button.data('plugin');
|
|
var actionType = $button.hasClass('mass-activate') ? 'mass_activate' : 'mass_deactivate';
|
|
|
|
if (!confirm('<?php _e('Are you sure you want to '); ?>' + (actionType === 'mass_activate' ? '<?php _e('activate'); ?>' : '<?php _e('deactivate'); ?>') + ' <?php _e('this plugin across all sites?'); ?>')) {
|
|
return;
|
|
}
|
|
|
|
$button.prop('disabled', true);
|
|
$('#save-status').text('<?php _e('Processing...', 'multisite-plugin-control'); ?>').show();
|
|
|
|
$.ajax({
|
|
url: ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'mpc_' + actionType,
|
|
plugin: plugin,
|
|
_ajax_nonce: '<?php echo wp_create_nonce('multisite_plugin_control_nonce'); ?>'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#save-status')
|
|
.removeClass('notice-error')
|
|
.addClass('notice-success')
|
|
.text(response.data.message)
|
|
.show()
|
|
.delay(3000)
|
|
.fadeOut();
|
|
} else {
|
|
$('#save-status')
|
|
.removeClass('notice-success')
|
|
.addClass('notice-error')
|
|
.text(response.data || '<?php _e('Operation failed.', 'multisite-plugin-control'); ?>')
|
|
.show();
|
|
}
|
|
$button.prop('disabled', false);
|
|
},
|
|
error: function() {
|
|
$('#save-status')
|
|
.removeClass('notice-success')
|
|
.addClass('notice-error')
|
|
.text('<?php _e('Server error occurred.', 'multisite-plugin-control'); ?>')
|
|
.show();
|
|
$button.prop('disabled', false);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.card {
|
|
background: #fff;
|
|
border: 1px solid #ccd0d4;
|
|
border-radius: 4px;
|
|
max-width: unset;
|
|
margin-top: 20px;
|
|
padding: 20px;
|
|
}
|
|
.notice {
|
|
padding: 8px 12px;
|
|
border-radius: 3px;
|
|
}
|
|
.notice-success {
|
|
background-color: #dff0d8;
|
|
border-left: 4px solid #46b450;
|
|
}
|
|
.notice-error {
|
|
background-color: #f2dede;
|
|
border-left: 4px solid #dc3232;
|
|
}
|
|
.styles-sync-tabs {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 5px;
|
|
border-bottom: 1px solid #c3c4c7;
|
|
margin-bottom: 20px;
|
|
}
|
|
.styles-tab {
|
|
padding: 8px 16px;
|
|
border: none;
|
|
background: none;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
border-bottom: 2px solid transparent;
|
|
}
|
|
.styles-tab.active {
|
|
border-bottom: 2px solid #007cba;
|
|
font-weight: 600;
|
|
background: #f0f0f1;
|
|
}
|
|
.styles-tab:hover:not(.active) {
|
|
background: #f0f0f1;
|
|
border-bottom-color: #dcdcde;
|
|
}
|
|
.styles-sync-content {
|
|
flex: 1;
|
|
}
|
|
table.fixed {
|
|
table-layout: auto;
|
|
}
|
|
</style>
|
|
<?php
|
|
}
|
|
|
|
private function get_plugin_usage_stats() {
|
|
global $wpdb;
|
|
$plugins = get_plugins();
|
|
$usage_stats = [];
|
|
|
|
if (wp_is_large_network()) {
|
|
return ['error' => __('Network too large to calculate usage stats.', 'multisite-plugin-control')];
|
|
}
|
|
|
|
$blogs = $wpdb->get_col($wpdb->prepare("SELECT blog_id FROM {$wpdb->blogs} WHERE site_id = %d AND spam = 0", $wpdb->siteid));
|
|
foreach ($plugins as $file => $p) {
|
|
if (is_network_only_plugin($file) || is_plugin_active_for_network($file)) {
|
|
continue;
|
|
}
|
|
$count = 0;
|
|
foreach ($blogs as $blog_id) {
|
|
switch_to_blog($blog_id);
|
|
if (is_plugin_active($file)) {
|
|
$count++;
|
|
}
|
|
restore_current_blog();
|
|
}
|
|
$usage_stats[$file] = [
|
|
'name' => $p['Name'],
|
|
'active_sites' => $count
|
|
];
|
|
}
|
|
return $usage_stats;
|
|
}
|
|
|
|
public function ajax_save_settings() {
|
|
check_ajax_referer('multisite_plugin_control_nonce', '_ajax_nonce') || wp_send_json_error(__('Invalid nonce.', 'multisite-plugin-control'));
|
|
if (!current_user_can('manage_network_options')) wp_send_json_error(__('Permission denied.', 'multisite-plugin-control'));
|
|
|
|
$settings = isset($_POST['settings']['control']) ? (array)$_POST['settings']['control'] : [];
|
|
$supporter_control = [];
|
|
$user_control = [];
|
|
$auto_activate = [];
|
|
|
|
foreach ($settings as $plugin => $value) {
|
|
switch ($value) {
|
|
case 'supporters':
|
|
$supporter_control[] = sanitize_text_field($plugin);
|
|
break;
|
|
case 'all':
|
|
$user_control[] = sanitize_text_field($plugin);
|
|
break;
|
|
case 'auto':
|
|
$auto_activate[] = sanitize_text_field($plugin);
|
|
break;
|
|
}
|
|
}
|
|
|
|
update_site_option('mpc_supporter_control_list', $supporter_control ?: 'EMPTY');
|
|
update_site_option('mpc_user_control_list', $user_control ?: 'EMPTY');
|
|
update_site_option('mpc_auto_activate_list', $auto_activate ?: 'EMPTY');
|
|
|
|
wp_send_json_success(['message' => __('Settings saved successfully!', 'multisite-plugin-control')]);
|
|
}
|
|
|
|
public function ajax_mass_activate() {
|
|
check_ajax_referer('multisite_plugin_control_nonce', '_ajax_nonce') || wp_send_json_error(__('Invalid nonce.', 'multisite-plugin-control'));
|
|
if (!current_user_can('manage_network_options')) wp_send_json_error(__('Permission denied.', 'multisite-plugin-control'));
|
|
|
|
$plugin = sanitize_text_field($_POST['plugin']);
|
|
$this->mass_activate($plugin);
|
|
wp_send_json_success(['message' => sprintf(__('%s has been mass activated.', 'multisite-plugin-control'), $plugin)]);
|
|
}
|
|
|
|
public function ajax_mass_deactivate() {
|
|
check_ajax_referer('multisite_plugin_control_nonce', '_ajax_nonce') || wp_send_json_error(__('Invalid nonce.', 'multisite-plugin-control'));
|
|
if (!current_user_can('manage_network_options')) wp_send_json_error(__('Permission denied.', 'multisite-plugin-control'));
|
|
|
|
$plugin = sanitize_text_field($_POST['plugin']);
|
|
$this->mass_deactivate($plugin);
|
|
wp_send_json_success(['message' => sprintf(__('%s has been mass deactivated.', 'multisite-plugin-control'), $plugin)]);
|
|
}
|
|
|
|
public function mass_activate($plugin) {
|
|
global $wpdb;
|
|
|
|
if (wp_is_large_network()) {
|
|
add_settings_error('mpc_messages', 'mass_activate_fail', __('Network too large for mass activation.', 'multisite-plugin-control'), 'error');
|
|
return false;
|
|
}
|
|
|
|
set_time_limit(120);
|
|
$blogs = $wpdb->get_col($wpdb->prepare("SELECT blog_id FROM {$wpdb->blogs} WHERE site_id = %d AND spam = 0", $wpdb->siteid));
|
|
$count = 0;
|
|
|
|
if ($blogs) {
|
|
foreach ($blogs as $blog_id) {
|
|
switch_to_blog($blog_id);
|
|
if (!is_plugin_active($plugin)) {
|
|
activate_plugin($plugin, '', false);
|
|
$count++;
|
|
}
|
|
restore_current_blog();
|
|
}
|
|
$this->update_stats('activate', count($blogs), $count);
|
|
add_settings_error('mpc_messages', 'mass_activate_success', sprintf(__('%s activated on %d sites.', 'multisite-plugin-control'), esc_html($plugin), $count), 'success');
|
|
} else {
|
|
add_settings_error('mpc_messages', 'mass_activate_fail', __('Failed to select blogs.', 'multisite-plugin-control'), 'error');
|
|
}
|
|
}
|
|
|
|
public function mass_deactivate($plugin) {
|
|
global $wpdb;
|
|
|
|
if (wp_is_large_network()) {
|
|
add_settings_error('mpc_messages', 'mass_deactivate_fail', __('Network too large for mass deactivation.', 'multisite-plugin-control'), 'error');
|
|
return false;
|
|
}
|
|
|
|
set_time_limit(120);
|
|
$blogs = $wpdb->get_col($wpdb->prepare("SELECT blog_id FROM {$wpdb->blogs} WHERE site_id = %d AND spam = 0", $wpdb->siteid));
|
|
$count = 0;
|
|
|
|
if ($blogs) {
|
|
foreach ($blogs as $blog_id) {
|
|
switch_to_blog($blog_id);
|
|
if (is_plugin_active($plugin)) {
|
|
deactivate_plugins($plugin, true);
|
|
$count++;
|
|
}
|
|
restore_current_blog();
|
|
}
|
|
$this->update_stats('deactivate', count($blogs), $count);
|
|
add_settings_error('mpc_messages', 'mass_deactivate_success', sprintf(__('%s deactivated on %d sites.', 'multisite-plugin-control'), esc_html($plugin), $count), 'success');
|
|
} else {
|
|
add_settings_error('mpc_messages', 'mass_deactivate_fail', __('Failed to select blogs.', 'multisite-plugin-control'), 'error');
|
|
}
|
|
}
|
|
|
|
private function update_stats($action, $total_sites, $changed) {
|
|
$this->stats['total_sites'] = $total_sites;
|
|
if ($action === 'activate') {
|
|
$this->stats['total_activations'] += $changed;
|
|
} else {
|
|
$this->stats['total_deactivations'] += $changed;
|
|
}
|
|
$this->stats['last_action_time'] = current_time('mysql');
|
|
update_site_option('mpc_stats', $this->stats);
|
|
}
|
|
|
|
public function new_blog($blog_id) {
|
|
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
|
$auto_activate = (array) get_site_option('mpc_auto_activate_list', []);
|
|
if ($auto_activate && $auto_activate[0] !== 'EMPTY') {
|
|
switch_to_blog($blog_id);
|
|
activate_plugins($auto_activate, '', false);
|
|
restore_current_blog();
|
|
}
|
|
}
|
|
|
|
public function remove_plugins($all_plugins) {
|
|
if (is_super_admin()) return $all_plugins;
|
|
$auto_activate = (array) get_site_option('mpc_auto_activate_list', []);
|
|
$user_control = (array) get_site_option('mpc_user_control_list', []);
|
|
$supporter_control = (array) get_site_option('mpc_supporter_control_list', []);
|
|
$override_plugins = (array) get_option('mpc_plugin_override_list', []);
|
|
|
|
foreach ($all_plugins as $plugin_file => $plugin_data) {
|
|
if (!in_array($plugin_file, $user_control) && !in_array($plugin_file, $auto_activate) && !in_array($plugin_file, $supporter_control) && !in_array($plugin_file, $override_plugins)) {
|
|
unset($all_plugins[$plugin_file]);
|
|
}
|
|
}
|
|
return $all_plugins;
|
|
}
|
|
|
|
public function action_links($action_links, $plugin_file, $plugin_data, $context) {
|
|
global $psts, $blog_id;
|
|
if (is_network_admin() || is_super_admin()) return $action_links;
|
|
|
|
$auto_activate = (array) get_site_option('mpc_auto_activate_list', []);
|
|
$user_control = (array) get_site_option('mpc_user_control_list', []);
|
|
$supporter_control = (array) get_site_option('mpc_supporter_control_list', []);
|
|
$override_plugins = (array) get_option('mpc_plugin_override_list', []);
|
|
|
|
if ($context !== 'active') {
|
|
if (in_array($plugin_file, $user_control) || in_array($plugin_file, $auto_activate) || in_array($plugin_file, $override_plugins)) {
|
|
return $action_links;
|
|
} elseif (in_array($plugin_file, $supporter_control) && function_exists('is_pro_site')) {
|
|
return is_pro_site() ? $action_links : ['<a style="color:red;" href="' . esc_url($psts->checkout_url($blog_id)) . '">' . __('Pro Sites Only', 'multisite-plugin-control') . '</a>'];
|
|
}
|
|
}
|
|
return $action_links;
|
|
}
|
|
|
|
public function supporter_message() {
|
|
global $pagenow;
|
|
if (is_super_admin() || $pagenow !== 'plugins.php' || !function_exists('is_pro_site')) return;
|
|
if (!is_pro_site()) {
|
|
if (function_exists('supporter_feature_notice')) {
|
|
supporter_feature_notice();
|
|
}
|
|
} else {
|
|
echo '<div class="error" style="background-color:#F9F9F9;border:0;font-weight:bold;"><p>' . sprintf(__('As a %s Pro Site, you now have access to all our premium plugins!', 'multisite-plugin-control'), get_site_option('site_name')) . '</p></div>';
|
|
}
|
|
}
|
|
|
|
public function remove_plugin_meta($plugin_meta, $plugin_file) {
|
|
if (is_network_admin() || is_super_admin()) return $plugin_meta;
|
|
remove_all_actions("after_plugin_row_$plugin_file");
|
|
return [];
|
|
}
|
|
|
|
public function remove_plugin_update_row() {
|
|
if (!is_network_admin() && !is_super_admin()) {
|
|
remove_all_actions('after_plugin_row');
|
|
}
|
|
}
|
|
|
|
public function blog_options_form($blog_id) {
|
|
$plugins = get_plugins();
|
|
$override_plugins = (array) get_blog_option($blog_id, 'mpc_plugin_override_list', []);
|
|
?>
|
|
</table>
|
|
<h3><?php _e('Plugin Override Options', 'multisite-plugin-control'); ?></h3>
|
|
<p><?php _e('Checked plugins will override network settings for this site.', 'multisite-plugin-control'); ?></p>
|
|
<table class="widefat" style="margin:10px;width:95%;">
|
|
<thead>
|
|
<tr>
|
|
<th><?php _e('User Control', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Name', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Version', 'multisite-plugin-control'); ?></th>
|
|
<th><?php _e('Author', 'multisite-plugin-control'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php
|
|
foreach ($plugins as $file => $p) {
|
|
if (is_network_only_plugin($file) || is_plugin_active_for_network($file)) continue;
|
|
$checked = in_array($file, $override_plugins) ? 'checked="checked"' : '';
|
|
echo "<tr><td><label><input name='plugins[$file]' type='checkbox' value='1' $checked> " . __('Enable', 'multisite-plugin-control') . "</label></td><td>" . esc_html($p['Name']) . "</td><td>" . esc_html($p['Version']) . "</td><td>" . wp_kses_post($p['Author']) . "</td></tr>";
|
|
}
|
|
?>
|
|
</tbody>
|
|
</table>
|
|
<?php
|
|
}
|
|
|
|
public function blog_options_form_process() {
|
|
$override_plugins = [];
|
|
if (isset($_POST['plugins']) && is_array($_POST['plugins'])) {
|
|
foreach ($_POST['plugins'] as $plugin => $value) {
|
|
$override_plugins[] = sanitize_text_field($plugin);
|
|
}
|
|
}
|
|
update_option('mpc_plugin_override_list', $override_plugins);
|
|
}
|
|
}
|
|
|
|
new MultisitePluginControl();
|