Skip to content

Instantly share code, notes, and snippets.

@wpmudev-sls
Created August 14, 2020 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wpmudev-sls/993abc94ce7adfc9021b092648ba8cae to your computer and use it in GitHub Desktop.
Save wpmudev-sls/993abc94ce7adfc9021b092648ba8cae to your computer and use it in GitHub Desktop.
[General] - Force reinstall plugins & themes
<?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