Initial Commit

This commit is contained in:
David Stone
2024-11-30 18:24:12 -07:00
commit e8f7955c1c
5432 changed files with 1397750 additions and 0 deletions

View File

@ -0,0 +1,123 @@
<?php
/**
* WP Ultimo Rollback
*
* Allows users to rollback WP Ultimo to the previous stable version.
*
* @package WP_Ultimo
* @subpackage Rollback
* @since 2.0.0
*/
namespace WP_Ultimo\Rollback;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Our own upgrader skin implementation that does not display errors.
*
* @since 2.0.0
*/
class Quiet_Plugin_Upgrader_Skin extends \Plugin_Upgrader_Skin {
/**
* Silence is golden...
*
* @since 2.0.0
* @return void
*/
public function header() {} // end header;
/**
* Silence is golden...
*
* @since 2.0.0
* @return void
*/
public function footer() {} // end footer;
/**
* Print errors.
*
* @since 2.0.0
*
* @param string|WP_Error $errors Errors.
* @return void
*/
public function error($errors) {
if (is_string($errors)) {
$this->feedback($errors);
} elseif (is_wp_error($errors) && $errors->has_errors()) {
foreach ($errors->get_error_messages() as $message) {
if ($errors->get_error_data() && is_string($errors->get_error_data())) {
$this->feedback($message . ' ' . esc_html(strip_tags($errors->get_error_data())));
} else {
$this->feedback($message);
} // end if;
} // end foreach;
} // end if;
} // end error;
/**
* Passes messages down to the upgrader class.
*
* @since 2.0.0
*
* @param string $string The error message.
* @param mixed ...$args other arguments.
* @return void
*/
public function feedback($string, ...$args) {
if (isset($this->upgrader->strings[$string])) {
$string = $this->upgrader->strings[$string];
} // end if;
if (strpos((string) $string, '%') !== false) {
if ($args ) {
$args = array_map('strip_tags', $args);
$args = array_map('esc_html', $args);
$string = vsprintf($string, $args);
} // end if;
} // end if;
if (empty($string)) {
return;
} // end if;
$this->upgrader->messages[] = $string;
} // end feedback;
/**
* Removes output.
*
* @since 2.0.0
*
* @param string $type it doesn't matter.
* @return void
*/
protected function decrement_update_count($type) {} // end decrement_update_count;
} // end class Quiet_Plugin_Upgrader_Skin;

View File

@ -0,0 +1,105 @@
<?php
/**
* WP Ultimo Rollback Plugin Upgrader
*
* Class that extends the WP Core Plugin_Upgrader found in core to do rollbacks.
* Modified to fit WP Ultimo needs.
*
* @package WP_Ultimo
* @subpackage Rollback
* @since 2.0.0
*/
namespace WP_Ultimo\Rollback;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Rollback Plugin Upgrader
*
* @since 2.0.0
*/
class Rollback_Plugin_Upgrader extends \Plugin_Upgrader {
/**
* Holds messages.
*
* @since 2.0.0
* @var array
*/
public $messages = array();
/**
* Plugin rollback.
*
* @param string $plugin Plugin Slug.
* @param array $args Arguments.
* @return mixed[]|bool|\WP_Error
*/
public function rollback($plugin, $args = array()) {
$defaults = array(
'clear_update_cache' => true,
'url' => '',
);
$parsed_args = wp_parse_args($args, $defaults);
$this->init();
$this->upgrade_strings();
// TODO: Add final check to make sure plugin exists
if (0) {
$this->skin->before();
$this->skin->set_result(false);
$this->skin->error('up_to_date');
$this->skin->after();
return false;
} // end if;
$plugin_slug = $this->skin->plugin;
$plugin_version = $this->skin->options['version'];
$url = $args['url'];
add_filter('upgrader_pre_install', array($this, 'deactivate_plugin_before_upgrade'), 10, 2);
add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4);
$this->run(array(
'package' => $url,
'destination' => WP_PLUGIN_DIR,
'clear_destination' => true,
'clear_working' => true,
'hook_extra' => array(
'plugin' => $plugin,
'type' => 'plugin',
'action' => 'update',
),
));
// Cleanup our hooks, in case something else does a upgrade on this connection.
remove_filter('upgrader_pre_install', array($this, 'deactivate_plugin_before_upgrade'));
remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'));
if (!$this->result || is_wp_error($this->result)) {
return false;
} // end if;
// Force refresh of plugin update information.
wp_clean_plugins_cache($parsed_args['clear_update_cache']);
return true;
} // end rollback;
} // end class Rollback_Plugin_Upgrader;

