multisite-plugin-control/multisite-plugin-control.php
feibisi 8c1625388e Bump version to 1.9.2 and update requirements
Updated the plugin version to 1.9.2 and changed the minimum required WordPress version to 5.9 in the plugin header.
2025-07-09 23:19:45 +08:00

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.2
* Author: WPMultisite.com
* Author URI: https://wpmultisite.com
* Network: true
* Requires at least: 5.9
* 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.2');
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();