201 lines
6.0 KiB
PHP
201 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace Yoast\WP\Test_Helper;
|
|
|
|
use Automatic_Upgrader_Skin;
|
|
use Exception;
|
|
use WP_Upgrader;
|
|
use WPSEO_Options;
|
|
use Yoast\WP\Lib\Migrations\Adapter;
|
|
use Yoast\WP\SEO\Config\Migration_Status;
|
|
use Yoast\WP\SEO\Loader;
|
|
use ZipArchive;
|
|
|
|
/**
|
|
* Downgrader class.
|
|
*/
|
|
class Downgrader implements Integration {
|
|
|
|
/**
|
|
* Registers WordPress hooks.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function add_hooks() {
|
|
\add_action( 'admin_post_yoast_rollback_control', [ $this, 'handle_submit' ] );
|
|
}
|
|
|
|
/**
|
|
* Retrieves the controls.
|
|
*
|
|
* @return string The HTML to use to render the controls.
|
|
*/
|
|
public function get_controls() {
|
|
$option = 'target_version';
|
|
|
|
$output = \sprintf( '<label for="%1$s">%2$s</label>', $option, \__( 'Downgrade to version: ', 'yoast-test-helper' ) );
|
|
$output .= \sprintf( '<input name="%1$s" id="%1$s" type="text"></input><br />', $option );
|
|
|
|
$title = \sprintf(
|
|
/* translators: %1$s is Yoast SEO. */
|
|
\__( 'Downgrade %1$s', 'yoast-test-helper' ),
|
|
'Yoast SEO'
|
|
);
|
|
|
|
return Form_Presenter::get_html( $title, 'yoast_rollback_control', $output );
|
|
}
|
|
|
|
/**
|
|
* Handles the form submission.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function handle_submit() {
|
|
if ( ! \check_admin_referer( 'yoast_rollback_control' ) ) {
|
|
return;
|
|
}
|
|
if ( ! isset( $_POST['target_version'] ) || ! \is_string( $_POST['target_version'] ) ) {
|
|
return;
|
|
}
|
|
|
|
$target_version = \sanitize_text_field( \wp_unslash( $_POST['target_version'] ) );
|
|
|
|
try {
|
|
$this->downgrade( $target_version );
|
|
\do_action(
|
|
'Yoast\WP\Test_Helper\notification',
|
|
new Notification(
|
|
\sprintf(
|
|
/* translators: %1$s is Yoast SEO, %2$s is the version number it was downgraded to. */
|
|
\__( '%1$s has been succesfully downgraded to version %2$s.', 'yoast-test-helper' ),
|
|
'Yoast SEO',
|
|
$target_version
|
|
),
|
|
'success'
|
|
)
|
|
);
|
|
} catch ( Exception $e ) {
|
|
\do_action(
|
|
'Yoast\WP\Test_Helper\notification',
|
|
new Notification( $e->getMessage(), 'error' )
|
|
);
|
|
}
|
|
|
|
\wp_safe_redirect( \self_admin_url( 'tools.php?page=' . \apply_filters( 'Yoast\WP\Test_Helper\admin_page', '' ) ) );
|
|
}
|
|
|
|
/**
|
|
* Downgrades the Yoast SEO version.
|
|
*
|
|
* @param string $target_version The version to downgrade to.
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws Exception If the downgrade fails.
|
|
*/
|
|
protected function downgrade( $target_version ) {
|
|
if ( ! \preg_match( '/^\d+\.\d+$/', $target_version ) ) {
|
|
throw new Exception( \__( 'An invalid version number was passed.', 'yoast-test-helper' ) );
|
|
}
|
|
|
|
if ( \version_compare( $target_version, '14.1', '<' ) ) {
|
|
throw new Exception( \__( 'Downgrading to below 14.1 is not supported', 'yoast-test-helper' ) );
|
|
}
|
|
|
|
require_once \ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
|
$upgrader = new WP_Upgrader( new Automatic_Upgrader_Skin() );
|
|
$upgrader->fs_connect();
|
|
|
|
$downloaded_archive = $upgrader->download_package( "https://downloads.wordpress.org/plugin/wordpress-seo.$target_version.zip" );
|
|
|
|
if ( \is_wp_error( $downloaded_archive ) ) {
|
|
throw new Exception( \__( 'The requested version could not be downloaded', 'yoast-test-helper' ) );
|
|
}
|
|
|
|
// Open the downloaded archive.
|
|
$zip = new ZipArchive();
|
|
$zip->open( $downloaded_archive );
|
|
|
|
$all_migration_files = \glob( \WPSEO_PATH . 'src/config/migrations/*.php' );
|
|
|
|
// Find all migrations that are not in the downgraded archive.
|
|
$migrations_to_downgrade = [];
|
|
foreach ( $all_migration_files as $migration_file ) {
|
|
$migration_file = \str_replace( \WPSEO_PATH, '', $migration_file );
|
|
if ( ! $zip->getFromName( 'wordpress-seo/' . $migration_file ) ) {
|
|
$basename = \basename( $migration_file, '.php' );
|
|
$version = \explode( '_', $basename )[0];
|
|
$migrations_to_downgrade[] = $version;
|
|
}
|
|
}
|
|
// Migrations should be downgraded from last to first.
|
|
\sort( $migrations_to_downgrade, \SORT_STRING );
|
|
$migrations_to_downgrade = \array_reverse( $migrations_to_downgrade );
|
|
|
|
$loader = \YoastSEO()->classes->get( Loader::class );
|
|
$adapter = \YoastSEO()->classes->get( Adapter::class );
|
|
$migration_status = \YoastSEO()->classes->get( Migration_Status::class );
|
|
$migrations = $loader->get_migrations( 'free' );
|
|
|
|
if ( ! $migration_status->lock_migration( 'free' ) ) {
|
|
throw new Exception( \__( 'A migration is already in progress. Please try again later.', 'yoast-test-helper' ) );
|
|
}
|
|
|
|
// Downgrade all migrations.
|
|
foreach ( $migrations_to_downgrade as $version ) {
|
|
$class = $migrations[ $version ];
|
|
try {
|
|
$migration = new $class( $adapter );
|
|
$adapter->start_transaction();
|
|
$migration->down();
|
|
$adapter->remove_version( $version );
|
|
$adapter->commit_transaction();
|
|
} catch ( Exception $e ) {
|
|
$adapter->rollback_transaction();
|
|
|
|
throw new Exception(
|
|
\sprintf(
|
|
/* translators: %1$s is the class name of the migration that failed, %2$s is the message given by the failure. */
|
|
\__( 'Migration %1$s failed with the message: %2$s', 'yoast-test-helper' ),
|
|
$class,
|
|
$e->getMessage()
|
|
),
|
|
0,
|
|
$e
|
|
);
|
|
}
|
|
}
|
|
$migration_status->set_success( 'free', $target_version );
|
|
|
|
$working_dir = $upgrader->unpack_package( $downloaded_archive, true );
|
|
if ( \is_wp_error( $working_dir ) ) {
|
|
throw new Exception( \__( 'Could not unpack the requested version.', 'yoast-test-helper' ) );
|
|
}
|
|
|
|
$result = $upgrader->install_package(
|
|
[
|
|
'source' => $working_dir,
|
|
'destination' => \WP_PLUGIN_DIR,
|
|
'clear_destination' => true,
|
|
'clear_working' => true,
|
|
'hook_extra' => [
|
|
'type' => 'plugin',
|
|
'action' => 'install',
|
|
],
|
|
]
|
|
);
|
|
if ( \is_wp_error( $result ) ) {
|
|
throw new Exception( \__( 'Could not install the requested version.', 'yoast-test-helper' ) );
|
|
}
|
|
|
|
$downgrade_version = static function( $option ) use ( $target_version ) {
|
|
$option['version'] = \sanitize_text_field( $target_version );
|
|
return $option;
|
|
};
|
|
|
|
\add_filter( 'sanitize_option_wpseo', $downgrade_version, 20 );
|
|
WPSEO_Options::set( 'version', $target_version );
|
|
\remove_filter( 'sanitize_option_wpseo', $downgrade_version );
|
|
}
|
|
}
|