View File

@ -0,0 +1,332 @@
<?php
/**
* WP Ultimo Rollback
*
* Allows users to rollback WP Ultimo to the previous stable version.
*
* @package WP_Ultimo
* @subpackage Rollback
* @since 2.0.0
*/
namespace WP_Ultimo\Rollback;
use \WP_Ultimo\License;
use \WP_Ultimo\Logger;
use \WP_Ultimo\Rollback\Rollback_Plugin_Upgrader;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Rollback.
*
* @since 2.0.0
*/
class Rollback {
use \WP_Ultimo\Traits\Singleton;
/**
* Holds the URL for serving build files.
*
* @since 2.0.0
*
* @var string
*/
protected $updates_url = 'https://licenses.nextpress.us/api/meta/wp-ultimo/';
/**
* Holds the URL for download build files.
*
* @since 2.4.0
*
* @var string
*/
protected $download_url = 'https://licenses.nextpress.us/api/download/wp-ultimo/';
/**
* Init
*
* @since 1.0
*
* @return void
*/
public function init() {
add_filter('network_admin_plugin_action_links', array($this, 'plugin_page_action_links'), 200, 4);
add_action('admin_init', array($this, 'handle_rollback_process'));
add_action('plugins_loaded', array($this, 'load_admin_page'));
} // end init;
/**
* Loads the rollback admin page.
*
* @since 2.0.7
* @return void
*/
public function load_admin_page() {
/*
* Loads the Rollback Pages
*/
new \WP_Ultimo\Admin_Pages\Rollback_Admin_Page();
} // end load_admin_page;
/**
* Handle the Rollback action.
*
* @since 2.0.0
*
* @return mixed
*/
public function handle_rollback_process() {
if (wu_request('action') !== 'rollback-wp-ultimo') {
return;
} // end if;
/*
* Run a couple of security checks here.
* First we check for a valid referer and nonce.
*/
check_admin_referer('wp-ultimo-rollback', '_wpnonce');
/*
* Then, we check for permissions.
*/
if (current_user_can('manage_network') === false) {
return;
} // end if;
/*
* We're safe. Now we can build the URL...
* First, reveal the API key.
*/
$license_key = rawurlencode(base64_decode((string) wu_request('n', '')));
$rollback_url = $this->get_versions_url('download', array(
'rollback' => wu_request('type', 'latest-stable') === 'latest-stable',
'version' => wu_request('version', wu_get_version()),
'license_key' => $license_key,
));
/*
* Unhook shutdown hooks.
*/
if (class_exists(\ActionScheduler_QueueRunner::class)) {
\ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request();
} // end if;
$this->process_rollback(array(
'url' => $rollback_url,
));
} // end handle_rollback_process;
/**
* Adds the rollback link to the WP Ultimo plugin omn the Plugin list table.
*
* @since 2.0.0
*
* @param string $actions Current actions.
* @param string $plugin_file The path of the plugin file.
* @param array $plugin_data Data about the plugin.
* @param string $context Context of the table.
* @return string New actions list.
*/
public function plugin_page_action_links($actions, $plugin_file, $plugin_data, $context) {
if (is_multisite() && (!is_network_admin() && !is_main_site())) {
return $actions;
} // end if;
if (!isset($plugin_data['Version'])) {
return $actions;
} // end if;
if ($plugin_file !== 'wp-multisite-waas/wp-multisite-waas.php') {
return $actions;
} // end if;
$actions['rollback'] = '<a href="' . wu_network_admin_url('wp-ultimo-rollback') . '">' . __('Rollback', 'wp-ultimo') . '</a>';
return $actions;
} // end plugin_page_action_links;
/**
* Process the Rollback.
*
* @since 2.0.0
*
* @param array $args Arguments.
* @return void
*/
public function process_rollback($args = array()) {
$plugin_file = 'wp-ultimo/wp-ultimo.php';
if (!class_exists(\Plugin_Upgrader_Skin::class)) {
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
require_once wu_path('inc/rollback/class-rollback-plugin-upgrader.php');
} // end if;
$slug = 'wp-ultimo';
$nonce = "upgrade-plugin_{$slug}";
$url = sprintf('index.php?page=wp-rollback&plugin_file=%s&action=upgrade-plugin', esc_url($plugin_file));
Logger::add('rollback-errors', sprintf('Rollback started... Download URL: %s', $url));
$plugin = $slug;
$version = wu_get_version();
$title = '';
try {
$upgrader = new Rollback_Plugin_Upgrader(new Quiet_Plugin_Upgrader_Skin(compact('title', 'nonce', 'url', 'plugin', 'version')));
$results = $upgrader->rollback('wp-ultimo', array(
'url' => $args['url'],
));
if ($results) {
wp_redirect(network_admin_url('plugins.php?activate=1'));
exit;
} else {
$messages = implode('<br><br>', $upgrader->messages);
wp_die($messages);
} // end if;
} catch (\Throwable $e) {
// translators: %s is the error message captured.
$error = new \WP_Error('maybe-error', sprintf(__('Something might have gone wrong doing the rollback. Check to see if the WP Ultimo version was downgraded or not on the plugins page. Error captured: %s.', 'wp-ultimo'), $e->getMessage()));
Logger::add('rollback-errors', $e->getMessage());
wp_die($error);
} // end try;
} // end process_rollback;
/**
* Get the URLs we will need to use to rollback.
*
* @since 2.0.0
*
* @param string $action Action to add to the URL.
* @param array $args Parameters to add.
* @return string
*/
public function get_versions_url($action = 'download', $args = array()) {
$defaults = array(
'version' => wu_get_version(),
'rollback' => true,
'license_key' => rawurlencode((string) License::get_instance()->get_license_key()),
);
$url = $action === 'download' ? $this->download_url : $this->updates_url;
$rollback_url = add_query_arg(wp_parse_args($args, $defaults), $url);
return $rollback_url;
} // end get_versions_url;
/**
* Get the available list of versions.
*
* @since 2.0.0
* @return array
*/
public function get_available_versions() {
$url = $this->get_versions_url('available_versions');
$response = wp_remote_get($url);
if (is_wp_error($response)) {
return $response;
} // end if;
$list = json_decode(wp_remote_retrieve_body($response));
if (is_object($list)) {
return false;
} // end if;
/*
* Clean up development builds.
*/
$list = array_filter($list, fn($item) => strpos((string) $item, 'beta') === false && strpos((string) $item, 'rc') === false);
$response_list = array();
$current_list = array_reverse(array_filter($list, fn($item) => strncmp((string) $item, '2.', strlen('2.')) === 0));
$response_list = array_slice($current_list, 0, 10);
if ($this->_is_legacy_network()) {
$legacy_list = array_reverse(array_filter($list, fn($item) => strncmp((string) $item, '1.', strlen('1.')) === 0));
$response_list = array_merge(array_slice($response_list, 0, 7), array_slice($legacy_list, 0, 3));
} // end if;
return $response_list;
} // end get_available_versions;
/**
* Check if network have a legacy install to rollback.
* FIXME: remove this and break Migrator::is_legacy_network in two methods.
*
* @since 2.0.11
* @return bool
*/
private function _is_legacy_network() {
$plans = get_posts(array(
'post_type' => 'wpultimo_plan',
'numberposts' => 1,
));
return !empty($plans);
} // end _is_legacy_network;
} // end class Rollback;