Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement migration logic and UI from Performance Lab modules to their standalone plugins #899

Merged
merged 15 commits into from
Dec 18, 2023
Merged
107 changes: 100 additions & 7 deletions admin/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ function perflab_load_modules_page( $modules = null, $focus_areas = null ) {
// Handle script enqueuing for settings page.
add_action( 'admin_enqueue_scripts', 'perflab_enqueue_modules_page_scripts' );

// Handle style for settings page.
add_action( 'admin_head', 'perflab_print_modules_page_style' );

// Handle admin notices for settings page.
add_action( 'admin_notices', 'perflab_plugin_admin_notices' );

// Register sections for all focus areas, plus 'Other'.
if ( ! is_array( $focus_areas ) ) {
$focus_areas = perflab_get_focus_areas();
Expand Down Expand Up @@ -531,6 +537,35 @@ function perflab_enqueue_modules_page_scripts() {
wp_enqueue_style( 'thickbox' );

wp_enqueue_script( 'plugin-install' );

// Bail early if module is not active.
$get_active_modules_with_standalone_plugins = perflab_get_active_modules_with_standalone_plugins();
if ( empty( $get_active_modules_with_standalone_plugins ) ) {
return;
}

wp_enqueue_script(
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
'perflab-module-migration-notice',
plugin_dir_url( __FILE__ ) . 'perflab-module-migration-notice.js',
array(),
'1.0.0',
array(
'strategy' => 'defer',
)
);

wp_localize_script(
'perflab-module-migration-notice',
'perflab_module_migration_notice',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'perflab-install-activate-plugins' ),
'has_permission' => current_user_can( 'install_plugins' ) && current_user_can( 'activate_plugins' ),
'permission_error' => esc_html__( 'Sorry, you are not allowed to manage plugins for this site. Please contact the administrator.', 'performance-lab' ),
'network_error' => esc_html__( 'Network response was not ok.', 'performance-lab' ),
'prompt_message' => esc_html__( 'Are you sure you want to migrate legacy modules to standalone plugins?', 'performance-lab' ),
)
);
}

/**
Expand Down Expand Up @@ -613,14 +648,8 @@ function perflab_deactivate_plugin() {
* Callback function hooked to admin_notices to render plugin activate/deactivate notices.
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
*
* @since n.e.x.t
*
* @return void
*/
function perflab_plugin_admin_notices() {
if ( 'settings_page_perflab-modules' !== get_current_screen()->id ) {
return;
}

if ( isset( $_GET['activate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
?>
<div class="notice notice-success is-dismissible">
Expand All @@ -634,5 +663,69 @@ function perflab_plugin_admin_notices() {
</div>
<?php
}

$active_modules_with_plugins = perflab_get_active_modules_with_standalone_plugins();

if ( ! empty( $active_modules_with_plugins ) ) {
$module_data = perflab_get_modules();
$available_modules_list = array();
foreach ( $active_modules_with_plugins as $module_slug ) {
if ( isset( $module_data[ $module_slug ] ) && ! perflab_is_standalone_plugin_loaded( $module_slug ) ) {
$available_modules_list[] = $module_data[ $module_slug ]['name'];
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
}
}

$modules_count = count( $available_modules_list );
if ( $modules_count < 1 ) {
return;
}

if ( 1 === $modules_count ) {
$message = '<p>';
$message .= sprintf(
/* translators: Module name */
esc_html__( 'Performance Lab has detected usage of "%s" module that have standalone plugin equivalents. Installing and activating a performance plugin will disable the legacy module equivalent. This will not impact functionality of the module.', 'performance-lab' ),
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
esc_attr( $available_modules_list[0] )
);
$message .= '</p>';
} else {
$message = '<p>' . esc_html__( 'Performance Lab has detected usage of modules that have standalone plugin equivalents. Please see the available plugins below. Installing and activating a performance plugin will disable the legacy module equivalent. This will not impact functionality of the module.', 'performance-lab' ) . '</p>';
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
$message .= '<strong>' . esc_html__( 'Available standalone plugins:', 'performance-lab' ) . '</strong>';
$message .= '<ol>';
foreach ( $available_modules_list as $names ) {
$message .= sprintf( '<li>%s</li>', esc_html( $names ) );
}
$message .= '</ol>';
}

echo '<div class="notice notice-warning is-dismissible">';
echo wp_kses_post( $message );
echo '<p class="perflab-button-wrapper">';
echo '<button type="button" class="button button-primary perflab-install-active-plugin">';
echo esc_html__( 'Migrate legacy modules to standalone plugins', 'performance-lab' );
echo '</button>';
echo '<span class="dashicons dashicons-update hidden"></span>';
echo '</p>';
echo '</div>';
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* Callback function to handle admin inline style.
*
* @since n.e.x.t
*/
function perflab_print_modules_page_style() {
?>
<style type="text/css">
.perflab-button-wrapper {
display: flex;
align-items: center;
}
.perflab-button-wrapper span {
animation: rotation 2s infinite linear;
margin-left: 5px;
}
</style>
<?php
}
add_action( 'admin_notices', 'perflab_plugin_admin_notices' );
44 changes: 44 additions & 0 deletions admin/perflab-module-migration-notice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
( function( document ) {
document.addEventListener( 'DOMContentLoaded', function() {
document.addEventListener( 'click', function(event) {
if ( event.target.classList.contains( 'perflab-install-active-plugin' ) ) {
if ( ! perflab_module_migration_notice.has_permission ) {
alert( perflab_module_migration_notice.permission_error );
return;
}

if ( confirm( perflab_module_migration_notice.prompt_message ) ) {
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
var target = event.target;
target.parentElement.querySelector( 'span' ).classList.remove( 'hidden' );

var data = new FormData();
data.append( 'action', 'perflab_install_activate_standalone_plugins' );
data.append( 'nonce', perflab_module_migration_notice.nonce );

fetch( perflab_module_migration_notice.ajaxurl, {
method: 'POST',
credentials: 'same-origin',
body: data
})
.then( function ( response ) {
if ( ! response.ok ) {
throw new Error( perflab_module_migration_notice.network_error );
}
return response.json();
})
.then( function( result ) {
target.parentElement.querySelector( 'span' ).classList.add( 'hidden' );
if ( result.error ) {
alert( result.data.errorMessage );
}
window.location.reload();
})
.catch( function( error ) {
alert( error.errorMessage );
window.location.reload();
});
}
}
});
});
} )( document );
121 changes: 118 additions & 3 deletions admin/plugins.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,37 @@ function perflab_get_standalone_plugins() {
);
}

/**
* Returns an array mapping of standalone plugins main file to existing wpp modules.
*
* @since n.e.x.t
*
* @return string[]
*/
function perflab_get_standalone_plugins_file_map() {
return array(
'webp-uploads' => 'webp-uploads/load.php',
'dominant-color-images' => 'dominant-color-images/load.php',
);
}
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns an array of standalone plugins with currently active modules.
*
* @since n.e.x.t
*
* @return string[]
*/
function perflab_get_active_modules_with_standalone_plugins() {
$modules = perflab_get_module_settings();
return array_filter(
array_keys( perflab_get_standalone_plugins_constants() ),
static function ( $v ) use ( $modules ) {
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
return ! empty( $modules[ $v ] ) && $modules[ $v ]['enabled'];
}
);
}

/**
* Renders plugin UI for managing standalone plugins within PL Settings screen.
*
Expand All @@ -64,10 +95,16 @@ function perflab_render_plugins_ui() {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
require_once ABSPATH . 'wp-admin/includes/plugin.php';

$standalone_plugins = array();
$standalone_plugins = array();
$get_active_modules_with_standalone_plugins = perflab_get_active_modules_with_standalone_plugins();
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
foreach ( perflab_get_standalone_plugins() as $managed_standalone_plugin_slug ) {
$standalone_plugins[ $managed_standalone_plugin_slug ] = array(
'plugin_data' => perflab_query_plugin_info( $managed_standalone_plugin_slug ),
'plugin_data' => array_merge(
perflab_query_plugin_info( $managed_standalone_plugin_slug ),
array(
'perflab_has_enabled_module' => ! empty( $get_active_modules_with_standalone_plugins[ $managed_standalone_plugin_slug ] ),
)
),
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
);
}

Expand Down Expand Up @@ -138,7 +175,6 @@ function perflab_render_plugin_card( array $plugin_data ) {
$action_links = array();

$status = install_plugin_install_status( $plugin_data );

switch ( $status['status'] ) {
case 'install':
if ( $status['url'] ) {
Expand Down Expand Up @@ -390,3 +426,82 @@ function perflab_render_plugin_card( array $plugin_data ) {
</div>
<?php
}

// WordPress AJAX action to handle the button click event.
add_action( 'wp_ajax_perflab_install_activate_standalone_plugins', 'perflab_install_activate_standalone_plugins_callback' );

/**
* Handles the standalone plugin install and activation via AJAX.
*
* @since n.e.x.t
*/
function perflab_install_activate_standalone_plugins_callback() {
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'perflab-install-activate-plugins' ) ) {
$status['errorMessage'] = esc_html__( 'Invalid nonce: Please refresh and try again.', 'performance-lab' );
wp_send_json_error( $status );
}

mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
if ( ! function_exists( 'plugins_api' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
}
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';

$get_standalone_plugins_file_map = perflab_get_standalone_plugins_file_map();
$plugins_to_activate = perflab_get_active_modules_with_standalone_plugins();
$plugins = get_plugins();
$status = array();

foreach ( $plugins_to_activate as $module_slug ) {

// Skip checking for already activated plugin.
if ( perflab_is_standalone_plugin_loaded( $module_slug ) ) {
continue;
}

$plugin_slug = basename( $module_slug );
$api = perflab_query_plugin_info( $plugin_slug );
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
$plugin_slug = isset( $get_standalone_plugins_file_map[ $plugin_slug ] ) ? $get_standalone_plugins_file_map[ $plugin_slug ] : '';
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved

if ( ! $plugin_slug ) {
$status['errorMessage'] = esc_html__( 'Invalid plugin.', 'performance-lab' );
wp_send_json_error( $status );
}

// Check if the plugin is already installed.
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
if ( ! isset( $plugins[ $plugin_slug ] ) ) {
$plugin_path = WP_PLUGIN_DIR . '/' . $plugin_slug;

// Check if the plugin file exists.
if ( ! file_exists( $plugin_path ) ) {
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
// Replace new Plugin_Installer_Skin with new Quiet_Upgrader_Skin when output needs to be suppressed.
$skin = new WP_Ajax_Upgrader_Skin( array( 'api' => $api ) );
$upgrader = new Plugin_Upgrader( $skin );
$result = $upgrader->install( $api['download_link'] );

if ( is_wp_error( $result ) ) {
$status['errorMessage'] = $result->get_error_message();
wp_send_json_error( $status );
} elseif ( is_wp_error( $skin->result ) ) {
$status['errorMessage'] = $skin->result->get_error_message();
wp_send_json_error( $status );
} elseif ( $skin->get_errors()->has_errors() ) {
$status['errorMessage'] = $skin->get_error_messages();
wp_send_json_error( $status );
}
}
}

$result = activate_plugin( $plugin_slug );
mukeshpanchal27 marked this conversation as resolved.
Show resolved Hide resolved
if ( is_wp_error( $result ) ) {
$status['errorMessage'] = $result->get_error_message();
wp_send_json_error( $status );
}

// Deactivate legacy modules.
unset( $modules[ $module_slug ] );

update_option( PERFLAB_MODULES_SETTING, $modules );
}
wp_send_json_success( $status );
}