Created
August 14, 2020 18:49
-
-
Save wpmudev-sls/993abc94ce7adfc9021b092648ba8cae to your computer and use it in GitHub Desktop.
[General] - Force reinstall plugins & themes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: [General] - Force reinstall plugins & themes | |
* Plugin URI: https://premium.wpmudev.org/ | |
* Description: Provides ability to re-install all plugins and themes from WP repo. Helpful when trying to clean up site | |
* Author: Panos Lyrakis @ WPMUDEV | |
* Author URI: https://premium.wpmudev.org/ | |
* License: GPLv2 or later | |
*/ | |
/** | |
* This snippet adds options to force re-install all plugins and themes from the wp repo. | |
* It will not force re-install 3rd party plugins from repos other than https://wordpress.org/ | |
* | |
* Visit the updates page (yoursite.com/wp-admin/update-core.php) and at the bottom of that page there should be 2 additional lists | |
* First is the plugins list from where you can choose which ones you need to force re-install. | |
* Second list is the themes list from where you can choose which ones you need to force re-install. | |
* Upon successful install there will be a green checkmark and upon error (eg package is from different/premium repo) a red x mark | |
*/ | |
if ( ! defined( 'ABSPATH' ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) { | |
return; | |
} | |
if ( ! class_exists( 'WPMUDEV_Reinstall_Plugins_N_Themes' ) ) { | |
class WPMUDEV_Reinstall_Plugins_N_Themes { | |
private static $_instance = null; | |
private $loader_image = ''; | |
private $check_mark = '<span class="dashicons dashicons-yes" style="color:#28B463;"></span>'; | |
private $x_mark = '<span class="dashicons dashicons-no" style="color:#FF5632;"></span>'; | |
public static function get_instance() { | |
if ( is_null( self::$_instance ) ) { | |
self::$_instance = new self(); | |
} | |
return self::$_instance; | |
} | |
private function __construct() { | |
$this->loader_image = admin_url() . 'images/spinner.gif'; | |
add_action( 'core_upgrade_preamble', array( $this, 'inject_reinstaller' ) ); | |
add_action( 'wp_ajax_wpmudev_force_reinstall_item', array( $this, 'reinstall_item_ajax' ) ); | |
} | |
public function reinstall_item_ajax() { | |
$_post_data = @file_get_contents( 'php://input' ); | |
$post_data = json_decode( $_post_data ); | |
if ( ! isset( $post_data->nonce ) || ! wp_verify_nonce( $post_data->nonce , 'wpmudev_force_reinstall_item_nonce' ) ) { | |
$return = array( | |
'success' => false, | |
'message' => 'AJAX nonce is nonsence' | |
); | |
wp_send_json( $return ); | |
} | |
if ( ! isset( $post_data->args ) ) { | |
$return = array( | |
'success' => false, | |
'message' => 'Data Missing' | |
); | |
wp_send_json( $return ); | |
} | |
$item_name = $post_data->name; | |
$item_file = $post_data->file; | |
$action_type = $post_data->type; | |
$callback = "reinstall_{$action_type}"; | |
$args = json_decode( $post_data->args ); | |
$response = $this->{$callback}( $args->slug ); | |
$has_error = isset( $response[ 'errorMessage' ] ) && ! empty( $response[ 'errorMessage' ] ); | |
$error_msg = $has_error ? $response[ 'errorMessage' ] : ''; | |
$return = array( | |
'success' => true, | |
'item' => $item_file, | |
'has_error' => $has_error, | |
'error_msg' => $error_msg, | |
'package' => $item_file, | |
); | |
wp_send_json( $return ); | |
} | |
/** | |
* Reinstalls the theme | |
* @see Theme_Upgrader | |
* | |
* @param string $slug The slug of the package. | |
* @return array Array containing the `errorCode` key if installation fails | |
*/ | |
function reinstall_theme( $slug ) { | |
if ( empty( $slug ) ) { | |
return array( | |
'slug' => '', | |
'errorCode' => 'no_theme_specified', | |
'errorMessage' => __( 'No theme specified.' ), | |
); | |
} | |
$slug = sanitize_key( wp_unslash( $slug ) ); | |
$status = array( | |
'install' => 'theme', | |
'slug' => $slug, | |
); | |
if ( ! current_user_can( 'install_themes' ) ) { | |
$status['errorMessage'] = __( 'Sorry, you are not allowed to install themes on this site.' ); | |
return $status; | |
} | |
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; | |
include_once ABSPATH . 'wp-admin/includes/theme.php'; | |
$api = themes_api( | |
'theme_information', | |
array( | |
'slug' => $slug, | |
'fields' => array( 'sections' => false ), | |
) | |
); | |
if ( is_wp_error( $api ) ) { | |
$status['errorMessage'] = $api->get_error_message(); | |
return $status; | |
} | |
$skin = new WP_Ajax_Upgrader_Skin(); | |
$upgrader = new Theme_Upgrader( $skin ); | |
$result = $upgrader->install( $api->download_link, array( 'overwrite_package' => true ) ); | |
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { | |
$status['debug'] = $skin->get_upgrade_messages(); | |
} | |
if ( is_wp_error( $result ) ) { | |
$status['errorCode'] = $result->get_error_code(); | |
$status['errorMessage'] = $result->get_error_message(); | |
return $status; | |
} elseif ( is_wp_error( $skin->result ) ) { | |
$status['errorCode'] = $skin->result->get_error_code(); | |
$status['errorMessage'] = $skin->result->get_error_message(); | |
return $status; | |
} elseif ( $skin->get_errors()->has_errors() ) { | |
$status['errorMessage'] = $skin->get_error_messages(); | |
return $status; | |
} elseif ( is_null( $result ) ) { | |
global $wp_filesystem; | |
$status['errorCode'] = 'unable_to_connect_to_filesystem'; | |
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' ); | |
// Pass through the error from WP_Filesystem if one was raised. | |
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) { | |
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() ); | |
} | |
return $status; | |
} | |
$status['themeName'] = wp_get_theme( $slug )->get( 'Name' ); | |
/* | |
* See WP_Theme_Install_List_Table::_get_theme_status() if we wanted to check | |
* on post-installation status. | |
*/ | |
return $status; | |
} | |
/** | |
* Reinstalls the plugin | |
* @see Plugin_Upgrader | |
* | |
* @param string $slug The slug of the package. | |
* @return array Array containing the `errorCode` key if installation fails | |
*/ | |
function reinstall_plugin( $slug ) { | |
if ( empty( $slug ) ) { | |
return array( | |
'slug' => '', | |
'errorCode' => 'no_plugin_specified', | |
'errorMessage' => __( 'No plugin specified.' ), | |
); | |
} | |
$status = array( | |
'install' => 'plugin', | |
'slug' => sanitize_key( wp_unslash( $slug ) ), | |
); | |
if ( ! current_user_can( 'install_plugins' ) ) { | |
$status['errorMessage'] = __( 'Sorry, you are not allowed to install plugins on this site.' ); | |
return $status; | |
} | |
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; | |
include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; | |
$api = plugins_api( | |
'plugin_information', | |
array( | |
'slug' => sanitize_key( wp_unslash( $slug ) ), | |
'fields' => array( | |
'sections' => false, | |
), | |
) | |
); | |
if ( is_wp_error( $api ) ) { | |
$status['errorMessage'] = $api->get_error_message(); | |
return $status; | |
} | |
$status['pluginName'] = $api->name; | |
$skin = new WP_Ajax_Upgrader_Skin(); | |
$upgrader = new Plugin_Upgrader( $skin ); | |
$result = $upgrader->install( $api->download_link, array( 'overwrite_package' => true ) ); | |
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { | |
$status['debug'] = $skin->get_upgrade_messages(); | |
} | |
if ( is_wp_error( $result ) ) { | |
$status['errorCode'] = $result->get_error_code(); | |
$status['errorMessage'] = $result->get_error_message(); | |
return $status; | |
} elseif ( is_wp_error( $skin->result ) ) { | |
$status['errorCode'] = $skin->result->get_error_code(); | |
$status['errorMessage'] = $skin->result->get_error_message(); | |
return $status; | |
} elseif ( $skin->get_errors()->has_errors() ) { | |
$status['errorMessage'] = $skin->get_error_messages(); | |
return $status; | |
} elseif ( is_null( $result ) ) { | |
global $wp_filesystem; | |
$status['errorCode'] = 'unable_to_connect_to_filesystem'; | |
$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' ); | |
// Pass through the error from WP_Filesystem if one was raised. | |
if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) { | |
$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() ); | |
} | |
return $status; | |
} | |
$install_status = install_plugin_install_status( $api ); | |
if ( is_multisite() && current_user_can( 'manage_network_plugins' ) && 'import' !== $pagenow ) { | |
$status['activateUrl'] = add_query_arg( array( 'networkwide' => 1 ), $status['activateUrl'] ); | |
} | |
return $status; | |
} | |
public function inject_reinstaller() { | |
?> | |
<h1><?php _e( 'Force Re-install' ); ?></h1> | |
<h2><?php _e( 'Plugins' ); ?></h2> | |
<p><?php _e( 'Choose which plugin you want to force re-instal' ); ?></p> | |
<div class="wpmudev-reinstall-container"> | |
<?php echo $this->plugins_list(); ?> | |
</div> | |
<h2><?php _e( 'Themes' ); ?></h2> | |
<p><?php _e( 'Choose which themes you want to force re-instal' ); ?></p> | |
<div class="wpmudev-reinstall-container"> | |
<?php echo $this->themes_list(); ?> | |
</div> | |
<?php | |
wp_nonce_field( 'wpmudev_force_reinstall_item_nonce', 'wpmudev_force_reinstall_item_nonce' ); | |
$this->js(); | |
} | |
/** | |
* List all plugins | |
*/ | |
protected function plugins_list() { | |
$plugins = get_plugins(); | |
if ( empty( $plugins ) ) { | |
return '<p>' . __( 'No plugins found' ) . '</p>'; | |
} | |
ob_start(); | |
?> | |
<p> | |
<input | |
id="wpmudev-re-install-plugins" | |
class="button wpmudev-re-installer" | |
data-type = "plugin" | |
type="submit" | |
value="<?php esc_attr_e( 'Re-install Plugins' ); ?>" | |
/> | |
</p> | |
<table class="widefat re-install-table" id="update-plugins-table"> | |
<thead> | |
<tr> | |
<td class="manage-column check-column"><input type="checkbox" class="reinstall-check-all" id="reinstall-plugins-select-all" /></td> | |
<td class="manage-column"><label for="reinstall-plugins-select-all"><?php _e( 'Select All' ); ?></label></td> | |
</tr> | |
</thead> | |
<tbody class="plugins-body"> | |
<?php | |
foreach ( (array) $plugins as $plugin_file => $plugin_data ) { | |
$plugin_name = $plugin_data['Name']; | |
$version_str = sprintf( __( '(Version: %s)' ), $plugin_data['Version'] ); | |
$slug = dirname( plugin_basename( $plugin_file ) ); | |
$args = array( | |
'plugin' => $plugin_file, | |
'slug' => $slug, | |
'action' => 'update-plugin', | |
'username' => '', | |
'password' => '', | |
'connection_type' => '', | |
'public_key' => '', | |
'private_key' => '', | |
); | |
?> | |
<tr> | |
<td class="<?php echo "{$slug}-column"; ?>"> | |
<input | |
type="checkbox" | |
class="reinstall-checkbox" | |
data-type="plugin" | |
data-file="<?php echo esc_attr( $plugin_file ); ?>" | |
data-name="<?php echo esc_attr( $plugin_name ); ?>" | |
data-version="<?php echo esc_attr( $plugin_data['Version'] ); ?>" | |
data-args='<?php echo json_encode( $args ); ?>' | |
id="plugin_box_<?php echo esc_attr( $plugin_file ); ?>" | |
/> | |
</td> | |
<td> | |
<label for="plugin_box_<?php echo $plugin_file; ?>"> | |
<?php echo "<strong>{$plugin_name}</strong> {$version_str}"; ?> | |
</label> | |
</td> | |
</tr> | |
<?php | |
} | |
?> | |
</tbody> | |
</table> | |
<p> | |
<input | |
id="wpmudev-re-install-plugins-2" | |
class="button wpmudev-re-installer" | |
data-type = "plugins" | |
type="submit" | |
value="<?php esc_attr_e( 'Re-install Plugins' ); ?>" | |
/> | |
</p> | |
<?php | |
return ob_get_clean(); | |
} | |
/** | |
* List all themes | |
*/ | |
protected function themes_list() { | |
$themes = wp_get_themes(); | |
if ( empty( $themes ) ) { | |
return '<p>' . __( 'No themes found' ) . '</p>'; | |
} | |
ob_start(); | |
?> | |
<p> | |
<input | |
id="wpmudev-re-install-themes" | |
class="button wpmudev-re-installer" | |
data-type = "theme" | |
type="submit" | |
value="<?php esc_attr_e( 'Re-install Themes' ); ?>" | |
/> | |
</p> | |
<table class="widefat re-install-table" id="update-themes-table"> | |
<thead> | |
<tr> | |
<td class="manage-column check-column"><input type="checkbox" class="reinstall-check-all" id="reinstall-themes-select-all" /></td> | |
<td class="manage-column"><label for="reinstall-themes-select-all"><?php _e( 'Select All' ); ?></label></td> | |
</tr> | |
</thead> | |
<tbody class="themes-body"> | |
<?php | |
foreach ( (array) $themes as $theme_slug => $theme ) { | |
$theme_name = $theme->name; | |
$version_str = sprintf( __( '(Version: %s)' ), $theme->version ); | |
$args = array( | |
'slug' => $theme_slug, | |
'action' => 'update-theme', | |
'username' => '', | |
'password' => '', | |
'connection_type' => '', | |
'public_key' => '', | |
'private_key' => '', | |
); | |
?> | |
<tr> | |
<td class="<?php echo "{$theme_slug}-column"; ?>"> | |
<input | |
type="checkbox" | |
class="reinstall-checkbox" | |
data-type="theme" | |
data-file="<?php echo esc_attr( $theme_slug ); ?>" | |
data-name="<?php echo esc_attr( $theme_name ); ?>" | |
data-version="<?php echo esc_attr( $theme->version ); ?>" | |
data-args='<?php echo json_encode( $args ); ?>' | |
id="theme_box_<?php echo esc_attr( $theme_slug ); ?>" | |
/> | |
</td> | |
<td> | |
<label for="theme_box_<?php echo $theme_slug; ?>"> | |
<?php echo "<strong>{$theme_name}</strong> {$version_str}"; ?> | |
</label> | |
</td> | |
</tr> | |
<?php | |
} | |
?> | |
</tbody> | |
</table> | |
<p> | |
<input | |
id="wpmudev-re-install-themes-2" | |
class="button wpmudev-re-installer" | |
data-type = "theme" | |
type="submit" | |
value="<?php esc_attr_e( 'Re-install Themes' ); ?>" | |
/> | |
</p> | |
<?php | |
return ob_get_clean(); | |
} | |
/** | |
* Prints the js that handles the UI actions and ajax calls | |
*/ | |
protected function js() { | |
?> | |
<script type="text/javascript"> | |
((d)=>{ | |
if ( ! window.wpmudev_force_reinstaller ) { | |
window.wpmudev_force_reinstaller = { | |
loader_image: '<?php echo $this->loader_image; ?>', | |
check_mark: '<?php echo $this->check_mark; ?>', | |
x_mark: '<?php echo $this->x_mark; ?>', | |
run: function(){ | |
let _self = wpmudev_force_reinstaller, | |
check_all = document.querySelectorAll( 'table.re-install-table input.reinstall-check-all' ), | |
buttons = document.querySelectorAll( '.wpmudev-re-installer' ); | |
for( let i = 0; i < check_all.length; i++ ) { | |
check_all[i].addEventListener( 'change', _self.toggle_select_all ); | |
} | |
for ( let i =0; i < buttons.length; i++ ) { | |
buttons[i].addEventListener( 'click', _self.force_update ); | |
} | |
}, | |
force_update : async function( event ) { | |
let _self = wpmudev_force_reinstaller, | |
element = event.target, | |
container = element.closest( '.wpmudev-reinstall-container' ), | |
table = container.querySelector( 'table.re-install-table' ), | |
checkboxes = table.querySelectorAll( 'input.reinstall-checkbox:checked' ); | |
for ( let i = 0; i < checkboxes.length; i++ ) { | |
let done = await _self.force_update_single( checkboxes[i] ); | |
} | |
}, | |
force_update_single : async function( item ) { | |
let _self = wpmudev_force_reinstaller, | |
type = item.getAttribute( 'data-type' ), | |
name = item.getAttribute( 'data-name' ), | |
file = item.getAttribute( 'data-file' ), | |
version = item.getAttribute( 'data-version' ), | |
args = item.getAttribute( 'data-args' ), | |
column = item.closest( 'td' ), | |
body = { | |
type : type, | |
name : name, | |
file : file, | |
version : version, | |
args : args, | |
nonce : d.querySelector( '#wpmudev_force_reinstall_item_nonce' ).value | |
}; | |
column.innerHTML = '<img src="' + _self.loader_image + '">'; | |
const response = await fetch( `${window.ajaxurl}?action=wpmudev_force_reinstall_item`, { | |
method: 'POST', // or 'PUT' | |
body: JSON.stringify( body ) | |
}); | |
let json = await response.json(); | |
if ( json.success ) { | |
if ( json.has_error ) { | |
column.innerHTML = _self.x_mark; | |
} else { | |
column.innerHTML = _self.check_mark; | |
} | |
} | |
}, | |
toggle_select_all : function( event ){ | |
let element = event.target, | |
table = element.closest( 'table.re-install-table' ), | |
checkboxes = table.querySelectorAll( 'input.reinstall-checkbox' ); | |
if ( element.checked ) { | |
for( let i = 0; i < checkboxes.length; i++ ) { | |
checkboxes[i].checked = true; | |
} | |
} else { | |
for( let i = 0; i < checkboxes.length; i++ ) { | |
checkboxes[i].checked = false; | |
} | |
} | |
} | |
} | |
// Check if the DOMContentLoaded has already been completed | |
if (d.readyState !== 'loading') { | |
wpmudev_force_reinstaller.run(); | |
} else { | |
d.addEventListener('DOMContentLoaded', wpmudev_force_reinstaller.run); | |
} | |
} | |
})(document); | |
</script> | |
<?php | |
} | |
} | |
if ( ! function_exists( 'wpmudev_reinstall_plugins_n_themes' ) ) { | |
function wpmudev_reinstall_plugins_n_themes() { | |
return WPMUDEV_Reinstall_Plugins_N_Themes::get_instance(); | |
}; | |
add_action( 'plugins_loaded', 'wpmudev_reinstall_plugins_n_themes', 10 ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment