Skip to content

Instantly share code, notes, and snippets.

@wpmudev-sls
Last active September 22, 2024 04:34
Show Gist options
  • Save wpmudev-sls/939ab23dc2cfd00049ce30b8d0b76798 to your computer and use it in GitHub Desktop.
Save wpmudev-sls/939ab23dc2cfd00049ce30b8d0b76798 to your computer and use it in GitHub Desktop.
[SmartCrawl Pro] Bulk-apply config to subsites
<?php
/**
* Plugin Name: [SmartCrawl Pro] Bulk-apply config to subsites
* Description: Adds an "Apply subsite config" link in the SmartCrawl network admin menu with a page to bulk-apply settings to subsites
* Author: Anderson Salas @ WPMUDEV
* Task: SLS-6513
* Author URI: https://premium.wpmudev.org
* License: GPLv2 or later
*/
add_action( 'plugins_loaded', function() {
if ( ! defined( 'SMARTCRAWL_VERSION' ) ) {
return; // SmartCrawl is not installed/enabled.
}
if ( class_exists( 'SmartCrawl_Subsite_Bulk_Config' ) ) {
return; // Already loaded.
}
class SmartCrawl_Subsite_Bulk_Config {
const NONCE = 'wds_network_site_bulk_config';
private static $instance;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
public function add_sc_submenu_item() {
add_submenu_page(
\SmartCrawl\Admin\Pages\Network_Settings::MENU_SLUG,
'Apply subsite config',
'Apply subsite config',
'manage_network_options',
'wds_network_site_bulk_config',
[ $this, 'admin_page' ],
99
);
}
public function __construct() {
if ( is_admin() && 'wds_network_site_bulk_config' === ( $_GET['page'] ?? '' ) ) {
add_action( 'admin_enqueue_scripts', function() {
wp_enqueue_style( 'wds-app' );
wp_enqueue_script( 'wds-shared-ui' );
});
add_filter( 'admin_body_class', function( $class ) {
return ( $class ?? '' ) . ' sui-' . str_ireplace( '.', '-', SMARTCRAWL_SUI_VERSION ) . ' ';
});
}
add_action( 'network_admin_menu', [ $this, 'add_sc_submenu_item' ], 99 );
add_action( 'admin_footer', [ $this, 'admin_importer_scripts' ] );
add_action( 'wp_ajax_wds_network_site_bulk_config', [ $this, 'ajax_handle_config' ] );
}
public function admin_importer_scripts() {
?>
<script>( function( $ ) {
$( '.sc-begin-import' ).click( function() {
$( this ).addClass( 'disabled' );
$( '.import-spinner' ).addClass( 'is-active' );
var data = {
'_wpnonce' : $( 'form#config-form input[name="_wpnonce"]' ).val(),
'config_id' : $( 'form#config-form select[name="config_id"]' ).val(),
'sites' : $( 'form#config-form input[name="sites[]"]:checked' ).map(function() {
return $(this).val();
}).get(),
'action' : 'wds_network_site_bulk_config'
};
$.post( ajaxurl, data, function( response ) {
if ( ! response.success ) {
alert( response.data.error );
} else {
alert( response.data.message );
}
}).fail( function() {
alert( 'An error occurred.' );
}).always( function() {
$( '.sc-begin-import' ).removeClass( 'disabled' );
$( '.import-spinner' ).removeClass( 'is-active' );
});
});
var _validate = function() {
$( '.sc-begin-import' ).removeClass( 'disabled' );
if ( 0 === $('input.site-checkbox:checked').length || '' === $('select[name="config_id"]').val() ) {
$( '.sc-begin-import' ).addClass( 'disabled' );
}
}
$( '.sc-select-all' ).click( function(e) {
e.preventDefault();
$( '.site-checkbox' ).prop('checked', true);
_validate();
});
$( '.sc-select-clear' ).click( function(e) {
e.preventDefault();
$( '.site-checkbox' ).prop('checked', false);
_validate();
});
$('input.site-checkbox, select[name="config_id"]').on( 'change', _validate);
_validate();
})( window.jQuery )</script>
<style>
.label-site, .label-site small {
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
display: block !important;
max-width: 515px;
}
</style>
<?php
}
public function admin_page() {
$configs = \SmartCrawl\Configs\Collection::get()->get_deflated_configs();
$sites = get_sites();
?>
<div class="sui-wrap">
<div class="sui-box" style="max-width:650px;">
<div class="sui-box-header">
<h2 class="sui-box-title">
<span class="sui-icon-widget-settings-config" aria-hidden="true"></span> Apply subsite config
</h2>
</div>
<?php if ( ! is_multisite() ) { ?>
<div class="sui-box-body">
<p>This tool is compatible only with multisite installations.</p>
</div>
<?php } else { ?>
<form id="config-form" method="post">
<div class="sui-box-body">
<?php wp_nonce_field( self::NONCE ); ?>
<p style="margin-top: 0">Select a config and click <strong>Apply Config</strong> to bulk-apply it to the desired subsites. Do not close this browser tab until the process is done.</p>
<div class="sui-form-field">
<label class="sui-label">Config name</label>
<select id="config-selector" class="sui-select" name="config_id">
<option value="">Select a config...</option>
<?php foreach( $configs as $config ) { ?>
<option value="<?php echo $config['id']; ?>"><?php echo $config['name']; ?></option>
<?php } ?>
</select>
</div>
<label class="sui-label" style="display:block;">
Target subsites
<span style="float:right">
<a href="#" class="sc-select-all" style="display: inline-block; margin-right: 10px">[Select all]</a>
<a href="#" class="sc-select-clear">[Clear]</a>
</span>
</label>
<div style="display:block;border: 1px solid #ddd;padding: 15px;max-height: 232px;overflow-y: auto;">
<?php
foreach( $sites as $site ) {
$site_details = get_blog_details( $site->blog_id );
?>
<div style="display:block">
<label for="site_<?php echo $site->blog_id; ?>" class="sui-checkbox">
<input type="checkbox" checked="checked" name="sites[]" value="<?php echo $site->blog_id; ?>" id="site_<?php echo $site->blog_id; ?>" class="site-checkbox" />
<span aria-hidden="true"></span>
<span id="label-site_<?php echo $site->blog_id; ?>" class="label-site">
<?php echo $site_details->blogname; ?><br /><small><?php echo $site_details->siteurl; ?></small>
</span>
</label>
</div>
<?php } ?>
</div>
<div class="sui-notice sui-notice-warning" style="margin-top:25px">
<div class="sui-notice-content">
<div class="sui-notice-message">
<span class="sui-notice-icon sui-icon-warning-alert sui-md" aria-hidden="true"></span>
<p><strong>WARNING: Any existing config will be OVERWRITTEN.</strong><br />It is highly recommended that you <a href="https://wpmudev.com/docs/hosting/backups/" target="_blank">create a backup</a> and test this tool on a <a href="https://wpmudev.com/docs/hosting/staging/" target="_blank">Staging Site</a> first.</p>
</div>
</div>
</div>
</div>
<div class="sui-box-footer">
<input type="button" name="submit" id="submit" class="sui-button sui-button-blue sc-begin-import" value="Apply Config" />
<div class="spinner import-spinner" style="float:none; width:auto; height:auto; padding: 10px 0 10px 20px; margin-top: 0; margin-left:0"></div>
</div>
</form>
<?php } ?>
</div>
</div>
<?php
}
private function do_bulk_config() {
$processed = 0;
if ( empty( $_POST['config_id'] ) ) {
wp_send_json_error( [ 'error' => 'Invalid or missing parameter: config_id' ] );
}
$config_id = sanitize_text_field( $_POST['config_id'] );
$sites = [];
if ( empty( $_POST['sites'] ) || ! is_array( $_POST['sites'] ) ) {
wp_send_json_error( [ 'error' => 'Invalid or missing parameter: sites' ] );
}
foreach( $_POST['sites'] as $site_id ) {
$sites[] = intval( $site_id );
}
if ( empty( $sites ) ) {
wp_send_json_error( [ 'error' => 'Invalid or missing parameter: sites' ] );
}
$config = \SmartCrawl\Configs\Collection::get()->get_by_id( $config_id );
if ( ! $config ) {
wp_send_json_error( [ 'error' => 'Failed to retrieve config_id: ' . $config_id ] );
}
$sc_config_controller = \SmartCrawl\Configs\Controller::get();
foreach( get_sites() as $site ) {
$blog_id = (int) $site->blog_id;
if ( ! in_array( $blog_id, $sites, true ) ) {
continue;
}
switch_to_blog( $blog_id );
$sc_config_controller->apply_handler( $config->get_configs() );
$processed++;
}
restore_current_blog();
return $processed;
}
public function ajax_handle_config() {
if ( empty( $_POST[ '_wpnonce' ] ) || ! wp_verify_nonce( $_POST[ '_wpnonce' ], self::NONCE ) ) {
wp_send_json_error( [ 'error' => 'Invalid nonce.' ] );
}
if ( ! current_user_can( 'manage_network_options' ) ) {
wp_send_json_error( [ 'error' => 'Not allowed.' ] );
}
if ( ! is_multisite() ) {
wp_send_json_error( [ 'error' => 'This tool is not compatible with single-site installations.' ] );
}
$total = $this->do_bulk_config();
wp_send_json_success( [ 'message' => 'The bulk-config has been completed successfully! (Total sites: ' . $total . ')'] );
}
}
SmartCrawl_Subsite_Bulk_Config::get_instance();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment