diff --git a/class/class-mainwp-child-install.php b/class/class-mainwp-child-install.php
index c5cc2a6c..41e89c87 100644
--- a/class/class-mainwp-child-install.php
+++ b/class/class-mainwp-child-install.php
@@ -516,7 +516,7 @@ private function after_installed( $result, &$output ) { //phpcs:ignore -- NOSONA
continue;
}
$thePlugin = get_plugin_data( $path . $srcFile );
- if ( null !== $thePlugin && '' !== $thePlugin && '' !== $thePlugin['Name'] ) {
+ if ( null !== $thePlugin && '' !== $thePlugin && '' !== $thePlugin['Name'] && 'readme.txt' !== $srcFile && 'README.md' !== $srcFile ) { // to fix: skip readme.txt.
$args['type'] = 'plugin';
$args['Name'] = $thePlugin['Name'];
$args['Version'] = $thePlugin['Version'];
diff --git a/class/class-mainwp-child-updates.php b/class/class-mainwp-child-updates.php
index 712c8a54..2177fb02 100644
--- a/class/class-mainwp-child-updates.php
+++ b/class/class-mainwp-child-updates.php
@@ -137,6 +137,8 @@ public function upgrade_plugin_theme() {
);
MainWP_Child_Actions::get_instance()->init_custom_hooks( $hooks );
+ static::enable_pre_auto_rollback_hooking();
+
$plugin_update = false;
// phpcs:disable WordPress.Security.NonceVerification
if ( isset( $_POST['type'] ) && 'plugin' === $_POST['type'] ) {
@@ -382,8 +384,9 @@ private function to_update_plugins( &$information, $plugins ) { //phpcs:ignore -
$updated_plugins = array();
foreach ( $result as $plugin => $info ) {
- $success = false;
- $error = '';
+ $success = false;
+ $problematic_update = false;
+ $error = '';
if ( empty( $info ) ) {
$information['upgrades'][ $plugin ] = false;
@@ -408,6 +411,10 @@ private function to_update_plugins( &$information, $plugins ) { //phpcs:ignore -
} elseif ( is_wp_error( $info ) ) {
$error = $info->get_error_message();
$information['upgrades_error'][ $plugin ] = $error;
+ $errors_codes = $info->get_error_codes();
+ if ( is_array( $errors_codes ) && in_array( 'mainwp_update_error_code', $errors_codes ) ) {
+ $problematic_update = true;
+ }
} else {
$information['upgrades'][ $plugin ] = true;
$success = true;
@@ -427,6 +434,10 @@ private function to_update_plugins( &$information, $plugins ) { //phpcs:ignore -
$info['error'] = $error;
}
+ if ( $problematic_update ) {
+ $info['rollback'] = 1;
+ }
+
$current_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
if ( ! is_array( $current_info ) ) {
$current_info = array();
@@ -582,9 +593,18 @@ private function to_upgrade_themes( &$information, $themes, $last_update ) { //p
$themes_info = MainWP_Child_Actions::get_instance()->get_current_themes_info();
$updated_themes = array();
foreach ( $result as $theme => $value ) {
- $success = false;
+ $success = false;
+ $error = '';
+ $problematic_update = false;
if ( empty( $value ) ) {
$information['upgrades'][ $theme ] = false;
+ } elseif ( is_wp_error( $value ) ) {
+ $error = $value->get_error_message();
+ $information['upgrades'][ $theme ] = false;
+ $errors_codes = $value->get_error_codes();
+ if ( is_array( $errors_codes ) && in_array( 'mainwp_update_error_code', $errors_codes ) ) {
+ $problematic_update = true;
+ }
} else {
$information['upgrades'][ $theme ] = true;
$success = true;
@@ -601,6 +621,14 @@ private function to_upgrade_themes( &$information, $themes, $last_update ) { //p
'success' => $success ? 1 : 0,
);
+ if ( $problematic_update ) {
+ $info['rollback'] = 1;
+ }
+
+ if ( ! empty( $error ) ) {
+ $info['error'] = $error;
+ }
+
$current_info = wp_get_theme( $theme );
if ( ! is_array( $current_info ) ) {
$current_info = array();
@@ -650,33 +678,206 @@ private function to_upgrade_themes( &$information, $themes, $last_update ) { //p
* @param array $mwp_premium_updates_to_do_slugs An array containing the list of premium themes slugs to update.
*/
private function update_premiums_to_do( &$information, $premiumUpgrader, $mwp_premium_updates_to_do, $mwp_premium_updates_to_do_slugs ) { //phpcs:ignore -- NOSONAR - complex.
+
+ if ( ! isset( $information['other_data']['updated_data'] ) ) {
+ $information['other_data']['updated_data'] = array();
+ }
+
+ $plugins_info = MainWP_Child_Actions::get_instance()->get_current_plugins_info();
+ $updated_plugins = array();
+
// Upgrade via WP.
// @see wp-admin/update.php.
- $result = $premiumUpgrader->bulk_upgrade( $mwp_premium_updates_to_do_slugs );
- if ( ! empty( $result ) ) {
- foreach ( $result as $plugin => $info ) {
- if ( ! empty( $info ) ) {
- $information['upgrades'][ $plugin ] = true;
+ $results = $premiumUpgrader->bulk_upgrade( $mwp_premium_updates_to_do_slugs );
+ if ( ! empty( $results ) ) {
+ foreach ( $results as $plugin => $result ) {
+ if ( ! empty( $result ) ) {
+
+ if ( is_wp_error( $result ) ) {
+ $slug = $plugin;
+
+ $update_info = array();
+ if ( is_array( $mwp_premium_updates_to_do ) ) {
+ $update_info = array_filter(
+ $mwp_premium_updates_to_do,
+ function ( $e ) use ( $slug ) {
+ return isset( $e['slug'] ) && $e['slug'] === $slug;
+ }
+ );
+ if ( $update_info ) {
+ $update_info = current( $update_info );
+ }
+ if ( ! is_array( $update_info ) ) {
+ $update_info = array();
+ }
+ }
+
+ $problematic_update = false;
+ $error = $result->get_error_message();
+ $errors_codes = $result->get_error_codes();
+ if ( is_array( $errors_codes ) && in_array( 'mainwp_update_error_code', $errors_codes ) ) {
+ $problematic_update = true;
+ }
+
+ $old_info = isset( $plugins_info[ $slug ] ) ? $plugins_info[ $slug ] : array();
+
+ if ( ! is_array( $old_info ) ) {
+ $old_info = array();
+ }
+ $name = isset( $old_info['Name'] ) ? $old_info['Name'] : '';
+
+ $info = array(
+ 'name' => $name,
+ 'old_version' => isset( $old_info['Version'] ) ? $old_info['Version'] : '',
+ 'slug' => $slug,
+ 'success' => 0,
+ );
+
+ if ( empty( $info['old_version'] ) && ! empty( $update_info['Version'] ) ) {
+ $info['old_version'] = $update_info['Version'];
+ }
+
+ if ( $problematic_update ) {
+ $info['rollback'] = 1;
+ }
+
+ if ( ! empty( $error ) ) {
+ $info['error'] = $error;
+ }
+
+ $current_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $slug );
+ if ( ! is_array( $current_info ) ) {
+ $current_info = array();
+ }
+
+ if ( ! empty( $current_info['Version'] ) ) {
+ $info['version'] = $current_info['Version'];
+ }
+
+ if ( empty( $info['name'] ) && ! empty( $current_info['Name'] ) ) {
+ $info['name'] = $current_info['Name'];
+ }
+
+ if ( empty( $info['name'] ) ) {
+ $info['name'] = $slug;
+ }
+
+ $information['other_data']['updated_data'][ $slug ] = $info;
+
+ } else {
+ $information['upgrades'][ $plugin ] = true;
+ }
+ $updated_plugins[ $slug ] = 1; // to prevent try next and incorrect.
}
}
}
// Upgrade via callback.
foreach ( $mwp_premium_updates_to_do as $update ) {
+
+ if ( isset( $update['slug'] ) && isset( $updated_plugins[ $update['slug'] ] ) ) {
+ continue;
+ }
+
$slug = ( isset( $update['slug'] ) ? $update['slug'] : $update['Name'] );
if ( isset( $update['url'] ) ) {
- $installer = new \WP_Upgrader();
- $result = $installer->run(
+
+ $installer = new \WP_Upgrader();
+
+ $hook_extra = array();
+
+ if ( 'plugin' === $update['type'] && false !== strpos( $slug, '/' ) ) {
+ $hook_extra = array(
+ 'plugin' => $slug,
+ 'temp_backup' => array(
+ 'slug' => dirname( $slug ),
+ 'src' => WP_PLUGIN_DIR,
+ 'dir' => 'plugins',
+ ),
+ );
+ }
+
+ $result = $installer->run(
array(
'package' => $update['url'],
'destination' => ( 'plugin' === $update['type'] ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/themes' ),
'clear_destination' => true,
'clear_working' => true,
- 'hook_extra' => array(),
+ 'hook_extra' => $hook_extra,
)
);
- $information['upgrades'][ $slug ] = ( ! is_wp_error( $result ) && ! empty( $result ) );
+
+ $success = ! is_wp_error( $result ) && ! empty( $result );
+ $information['upgrades'][ $slug ] = $success;
+
+ $problematic_update = false;
+
+ $error = '';
+
+ if ( is_wp_error( $result ) ) {
+ $error = $result->get_error_message();
+ $errors_codes = $result->get_error_codes();
+ if ( is_array( $errors_codes ) && in_array( 'mainwp_update_error_code', $errors_codes ) ) {
+ $problematic_update = true;
+ }
+ }
+
+ $name = ! empty( $update['name'] ) ? $update['name'] : '';
+
+ if ( empty( $name ) ) {
+ $name = ! empty( $update['Name'] ) ? $update['Name'] : '';
+ }
+
+ $old_info = array();
+
+ if ( 'plugin' === $update['type'] ) {
+ $old_info = isset( $plugins_info[ $slug ] ) ? $plugins_info[ $slug ] : array();
+ if ( ! is_array( $old_info ) ) {
+ $old_info = array();
+ }
+ }
+
+ $info = array(
+ 'name' => $name,
+ 'old_version' => isset( $old_info['version'] ) ? $old_info['version'] : '',
+ 'slug' => $slug,
+ 'success' => $success ? 1 : 0,
+ );
+
+ if ( $problematic_update ) {
+ $info['rollback'] = 1;
+ }
+
+ if ( ! empty( $error ) ) {
+ $info['error'] = $error;
+ }
+
+ if ( 'plugin' === $update['type'] ) {
+ $current_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $slug );
+ if ( ! is_array( $current_info ) ) {
+ $current_info = array();
+ }
+
+ if ( ! empty( $current_info['Version'] ) ) {
+ $info['version'] = $current_info['Version'];
+ }
+
+ if ( empty( $info['name'] ) && ! empty( $current_info['Name'] ) ) {
+ $info['name'] = $current_info['Name'];
+ }
+ }
+
+ if ( empty( $info['version'] ) && ! empty( $update['version'] ) ) {
+ $info['version'] = $update['version'];
+ }
+
+ if ( empty( $info['name'] ) ) {
+ $info['name'] = $slug;
+ }
+
+ $information['other_data']['updated_data'][ $slug ] = $info;
+
} elseif ( isset( $update['callback'] ) ) {
if ( is_array( $update['callback'] ) && isset( $update['callback'][0] ) && isset( $update['callback'][1] ) ) {
$update_result = call_user_func(
@@ -1191,4 +1392,25 @@ public function upgrade_translation() { //phpcs:ignore -- NOSONAR - complex.
$information['sync'] = MainWP_Child_Stats::get_instance()->get_site_stats( array(), false );
MainWP_Helper::write( $information );
}
+
+
+ /**
+ * Method enable_pre_auto_rollback_hooking().
+ */
+ public static function enable_pre_auto_rollback_hooking() {
+ add_filter( 'upgrader_install_package_result', array( static::get_class_name(), 'upgrader_auto_rollback_hooking' ), 99, 2 );
+ }
+
+ /**
+ * Method upgrader_auto_rollback_hooking().
+ *
+ * @param array|WP_Error $result Result from WP_Upgrader::install_package().
+ * @param array $hook_extra Extra arguments passed to hooked filters.
+ */
+ public static function upgrader_auto_rollback_hooking( $result, $hook_extra = array() ) {
+ if ( is_wp_error( $result ) && is_array( $hook_extra ) && ! empty( $hook_extra['temp_backup'] ) ) {
+ $result->add( 'mainwp_update_error_code', 'Update error.' );
+ }
+ return $result;
+ }
}
diff --git a/class/class-mainwp-child.php b/class/class-mainwp-child.php
index 0fc323f7..d567472f 100644
--- a/class/class-mainwp-child.php
+++ b/class/class-mainwp-child.php
@@ -30,7 +30,7 @@ class MainWP_Child {
*
* @var string MainWP Child plugin version.
*/
- public static $version = '5.1-RC1'; // NOSONAR - not IP.
+ public static $version = '5.1'; // NOSONAR - not IP.
/**
* Private variable containing the latest MainWP Child update version.
diff --git a/class/class-mainwp-clone-install.php b/class/class-mainwp-clone-install.php
index eccaf5de..f1297f87 100644
--- a/class/class-mainwp-clone-install.php
+++ b/class/class-mainwp-clone-install.php
@@ -440,13 +440,40 @@ public function get_config_contents() {
} elseif ( $this->check_zip_support() ) {
$zip = new \ZipArchive();
$zipRes = $zip->open( $this->file );
- if ( $zipRes ) {
- $content = $zip->getFromName( 'clone/config.txt' );
- $zip->close();
- return $content;
+ // Check if the ZIP file was successfully opened.
+ if ( true !== $zipRes ) {
+ // Try to get the content of 'clone/config.txt' from the ZIP file.
+ $content = $zip->getFromName( 'clone/config.txt' );
+ // Check if the content was successfully retrieved.
+ if ( false !== $content ) {
+ $zip->close();
+ return $content;
+ }
+ } else {
+ $err = '';
+ // Handle errors based on the result code.
+ switch ( $zipRes ) {
+ case \ZipArchive::ER_NOENT:
+ $err = "ZIP file does not exist.\n";
+ break;
+ case \ZipArchive::ER_NOZIP:
+ $err = "Not a ZIP archive or corrupted.\n";
+ break;
+ case \ZipArchive::ER_OPEN:
+ $err = "Failed to open the ZIP file.\n";
+ break;
+ case \ZipArchive::ER_READ:
+ $err = "Failed to read the ZIP file.\n";
+ break;
+ default:
+ $err = "Failed to open the ZIP file. Error code: $zipRes\n";
+ break;
+ }
+ if ( $err ) {
+ error_log( $err ); //phpcs:ignore -- NOSONAR - for dev.
+ }
}
-
return false;
} else {
$zip = new \PclZip( $this->file );
diff --git a/class/class-mainwp-clone-page.php b/class/class-mainwp-clone-page.php
index 8b244a1c..81c12ee6 100644
--- a/class/class-mainwp-clone-page.php
+++ b/class/class-mainwp-clone-page.php
@@ -69,9 +69,9 @@ public static function print_scripts() {
$ui = $wp_scripts->query( 'jquery-ui-core' );
$version = $ui->ver;
if ( MainWP_Helper::starts_with( $version, '1.10' ) ) {
- wp_enqueue_style( 'jquery-ui-style', plugins_url( '/css/1.10.4/jquery-ui.min.css', __DIR__ ), array(), '1.10', 'all' );
+ wp_enqueue_style( 'jquery-ui-style', plugins_url( 'css/1.10.4/jquery-ui.min.css', __DIR__ ), array(), '1.10', 'all' );
} else {
- wp_enqueue_style( 'jquery-ui-style', plugins_url( '/css/1.11.1/jquery-ui.min.css', __DIR__ ), array(), '1.11', 'all' );
+ wp_enqueue_style( 'jquery-ui-style', plugins_url( 'css/1.11.1/jquery-ui.min.css', __DIR__ ), array(), '1.11', 'all' );
}
}
diff --git a/class/class-mainwp-clone.php b/class/class-mainwp-clone.php
index 7afe2f88..47e292c5 100644
--- a/class/class-mainwp-clone.php
+++ b/class/class-mainwp-clone.php
@@ -411,6 +411,9 @@ public function clone_backup_create() {
// Send request to the childsite!
+ $timeout = 20 * 60 * 60;
+ MainWP_Helper::set_limit( $timeout );
+
/**
* The installed version of WordPress.
*
@@ -743,7 +746,7 @@ public function clone_backup_extract() {
* @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
*/
private function clone_backup_get_file( $file, &$testFull ) {
- if ( '' === $file ) {
+ if ( empty( $file ) ) {
$dirs = MainWP_Helper::get_mainwp_dir( 'backup', false );
$backupdir = $dirs[0];
$files = glob( $backupdir . 'download-*' );
diff --git a/class/class-mainwp-connect.php b/class/class-mainwp-connect.php
index 1b8a6a73..4f73c68d 100644
--- a/class/class-mainwp-connect.php
+++ b/class/class-mainwp-connect.php
@@ -111,13 +111,11 @@ public function register_site() { // phpcs:ignore -- NOSONAR - Current complexit
}
// Check if the user exists and if yes, check if it's Administartor user.
- if ( isset( $_POST['user'] ) ) {
- if ( empty( $_POST['user'] ) || ! $this->login( wp_unslash( $_POST['user'] ) ) ) {
- MainWP_Helper::instance()->error( esc_html__( 'Unexisting administrator user. Please verify that it is an existing administrator.', 'mainwp-child' ) );
- }
- if ( ! MainWP_Helper::is_admin() ) {
- MainWP_Helper::instance()->error( esc_html__( 'User is not an administrator. Please use an administrator user to establish the connection.', 'mainwp-child' ) );
- }
+ if ( empty( $_POST['user'] ) || ! $this->login( wp_unslash( $_POST['user'] ) ) ) {
+ MainWP_Helper::instance()->error( esc_html__( 'Unexisting administrator user. Please verify that it is an existing administrator.', 'mainwp-child' ) );
+ }
+ if ( ! MainWP_Helper::is_admin() ) {
+ MainWP_Helper::instance()->error( esc_html__( 'User is not an administrator. Please use an administrator user to establish the connection.', 'mainwp-child' ) );
}
// Update the mainwp_child_pubkey option.
diff --git a/class/class-mainwp-helper.php b/class/class-mainwp-helper.php
index 5b8e5bed..ea98a842 100644
--- a/class/class-mainwp-helper.php
+++ b/class/class-mainwp-helper.php
@@ -60,6 +60,27 @@ public static function write( $value ) {
die( '' . base64_encode( $output ) . '' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions,WordPress.Security.EscapeOutput -- base64_encode function is used for backwards compatibility.
}
+ /**
+ * Method write_feedback()
+ *
+ * Send response feedback data to be sent to the MainWP Dashboard.
+ *
+ * @param mixed $value Contains information to be send.
+ * @param mixed $action action send message.
+ */
+ public static function write_feedback( $value, $action = '' ) {
+ /**
+ * Action: process send feedback message.
+ *
+ * @since 5.1
+ */
+ do_action( 'mainwp_child_before_send_feedback_message', $value, $action );
+
+ $output = wp_json_encode( $value );
+
+ echo '' . base64_encode( $output ) . ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions,WordPress.Security.EscapeOutput -- base64_encode function is used for backwards compatibility.
+ }
+
/**
* Method send()
diff --git a/mainwp-child.php b/mainwp-child.php
index d62ef32f..091b42fa 100644
--- a/mainwp-child.php
+++ b/mainwp-child.php
@@ -12,7 +12,7 @@
* Author: MainWP
* Author URI: https://mainwp.com
* Text Domain: mainwp-child
- * Version: 5.1-RC1
+ * Version: 5.1
* Requires at least: 5.4
* Requires PHP: 7.4
*/
diff --git a/readme.txt b/readme.txt
index f3f5e299..3a68e30e 100644
--- a/readme.txt
+++ b/readme.txt
@@ -7,7 +7,7 @@ Plugin URI: https://mainwp.com
Requires at least: 6.2
Tested up to: 6.5.3
Requires PHP: 7.4
-Stable tag: 5.1-RC1
+Stable tag: 5.1
License: GPLv3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -111,6 +111,14 @@ We have an extensive FAQ with more questions and answers [here](https://mainwp.c
== Changelog ==
+= 5.1 - 6-18-2024 =
+
+* Fixed: An issue with submitting Time Capsule settings.
+* Added: Integrated a Rollback feature to revert plugins to the last stable version in case of update errors.
+* Updated: Addressed coding standard issues found by SonarCloud.
+
+[See Video Changelog](https://youtu.be/OtqrgU8q5RA)
+
= 5.0.1.1 - 4-23-2024 =
* Added: Support for the RunCloud Hub plugin in the Cache Control.