Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,851 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
if (!$updraftcentral_host_plugin->is_host_dir_set()) die('No access.');
|
||||
|
||||
// This file is included during plugins_loaded
|
||||
|
||||
// Load the listener class that we rely on to pick up messages
|
||||
if (!class_exists('UpdraftCentral_Listener')) require_once('listener.php');
|
||||
|
||||
// We exit if class already exists. More common if two or more plugins integrated
|
||||
// the same `UpdraftCentral` client folder.
|
||||
if (!class_exists('UpdraftCentral_Main')) :
|
||||
|
||||
class UpdraftCentral_Main {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
add_action('udrpc_log', array($this, 'udrpc_log'), 10, 3);
|
||||
|
||||
add_action('wp_ajax_updraftcentral_receivepublickey', array($this, 'wp_ajax_updraftcentral_receivepublickey'));
|
||||
add_action('wp_ajax_nopriv_updraftcentral_receivepublickey', array($this, 'wp_ajax_updraftcentral_receivepublickey'));
|
||||
|
||||
// The host plugin's command class is registered in its "plugins_loaded" method (e.g. UpdraftPlus::plugins_loaded()).
|
||||
//
|
||||
// N.B. The new filter "updraftcentral_remotecontrol_command_classes" was introduced on Jan. 2021 and will soon replace the
|
||||
// old filter "updraftplus_remotecontrol_command_classes" (below). This was done in order to synchronize all available filters
|
||||
// and actions related to UpdraftCentral so that we can easily port the UpdraftCentral client code into our other plugins.
|
||||
//
|
||||
// If you happened to use the old filter from any of your projects then you might as well update it with the new filter as the
|
||||
// old filter has already been marked as deprecated, though currently supported as can be seen below but will soon be remove
|
||||
// from this code block.
|
||||
$command_classes = apply_filters('updraftcentral_remotecontrol_command_classes', array(
|
||||
'core' => 'UpdraftCentral_Core_Commands',
|
||||
'updates' => 'UpdraftCentral_Updates_Commands',
|
||||
'users' => 'UpdraftCentral_Users_Commands',
|
||||
'comments' => 'UpdraftCentral_Comments_Commands',
|
||||
'analytics' => 'UpdraftCentral_Analytics_Commands',
|
||||
'plugin' => 'UpdraftCentral_Plugin_Commands',
|
||||
'theme' => 'UpdraftCentral_Theme_Commands',
|
||||
'posts' => 'UpdraftCentral_Posts_Commands',
|
||||
'media' => 'UpdraftCentral_Media_Commands',
|
||||
'pages' => 'UpdraftCentral_Pages_Commands',
|
||||
'backups' => 'UpdraftCentral_Backups_Commands'
|
||||
));
|
||||
|
||||
// N.B. This "updraftplus_remotecontrol_command_classes" filter has been marked as deprecated and will be remove after May 2021.
|
||||
// Please see above code comment for further explanation and its alternative.
|
||||
$command_classes = apply_filters('updraftplus_remotecontrol_command_classes', $command_classes);
|
||||
|
||||
// If nothing was sent, then there is no incoming message, so no need to set up a listener (or CORS request, etc.). This avoids a DB SELECT query on the option below in the case where it didn't get autoloaded, which is the case when there are no keys.
|
||||
if (!empty($_SERVER['REQUEST_METHOD']) && ('GET' == $_SERVER['REQUEST_METHOD'] || 'POST' == $_SERVER['REQUEST_METHOD']) && (empty($_REQUEST['action']) || 'updraft_central' !== $_REQUEST['action']) && empty($_REQUEST['udcentral_action']) && empty($_REQUEST['udrpc_message'])) return;
|
||||
|
||||
// Remote control keys
|
||||
// These are different from the remote send keys, which are set up in the Migrator add-on
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
|
||||
if (is_array($our_keys) && !empty($our_keys)) {
|
||||
new UpdraftCentral_Listener($our_keys, $command_classes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the needed styles and scripts for UpdraftCentral
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_central_scripts() {
|
||||
|
||||
// This is an additional check; the caller is assumed to have already run checks before painting its page in general
|
||||
if (!current_user_can('manage_options')) return;
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
$version = $updraftcentral_host_plugin->get_version();
|
||||
|
||||
$enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? $version.'.'.time() : $version;
|
||||
$min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
|
||||
|
||||
// Fallback to unminified version if the minified version is not found.
|
||||
if (!empty($min_or_not) && !file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/js/central'.$min_or_not.'.js')) {
|
||||
$min_or_not = '';
|
||||
}
|
||||
|
||||
wp_enqueue_script('updraft-central', UPDRAFTCENTRAL_CLIENT_URL.'/js/central'.$min_or_not.'.js', array(), $enqueue_version);
|
||||
wp_enqueue_style('updraft-central', UPDRAFTCENTRAL_CLIENT_URL.'/css/central'.$min_or_not.'.css', array(), $enqueue_version);
|
||||
|
||||
$localize = array_merge(
|
||||
array(
|
||||
'central_url' => UPDRAFTCENTRAL_CLIENT_URL,
|
||||
'plugin_name' => $updraftcentral_host_plugin->get_plugin_name(),
|
||||
'updraftcentral_request_nonce' => wp_create_nonce('updraftcentral-request-nonce'),
|
||||
),
|
||||
$updraftcentral_host_plugin->translations
|
||||
);
|
||||
|
||||
wp_localize_script('updraft-central', 'uclion', apply_filters('updraftcentral_uclion', $localize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves current clean url for anchor link where href attribute value is not url (for ex. #div) or empty. Output is not escaped (caller should escape).
|
||||
*
|
||||
* @return String - current clean url
|
||||
*/
|
||||
public function get_current_clean_url() {
|
||||
|
||||
// Within an UpdraftCentral context, there should be no prefix on the anchor link
|
||||
if (defined('UPDRAFTCENTRAL_COMMAND') && UPDRAFTCENTRAL_COMMAND || defined('WP_CLI') && WP_CLI) return '';
|
||||
|
||||
if (defined('DOING_AJAX') && DOING_AJAX && !empty($_SERVER['HTTP_REFERER'])) {
|
||||
$current_url = $_SERVER['HTTP_REFERER'];
|
||||
} else {
|
||||
$url_prefix = is_ssl() ? 'https' : 'http';
|
||||
$host = empty($_SERVER['HTTP_HOST']) ? parse_url(network_site_url(), PHP_URL_HOST) : $_SERVER['HTTP_HOST'];
|
||||
$current_url = $url_prefix."://".$host.wp_unslash($_SERVER['REQUEST_URI']);
|
||||
}
|
||||
$remove_query_args = array('state', 'action', 'oauth_verifier', 'nonce', 'updraftplus_instance', 'access_token', 'user_id', 'updraftplus_googledriveauth');
|
||||
|
||||
$query_string = remove_query_arg($remove_query_args, $current_url);
|
||||
return function_exists('wp_unslash') ? wp_unslash($query_string) : stripslashes_deep($query_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WordPress version
|
||||
*
|
||||
* @return String - the version
|
||||
*/
|
||||
public function get_wordpress_version() {
|
||||
static $got_wp_version = false;
|
||||
if (!$got_wp_version) {
|
||||
@include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
||||
$got_wp_version = $wp_version;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
|
||||
}
|
||||
return $got_wp_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdraftCentral generated keys
|
||||
*
|
||||
* @param Mixed $default default value to return when option is not found
|
||||
*
|
||||
* @return Mixed
|
||||
*/
|
||||
private function get_central_localkeys($default = null) {
|
||||
|
||||
$option = 'updraft_central_localkeys';
|
||||
$ret = get_option($option, $default);
|
||||
return apply_filters('updraftcentral_get_option', $ret, $option, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UpdraftCentral's keys
|
||||
*
|
||||
* @param string $value Specify option value
|
||||
* @param bool $use_cache Whether or not to use the WP options cache
|
||||
* @param string $autoload Whether to autoload (only takes effect on a change of value)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function update_central_localkeys($value, $use_cache = true, $autoload = 'yes') {
|
||||
$option = 'updraft_central_localkeys';
|
||||
|
||||
return update_option($option, apply_filters('updraftcentral_update_option', $value, $option, $use_cache), $autoload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a new public key in $_GET, and echo a response. Will die() if called.
|
||||
*/
|
||||
public function wp_ajax_updraftcentral_receivepublickey() {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
// The actual nonce check is done in the method below
|
||||
if (empty($_GET['_wpnonce']) || empty($_GET['public_key']) || !isset($_GET['updraft_key_index'])) die;
|
||||
|
||||
$result = $this->receive_public_key();
|
||||
if (!is_array($result) || empty($result['responsetype'])) die;
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>UpdraftCentral</title>
|
||||
<style>
|
||||
body {text-align: center;font-family: Helvetica,Arial,Lucida,sans-serif;background-color: #A64C1A;color: #FFF;height: 100%;width: 100%;margin: 0;padding: 0;}#main {height: 100%;width: 100%;display: table;}#wrapper {display: table-cell;height: 100%;vertical-align: middle;}h1 {margin-bottom: 5px;}h2 {margin-top: 0;font-size: 22px;color: #FFF;}#btn-close {color: #FFF;font-size: 20px;font-weight: 500;padding: .3em 1em;line-height: 1.7em !important;background-color: transparent;background-size: cover;background-position: 50%;background-repeat: no-repeat;border: 2px solid;border-radius: 3px;-webkit-transition-duration: .2s;transition-duration: .2s;-webkit-transition-property: all !important;transition-property: all !important;text-decoration: none;}#btn-close:hover {background-color: #DE6726;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="wrapper"><img src="<?php echo esc_url(UPDRAFTCENTRAL_CLIENT_URL).'/images/ud-logo.png'; ?>" width="60" /> <h1><?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection', true); ?></h1><h2><?php echo esc_html(network_site_url()); ?></h2><p>
|
||||
<?php
|
||||
if ('ok' == $result['responsetype']) {
|
||||
$updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection_successful', true);
|
||||
} else {
|
||||
?>
|
||||
<strong><span id="udc-connect-failed">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection_failed', true); ?>
|
||||
</span></strong><br>
|
||||
<?php
|
||||
switch ($result['code']) {
|
||||
case 'unknown_key':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('unknown_key', true);
|
||||
break;
|
||||
case 'not_logged_in':
|
||||
echo esc_html($updraftcentral_host_plugin->retrieve_show_message('not_logged_in')).' ';
|
||||
$updraftcentral_host_plugin->retrieve_show_message('must_visit_url', true);
|
||||
break;
|
||||
case 'nonce_failure':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('security_check', true);
|
||||
$updraftcentral_host_plugin->retrieve_show_message('must_visit_link', true);
|
||||
break;
|
||||
case 'already_have':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('connection_already_made', true);
|
||||
break;
|
||||
case 'insufficient_privilege':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('insufficient_privilege', true);
|
||||
break;
|
||||
default:
|
||||
echo esc_html(print_r($result, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
<p><a id="btn-close" href="<?php echo esc_url($this->get_current_clean_url()); ?>" onclick="window.close();"><?php $updraftcentral_host_plugin->retrieve_show_message('close', true); ?></a>
|
||||
</p></div></div>
|
||||
<?php
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks _wpnonce, and if successful, saves the public key found in $_GET
|
||||
*
|
||||
* @return Array - with keys responsetype (can be 'error' or 'ok') and code, indicating whether the parse was successful
|
||||
*/
|
||||
private function receive_public_key() {
|
||||
|
||||
if (!is_user_logged_in()) {
|
||||
return array('responsetype' => 'error', 'code' => 'not_logged_in');
|
||||
}
|
||||
|
||||
if (!wp_verify_nonce($_GET['_wpnonce'], 'updraftcentral_receivepublickey')) return array('responsetype' => 'error', 'code' => 'nonce_failure');
|
||||
|
||||
$updraft_key_index = $_GET['updraft_key_index'];
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
|
||||
if (!isset($our_keys[$updraft_key_index])) {
|
||||
return array('responsetype' => 'error', 'code' => 'unknown_key');
|
||||
}
|
||||
|
||||
if (!empty($our_keys[$updraft_key_index]['publickey_remote'])) {
|
||||
return array('responsetype' => 'error', 'code' => 'already_have');
|
||||
}
|
||||
|
||||
$our_keys[$updraft_key_index]['publickey_remote'] = base64_decode(stripslashes($_GET['public_key']));
|
||||
$this->update_central_localkeys($our_keys, true, 'no');
|
||||
|
||||
return array('responsetype' => 'ok', 'code' => 'ok');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action parameters, from udrpc: $message, $level, $this->key_name_indicator, $this->debug, $this
|
||||
*
|
||||
* @param string $message The log message
|
||||
* @param string $level Log level
|
||||
* @param string $key_name_indicator This indicates the key name
|
||||
*/
|
||||
public function udrpc_log($message, $level, $key_name_indicator) {
|
||||
|
||||
$udrpc_log = get_site_option('updraftcentral_client_log');
|
||||
if (!is_array($udrpc_log)) $udrpc_log = array();
|
||||
|
||||
$new_item = array(
|
||||
'time' => time(),
|
||||
'level' => $level,
|
||||
'message' => $message,
|
||||
'key_name_indicator' => $key_name_indicator
|
||||
);
|
||||
|
||||
if (!empty($_SERVER['REMOTE_ADDR'])) {
|
||||
$new_item['remote_ip'] = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
|
||||
$new_item['http_user_agent'] = $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
if (!empty($_SERVER['HTTP_X_SECONDARY_USER_AGENT'])) {
|
||||
$new_item['http_secondary_user_agent'] = $_SERVER['HTTP_X_SECONDARY_USER_AGENT'];
|
||||
}
|
||||
|
||||
$udrpc_log[] = $new_item;
|
||||
|
||||
if (count($udrpc_log) > 50) array_shift($udrpc_log);
|
||||
|
||||
update_site_option('updraftcentral_client_log', $udrpc_log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete UpdraftCentral Key
|
||||
*
|
||||
* @param array $key_id key_id of UpdraftCentral
|
||||
*
|
||||
* @return array which contains deleted flag and key table. If error, Returns array which contains fatal_error flag and fatal_error_message
|
||||
*/
|
||||
public function delete_key($key_id) {
|
||||
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
if (is_array($key_id) && isset($key_id['key_id'])) {
|
||||
$key_id = $key_id['key_id'];
|
||||
}
|
||||
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
if (isset($our_keys[$key_id])) {
|
||||
unset($our_keys[$key_id]);
|
||||
$this->update_central_localkeys($our_keys);
|
||||
}
|
||||
return array('deleted' => 1, 'keys_table' => $this->get_keys_table());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UpdraftCentral Log
|
||||
*
|
||||
* @return array which contains log_contents. If error, Returns array which contains fatal_error flag and fatal_error_message
|
||||
*/
|
||||
public function get_log() {
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$udrpc_log = get_site_option('updraftcentral_client_log');
|
||||
if (!is_array($udrpc_log)) $udrpc_log = array();
|
||||
|
||||
$log_contents = '';
|
||||
|
||||
// Events are appended to the array in the order they happen. So, reversing the order gets them into most-recent-first order.
|
||||
rsort($udrpc_log);
|
||||
|
||||
if (empty($udrpc_log)) {
|
||||
$log_contents = '<em>'.$updraftcentral_host_plugin->retrieve_show_message('nothing_yet_logged').'</em>';
|
||||
}
|
||||
|
||||
foreach ($udrpc_log as $m) {
|
||||
|
||||
// Skip invalid data
|
||||
if (!isset($m['time'])) continue;
|
||||
|
||||
$time = gmdate('Y-m-d H:i:s O', $m['time']);
|
||||
// $level is not used yet. We could put the message in different colours for different levels, if/when it becomes used.
|
||||
|
||||
$key_name_indicator = empty($m['key_name_indicator']) ? '' : $m['key_name_indicator'];
|
||||
|
||||
$log_contents .= '<span title="'.esc_attr(print_r($m, true)).'">'."$time ";
|
||||
|
||||
if (!empty($m['remote_ip'])) $log_contents .= '['.htmlspecialchars($m['remote_ip']).'] ';
|
||||
|
||||
$log_contents .= "[".htmlspecialchars($key_name_indicator)."] ".htmlspecialchars($m['message'])."</span>\n";
|
||||
}
|
||||
|
||||
return array('log_contents' => $log_contents);
|
||||
|
||||
}
|
||||
|
||||
public function create_key($params) {
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
// Use the site URL - this means that if the site URL changes, communication ends; which is the case anyway
|
||||
$user = wp_get_current_user();
|
||||
|
||||
if (!is_object($user) || empty($user->ID)) return array('error' => $updraftcentral_host_plugin->retrieve_show_message('insufficient_privilege'));
|
||||
|
||||
if (!current_user_can('manage_options')) return array('error' => $updraftcentral_host_plugin->retrieve_show_message('insufficient_privilege'));
|
||||
|
||||
$where_send = empty($params['where_send']) ? '' : (string) $params['where_send'];
|
||||
|
||||
if ('__updraftpluscom' != $where_send) {
|
||||
$purl = parse_url($where_send);
|
||||
if (empty($purl) || !array($purl) || empty($purl['scheme']) || empty($purl['host'])) return array('error' => $updraftcentral_host_plugin->retrieve_show_message('invalid_url'));
|
||||
}
|
||||
|
||||
// ENT_HTML5 exists only on PHP 5.4+
|
||||
// @codingStandardsIgnoreLine
|
||||
$flags = defined('ENT_HTML5') ? ENT_QUOTES | ENT_HTML5 : ENT_QUOTES;
|
||||
|
||||
$extra_info = array(
|
||||
'user_id' => $user->ID,
|
||||
'user_login' => $user->user_login,
|
||||
'ms_id' => get_current_blog_id(),
|
||||
'site_title' => html_entity_decode(get_bloginfo('name'), $flags),
|
||||
);
|
||||
|
||||
if ($where_send) {
|
||||
$extra_info['mothership'] = $where_send;
|
||||
if (!empty($params['mothership_firewalled'])) {
|
||||
$extra_info['mothership_firewalled'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($params['key_description'])) {
|
||||
$extra_info['name'] = (string) $params['key_description'];
|
||||
}
|
||||
|
||||
$key_size = (empty($params['key_size']) || !is_numeric($params['key_size']) || $params['key_size'] < 512) ? 2048 : (int) $params['key_size'];
|
||||
|
||||
$extra_info['key_size'] = $key_size;
|
||||
|
||||
$created = $this->create_remote_control_key(false, $extra_info, $where_send);
|
||||
|
||||
if (is_array($created)) {
|
||||
$created['keys_table'] = $this->get_keys_table();
|
||||
|
||||
$created['keys_guide'] = '<h2 class="updraftcentral_wizard_success">'. $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_key_created') .'</h2>';
|
||||
|
||||
if ('__updraftpluscom' != $where_send) {
|
||||
$created['keys_guide'] .= '<div class="updraftcentral_wizard_success"><p>'.sprintf($updraftcentral_host_plugin->retrieve_show_message('need_to_copy_key'), '<a href="'.$where_send.'" target="_blank">UpdraftCentral dashboard</a>').'</p><p>'.$updraftcentral_host_plugin->retrieve_show_message('press_add_site_button').'</p><p>'.sprintf($updraftcentral_host_plugin->retrieve_show_message('detailed_instructions'), '<a target="_blank" href="https://updraftplus.com/updraftcentral-how-to-add-a-site/">UpdraftPlus.com</a>').'</p></div>';
|
||||
} else {
|
||||
$created['keys_guide'] .= '<div class="updraftcentral_wizard_success"><p>'. sprintf($updraftcentral_host_plugin->retrieve_show_message('control_this_site'), '<a target="_blank" href="https://updraftplus.com/my-account/updraftcentral-remote-control/">UpdraftPlus.com</a>').'</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
return $created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an index, return the indicator name
|
||||
*
|
||||
* @param String $index
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
private function indicator_name_from_index($index) {
|
||||
return $index.'.central.updraftplus.com';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an RPC object, and sets some defaults on it that we always want
|
||||
*
|
||||
* @param string $indicator_name indicator name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_udrpc($indicator_name = 'migrator.updraftplus.com') {
|
||||
|
||||
global $updraftcentral_host_plugin, $updraftplus;
|
||||
|
||||
$updraftplus->ensure_phpseclib();
|
||||
|
||||
if (!class_exists('UpdraftPlus_Remote_Communications_V2')) include_once($updraftcentral_host_plugin->get_host_dir().'/vendor/team-updraft/common-libs/src/updraft-rpc/class-udrpc2.php');
|
||||
$ud_rpc = new UpdraftPlus_Remote_Communications_V2($indicator_name);
|
||||
$ud_rpc->set_can_generate(true);
|
||||
|
||||
return $ud_rpc;
|
||||
}
|
||||
|
||||
private function create_remote_control_key($index = false, $extra_info = array(), $post_it = false) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
|
||||
if (false === $index) {
|
||||
if (empty($our_keys)) {
|
||||
$index = 0;
|
||||
} else {
|
||||
$index = max(array_keys($our_keys))+1;
|
||||
}
|
||||
}
|
||||
|
||||
$name_hash = $index;
|
||||
|
||||
if (isset($our_keys[$name_hash])) {
|
||||
unset($our_keys[$name_hash]);
|
||||
}
|
||||
|
||||
$indicator_name = $this->indicator_name_from_index($name_hash);
|
||||
$ud_rpc = $this->get_udrpc($indicator_name);
|
||||
|
||||
if ('__updraftpluscom' == $post_it) {
|
||||
$post_it = defined('UPDRAFTPLUS_OVERRIDE_UDCOM_DESTINATION') ? UPDRAFTPLUS_OVERRIDE_UDCOM_DESTINATION : 'https://updraftplus.com/?updraftcentral_action=receive_key';
|
||||
$post_it_description = 'UpdraftPlus.Com';
|
||||
} else {
|
||||
$post_it_description = $post_it;
|
||||
}
|
||||
|
||||
// Normally, key generation takes seconds, even on a slow machine. However, some Windows machines appear to have a setup in which it takes a minute or more. And then, if you're on a double-localhost setup on slow hardware - even worse. It doesn't hurt to just raise the maximum execution time.
|
||||
|
||||
if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTCENTRAL_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
||||
|
||||
$key_size = (empty($extra_info['key_size']) || !is_numeric($extra_info['key_size']) || $extra_info['key_size'] < 512) ? 2048 : (int) $extra_info['key_size'];
|
||||
|
||||
if (is_object($ud_rpc) && $ud_rpc->generate_new_keypair($key_size)) {
|
||||
|
||||
if ($post_it && empty($extra_info['mothership_firewalled'])) {
|
||||
|
||||
$p_url = parse_url($post_it);
|
||||
if (is_array($p_url) && !empty($p_url['user'])) {
|
||||
$http_username = $p_url['user'];
|
||||
$http_password = empty($p_url['pass']) ? '' : $p_url['pass'];
|
||||
$post_it = $p_url['scheme'].'://'.$p_url['host'];
|
||||
if (!empty($p_url['port'])) $post_it .= ':'.$p_url['port'];
|
||||
$post_it .= $p_url['path'];
|
||||
if (!empty($p_url['query'])) $post_it .= '?'.$p_url['query'];
|
||||
}
|
||||
|
||||
$post_options = array(
|
||||
'timeout' => 90,
|
||||
'body' => array(
|
||||
'updraftcentral_action' => 'receive_key',
|
||||
'key' => $ud_rpc->get_key_remote()
|
||||
)
|
||||
);
|
||||
|
||||
if (!empty($http_username)) {
|
||||
$post_options['headers'] = array(
|
||||
'Authorization' => 'Basic '.base64_encode($http_username.':'.$http_password)
|
||||
);
|
||||
}
|
||||
|
||||
// This option allows the key to be sent to the other side via a known-secure channel (e.g. http over SSL), rather than potentially allowing it to travel over an unencrypted channel (e.g. http back to the user's browser). As such, if specified, it is compulsory for it to work.
|
||||
|
||||
$updraftcentral_host_plugin->register_wp_http_option_hooks();
|
||||
|
||||
$sent_key = wp_remote_post(
|
||||
$post_it,
|
||||
$post_options
|
||||
);
|
||||
|
||||
$updraftcentral_host_plugin->register_wp_http_option_hooks(false);
|
||||
|
||||
$connection_troubleshooting_url = 'https://updraftplus.com/troubleshooting-updraftcentral-connection-issues/';
|
||||
if (is_wp_error($sent_key) || empty($sent_key)) {
|
||||
|
||||
$err_msg = sprintf($updraftcentral_host_plugin->retrieve_show_message('attempt_to_register_failed'), (string) $post_it_description, $connection_troubleshooting_url);
|
||||
if (is_wp_error($sent_key)) $err_msg .= ' '.$sent_key->get_error_message().' ('.$sent_key->get_error_code().')';
|
||||
return array(
|
||||
'r' => $err_msg
|
||||
);
|
||||
}
|
||||
|
||||
$response = json_decode(wp_remote_retrieve_body($sent_key), true);
|
||||
|
||||
if (!is_array($response) || !isset($response['key_id']) || !isset($response['key_public'])) {
|
||||
return array(
|
||||
'r' => sprintf($updraftcentral_host_plugin->retrieve_show_message('attempt_to_register_failed'), (string) $post_it_description, $connection_troubleshooting_url),
|
||||
'raw' => wp_remote_retrieve_body($sent_key)
|
||||
);
|
||||
}
|
||||
|
||||
$key_hash = hash('sha256', $ud_rpc->get_key_remote());
|
||||
|
||||
$local_bundle = $ud_rpc->get_portable_bundle('base64_with_count', $extra_info, array('key' => array('key_hash' => $key_hash, 'key_id' => $response['key_id'])));
|
||||
|
||||
} elseif ($post_it) {
|
||||
// Don't send; instead, include in the bundle info that the mothership is firewalled; this will then tell the mothership to try the reverse connection instead
|
||||
|
||||
if (is_array($extra_info)) {
|
||||
$extra_info['mothership_firewalled_callback_url'] = wp_nonce_url(admin_url('admin-ajax.php'), 'updraftcentral_receivepublickey');
|
||||
$extra_info['updraft_key_index'] = $index;
|
||||
}
|
||||
|
||||
|
||||
$local_bundle = $ud_rpc->get_portable_bundle('base64_with_count', $extra_info, array('key' => $ud_rpc->get_key_remote()));
|
||||
}
|
||||
|
||||
|
||||
if (isset($extra_info['name'])) {
|
||||
$name = (string) $extra_info['name'];
|
||||
unset($extra_info['name']);
|
||||
} else {
|
||||
$name = 'UpdraftCentral Remote Control';
|
||||
}
|
||||
|
||||
$our_keys[$name_hash] = array(
|
||||
'name' => $name,
|
||||
'key' => $ud_rpc->get_key_local(),
|
||||
'extra_info' => $extra_info,
|
||||
'created' => time(),
|
||||
);
|
||||
// Store the other side's public key
|
||||
if (!empty($response) && is_array($response) && !empty($response['key_public'])) {
|
||||
$our_keys[$name_hash]['publickey_remote'] = $response['key_public'];
|
||||
}
|
||||
$this->update_central_localkeys($our_keys, true, 'no');
|
||||
|
||||
return array(
|
||||
'bundle' => $local_bundle,
|
||||
'r' => $updraftcentral_host_plugin->retrieve_show_message('key_created_successfully').' '.$updraftcentral_host_plugin->retrieve_show_message('copy_paste_key'),
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML for the keys table
|
||||
*
|
||||
* @param Boolean $echo_instead_of_return Whether the result should be echoed or returned
|
||||
* @return String
|
||||
*/
|
||||
public function get_keys_table($echo_instead_of_return = false) {
|
||||
|
||||
// This is an additional check - it implies requirement for a dashboard context
|
||||
if (!current_user_can('manage_options')) return;
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
if (!$echo_instead_of_return) ob_start();
|
||||
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
|
||||
if (empty($our_keys)) {
|
||||
?>
|
||||
<tr><td colspan="2"><em><?php $updraftcentral_host_plugin->retrieve_show_message('no_updraftcentral_dashboards', true); ?></em></td></tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<div id="updraftcentral_keys_content" style="margin: 10px 0;">
|
||||
<?php if (!empty($our_keys)) { ?>
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" class="updraftcentral_keys_show hidden-in-updraftcentral"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('manage_keys'), count($our_keys))); ?></a>
|
||||
<?php } ?>
|
||||
<table id="updraftcentral_keys_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left;"><?php $updraftcentral_host_plugin->retrieve_show_message('key_description', true); ?></th>
|
||||
<th style="text-align:left;"><?php $updraftcentral_host_plugin->retrieve_show_message('details', true); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
foreach ($our_keys as $i => $key) {
|
||||
|
||||
if (empty($key['extra_info'])) continue;
|
||||
|
||||
$user_id = $key['extra_info']['user_id'];
|
||||
|
||||
if (!empty($key['extra_info']['mothership'])) {
|
||||
|
||||
$mothership_url = $key['extra_info']['mothership'];
|
||||
|
||||
if ('__updraftpluscom' == $mothership_url) {
|
||||
$reconstructed_url = 'https://updraftplus.com';
|
||||
} else {
|
||||
$purl = parse_url($mothership_url);
|
||||
$path = empty($purl['path']) ? '' : $purl['path'];
|
||||
|
||||
$reconstructed_url = $purl['scheme'].'://'.$purl['host'].(!empty($purl['port']) ? ':'.$purl['port'] : '').$path;
|
||||
}
|
||||
|
||||
} else {
|
||||
$reconstructed_url = $updraftcentral_host_plugin->retrieve_show_message('unknown');
|
||||
}
|
||||
|
||||
$name = $key['name'];
|
||||
|
||||
$user = get_user_by('id', $user_id);
|
||||
|
||||
$user_display = is_a($user, 'WP_User') ? $user->user_login.' ('.$user->user_email.')' : $updraftcentral_host_plugin->retrieve_show_message('unknown');
|
||||
?>
|
||||
<tr class="updraft_debugrow"><td style="vertical-align:top;"><?php echo esc_html($name.' ('.$i.')'); ?></td><td><?php $updraftcentral_host_plugin->retrieve_show_message('access_as_user', true); ?> <?php echo esc_html($user_display); ?> <br> <?php $updraftcentral_host_plugin->retrieve_show_message('public_key_sent', true); ?> <?php echo esc_html($reconstructed_url); ?><br>
|
||||
<?php
|
||||
if (!empty($key['created'])) {
|
||||
echo esc_html($updraftcentral_host_plugin->retrieve_show_message('created').' '.date_i18n(get_option('date_format').' '.get_option('time_format'), $key['created'])).'.';
|
||||
if (!empty($key['extra_info']['key_size'])) {
|
||||
echo ' '.esc_html(sprintf($updraftcentral_host_plugin->retrieve_show_message('key_size'), $key['extra_info']['key_size'])).'.';
|
||||
}
|
||||
?>
|
||||
<br>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" data-key_id="<?php echo esc_attr($i); ?>" class="updraftcentral_key_delete"><?php $updraftcentral_host_plugin->retrieve_show_message('delete', true); ?></a></td></tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
if (!$echo_instead_of_return) return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML markup for the 'create key' section
|
||||
*
|
||||
* @param Boolean $echo_instead_of_return Whether the result should be echoed or returned
|
||||
* @return String|Void - the HTML
|
||||
*/
|
||||
private function create_key_markup($echo_instead_of_return = false) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
if (!$echo_instead_of_return) ob_start();
|
||||
?>
|
||||
<div class="create_key_container">
|
||||
<h4 class="updraftcentral_wizard_stage1"> <?php $updraftcentral_host_plugin->retrieve_show_message('connect_to_updraftcentral_dashboard', true); ?></h4>
|
||||
<table style="width: 100%; table-layout:fixed;">
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
<tr class="updraftcentral_wizard_stage1">
|
||||
<td>
|
||||
<div class="updraftcentral_wizard_mothership updraftcentral_wizard_option">
|
||||
<label class="button-primary" tabindex="0">
|
||||
<input checked="checked" type="radio" name="updraftcentral_mothership" id="updraftcentral_mothership_updraftpluscom" style="display: none;">
|
||||
TeamUpdraft.com
|
||||
</label><br>
|
||||
<div><?php echo wp_kses_post(sprintf(esc_html($updraftcentral_host_plugin->retrieve_show_message('in_example')), '<a target="_blank" href="https://teamupdraft.com/my-account/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=an-account&utm_creative_format=text">'.esc_html($updraftcentral_host_plugin->retrieve_show_message('an_account')).'</a>')); ?></div>
|
||||
|
||||
</div>
|
||||
<div class="updraftcentral_wizard_self_hosted_stage1 updraftcentral_wizard_option">
|
||||
<label class="button-primary" tabindex="0">
|
||||
<input type="radio" name="updraftcentral_mothership" id="updraftcentral_mothership_other" style="display: none;">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('self_hosted_dashboard', true);?>
|
||||
</label><br>
|
||||
<div><?php echo wp_kses_post(sprintf(esc_html($updraftcentral_host_plugin->retrieve_show_message('website_installed')), '<a target="_blank" href="https://wordpress.org/plugins/updraftcentral/">UpdraftCentral</a>')); ?></div>
|
||||
</div>
|
||||
<div class="updraftcentral_wizard_self_hosted_stage2" style="float:left; clear:left;display:none;">
|
||||
<p style="font-size: 13px;"><?php $updraftcentral_host_plugin->retrieve_show_message('enter_url', true); ?></p>
|
||||
<p style="font-size: 13px;" id="updraftcentral_wizard_stage1_error"></p>
|
||||
<input disabled="disabled" id="updraftcentral_keycreate_mothership" type="text" size="40" placeholder="<?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_dashboard_url', true); ?>" value="">
|
||||
<button type="button" class="button button-primary" id="updraftcentral_stage2_go"><?php $updraftcentral_host_plugin->retrieve_show_message('next', true); ?></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<h4 class="updraftcentral_wizard_stage2" style="display: none;"><?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection_details', true); ?></h4>
|
||||
<td class="updraftcentral_keycreate_description">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('description', true); ?>:
|
||||
<input id="updraftcentral_keycreate_description" type="text" size="20" placeholder="<?php $updraftcentral_host_plugin->retrieve_show_message('enter_description', true); ?>" value="" >
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<td>
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('encryption_key_size', true); ?>
|
||||
<select style="" id="updraftcentral_keycreate_keysize">
|
||||
<option value="512"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bits').' - '.$updraftcentral_host_plugin->retrieve_show_message('easy_to_break'), '512')); ?></option>
|
||||
<option value="1024"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bits').' - '.$updraftcentral_host_plugin->retrieve_show_message('faster'), '1024')); ?></option>
|
||||
<option value="2048" selected="selected"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bytes').' - '.$updraftcentral_host_plugin->retrieve_show_message('recommended'), '2048')); ?></option>
|
||||
<option value="4096"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bits').' - '.$updraftcentral_host_plugin->retrieve_show_message('slower'), '4096')); ?></option>
|
||||
</select>
|
||||
<br>
|
||||
<div id="updraftcentral_keycreate_mothership_firewalled_container">
|
||||
<label>
|
||||
<input id="updraftcentral_keycreate_mothership_firewalled" type="checkbox">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('use_alternative_method', true); ?>
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" id="updraftcentral_keycreate_altmethod_moreinfo_get"><?php $updraftcentral_host_plugin->retrieve_show_message('more_information', true); ?></a>
|
||||
<p id="updraftcentral_keycreate_altmethod_moreinfo" style="display:none; border: 1px dotted; padding: 3px; margin: 2px 10px 2px 24px;">
|
||||
<em><?php $updraftcentral_host_plugin->retrieve_show_message('this_is_useful', true);?></em>
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<td>
|
||||
<button style="margin-top: 5px;" type="button" class="button button-primary" id="updraftcentral_keycreate_go"><?php $updraftcentral_host_plugin->retrieve_show_message('create', true); ?></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<td>
|
||||
<a id="updraftcentral_stage1_go"><?php $updraftcentral_host_plugin->retrieve_show_message('back', true); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="updraft-copy-modal" title="<?php esc_html_e('Copy to clipboard', 'updraftplus');?>">
|
||||
<p>
|
||||
<?php echo esc_html__('Your web browser prevented the copy operation.', 'updraftplus').' '.'<a href="https://updraftplus.com/faqs/how-do-i-set-clipboard-permissions-for-different-browsers/" target="__blank">'.' '.esc_html__('Follow this link to read about how to set browser permission', 'updraftplus').'</a>'; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (!$echo_instead_of_return) return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get log event viewer mark-up
|
||||
*
|
||||
* @param Boolean $echo_instead_of_return Whether the result should be echoed or returned
|
||||
* @return String - the HTML
|
||||
*/
|
||||
private function get_log_markup($echo_instead_of_return = false) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
if (!$echo_instead_of_return) ob_start();
|
||||
?>
|
||||
<div id="updraftcentral_view_log_container" style="margin: 10px 0;">
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" id="updraftcentral_view_log"><?php $updraftcentral_host_plugin->retrieve_show_message('view_log_events', true); ?>...</a><br>
|
||||
<pre id="updraftcentral_view_log_contents" style="min-height: 110px; padding: 0 4px;">
|
||||
</pre>
|
||||
</div>
|
||||
<?php
|
||||
if (!$echo_instead_of_return) return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo the debug-tools dashboard HTML. Called by the WP action updraftplus_debugtools_dashboard.
|
||||
*/
|
||||
public function debugtools_dashboard() {
|
||||
|
||||
$this->enqueue_central_scripts();
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$including_desc = '';
|
||||
if (function_exists('get_current_screen')) {
|
||||
$screen = get_current_screen();
|
||||
$hosts = apply_filters('updraftcentral_host_plugins', array());
|
||||
$includes = $updraftcentral_host_plugin->retrieve_show_message('including_description');
|
||||
|
||||
foreach ($hosts as $plugin) {
|
||||
if (false !== stripos($screen->id, $plugin)) {
|
||||
$key = str_replace('-', '_', strtolower($plugin)).'_desc';
|
||||
if (isset($includes[$key])) {
|
||||
$including_desc = $includes[$key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$updraftcentral_description = preg_replace('/\s+/', ' ', sprintf($updraftcentral_host_plugin->retrieve_show_message('updraftcentral_description'), $including_desc));
|
||||
?>
|
||||
<div class="advanced_tools updraft_central">
|
||||
<h3><?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_remote_control', true); ?></h3>
|
||||
<p>
|
||||
<?php echo esc_html($updraftcentral_description); ?> <a target="_blank" href="https://teamupdraft.com/updraftcentral/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=read-more-here&utm_creative_format=text"><?php $updraftcentral_host_plugin->retrieve_show_message('read_more', true); ?></a>
|
||||
</p>
|
||||
<div style="min-height: 310px;" id="updraftcentral_keys">
|
||||
<?php $this->create_key_markup(true); ?>
|
||||
<?php $this->get_keys_table(true); ?>
|
||||
<button style="display: none;" type="button" class="button button-primary" id="updraftcentral_wizard_go"><?php $updraftcentral_host_plugin->retrieve_show_message('create_another_key', true); ?></button>
|
||||
<?php $this->get_log_markup(true); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
global $updraftcentral_main;
|
||||
$updraftcentral_main = new UpdraftCentral_Main();
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
class Automatic_Upgrader_Skin extends Automatic_Upgrader_Skin_Main {
|
||||
|
||||
public function feedback($string, ...$args) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ellipsisFound, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- spread operator is not supported in PHP < 5.5 but WP 5.3 supports PHP 5.6 minimum
|
||||
parent::updraft_feedback($string);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// @codingStandardsIgnoreFile
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
// Extracted from 4.5.2/wordpress/wp-admin/includes/class-wp-upgrader-skins.php; with the bulk_*() methods added since they are not in the base class on all WP versions.
|
||||
// Needed only on WP < 3.7
|
||||
|
||||
/**
|
||||
* Upgrader Skin for Automatic WordPress Upgrades
|
||||
*
|
||||
* Extracted from 4.5.2/wordpress/wp-admin/includes/class-wp-upgrader-skins.php; with the bulk_*() methods added since they are not in the base class on all WP versions.
|
||||
* Needed only on WP < 3.7
|
||||
*
|
||||
* This skin is designed to be used when no output is intended, all output
|
||||
* is captured and stored for the caller to process and log/email/discard.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Upgrader
|
||||
* @since 3.7.0
|
||||
*/
|
||||
class Automatic_Upgrader_Skin_Main extends WP_Upgrader_Skin {
|
||||
|
||||
protected $messages = array();
|
||||
|
||||
/**
|
||||
* Request filesystem credentials
|
||||
*
|
||||
* @param bool $error Check if there is an error: default is false
|
||||
* @param string $context Context for credentials
|
||||
* @param bool $allow_relaxed_file_ownership Check if relaxed file ownership is allowed
|
||||
* @return bool
|
||||
*/
|
||||
public function request_filesystem_credentials($error = false, $context = '', $allow_relaxed_file_ownership = false) {
|
||||
if ($context) {
|
||||
$this->options['context'] = $context;
|
||||
}
|
||||
// TODO: fix up request_filesystem_credentials(), or split it, to allow us to request a no-output version
|
||||
// This will output a credentials form in event of failure, We don't want that, so just hide with a buffer
|
||||
ob_start();
|
||||
$result = parent::request_filesystem_credentials($error, $context, $allow_relaxed_file_ownership);
|
||||
ob_end_clean();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get update message
|
||||
*
|
||||
* @return array reti=urns an array of messages
|
||||
*/
|
||||
public function get_upgrade_messages() {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feedback
|
||||
*
|
||||
* @param string|array|WP_Error $data THis is the data to be used for the feedback
|
||||
*/
|
||||
protected function updraft_feedback($data) {
|
||||
if (is_wp_error($data)) {
|
||||
$string = $data->get_error_message();
|
||||
} elseif (is_array($data)) {
|
||||
return;
|
||||
} else {
|
||||
$string = $data;
|
||||
}
|
||||
if (!empty($this->upgrader->strings[$string]))
|
||||
$string = $this->upgrader->strings[$string];
|
||||
|
||||
if (false !== strpos($string, '%')) {
|
||||
$args = func_get_args();
|
||||
$args = array_splice($args, 1);
|
||||
if (!empty($args))
|
||||
$string = vsprintf($string, $args);
|
||||
}
|
||||
|
||||
$string = trim($string);
|
||||
|
||||
// Only allow basic HTML in the messages, as it'll be used in emails/logs rather than direct browser output.
|
||||
$string = wp_kses($string, array(
|
||||
'a' => array(
|
||||
'href' => true
|
||||
),
|
||||
'br' => true,
|
||||
'em' => true,
|
||||
'strong' => true,
|
||||
));
|
||||
|
||||
if (empty($string))
|
||||
return;
|
||||
|
||||
$this->messages[] = $string;
|
||||
}
|
||||
|
||||
public function header() {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
public function footer() {
|
||||
$output = ob_get_clean();
|
||||
if (!empty($output))
|
||||
$this->feedback($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
*/
|
||||
public function bulk_header() {}
|
||||
|
||||
public function bulk_footer() {
|
||||
}
|
||||
}
|
||||
|
||||
global $updraftcentral_main;
|
||||
$wp_version = $updraftcentral_main->get_wordpress_version();
|
||||
|
||||
if (version_compare($wp_version, '5.3', '>=')) {
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) require_once(dirname(__FILE__).'/automatic-upgrader-skin-compatibility.php');
|
||||
} else {
|
||||
class Automatic_Upgrader_Skin extends Automatic_Upgrader_Skin_Main {
|
||||
|
||||
public function feedback($string) {
|
||||
parent::updraft_feedback($string);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH') || !defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* The extended class of Plugin_Upgrader that is mostly used for overriding some of the parent methods to short-circuit their native behaviour or to manipulate some data, parameters and/or method arguments
|
||||
*/
|
||||
class UpdraftCentral_Plugin_Upgrader extends Plugin_Upgrader {
|
||||
|
||||
/**
|
||||
* Run an upgrade/installation
|
||||
*
|
||||
* @param Array $options {
|
||||
* Array or string of arguments for upgrading/installing a package.
|
||||
*
|
||||
* @type bool $clear_destination Whether to delete any files already in the destination folder. Default false. (since 2.8.0)
|
||||
* }
|
||||
*
|
||||
* @return Array|False|WP_Error The result from self::install_package() on success, otherwise a WP_Error,
|
||||
* or false if unable to connect to the filesystem.
|
||||
*/
|
||||
public function run($options) {
|
||||
$options['clear_destination'] = true; // force overwritting the existing one, in case WP < 5.5.0 is in use where "overwrite_package" parameter doesn't exist
|
||||
return parent::run($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The extended class of Plugin_Upgrader that is mostly used for overriding some of the parent methods to short-circuit their native behaviour or to manipulate some data, parameters and/or method arguments
|
||||
*/
|
||||
class UpdraftCentral_Theme_Upgrader extends Theme_Upgrader {
|
||||
|
||||
/**
|
||||
* Run an upgrade/installation
|
||||
*
|
||||
* @param Array $options {
|
||||
* Array or string of arguments for upgrading/installing a package.
|
||||
*
|
||||
* @type bool $clear_destination Whether to delete any files already in the destination folder. Default false. (since 2.8.0)
|
||||
* }
|
||||
*
|
||||
* @return Array|False|WP_Error The result from self::install_package() on success, otherwise a WP_Error,
|
||||
* or false if unable to connect to the filesystem.
|
||||
*/
|
||||
public function run($options) {
|
||||
$options['clear_destination'] = true; // force overwritting the existing one, in case WP < 5.5.0 is in use where "overwrite_package" parameter doesn't exist
|
||||
return parent::run($options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* - A container for all the RPC commands implemented. Commands map exactly onto method names (and hence this class should not implement anything else, beyond the constructor, and private methods)
|
||||
* - Return format is array('response' => (string - a code), 'data' => (mixed));
|
||||
*
|
||||
* RPC commands are not allowed to begin with an underscore. So, any private methods can be prefixed with an underscore.
|
||||
*/
|
||||
abstract class UpdraftCentral_Commands {
|
||||
|
||||
protected $rc;
|
||||
|
||||
protected $ud;
|
||||
|
||||
protected $installed_data;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $rc
|
||||
*/
|
||||
public function __construct($rc) {
|
||||
$this->rc = $rc;
|
||||
global $updraftplus;
|
||||
$this->ud = $updraftplus;
|
||||
$this->installed_data = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Include a file or files from wp-admin/includes
|
||||
*/
|
||||
final protected function _admin_include() {
|
||||
$files = func_get_args();
|
||||
foreach ($files as $file) {
|
||||
include_once(ABSPATH.'/wp-admin/includes/'.$file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Include a file or files from wp-includes
|
||||
*/
|
||||
final protected function _frontend_include() {
|
||||
$files = func_get_args();
|
||||
foreach ($files as $file) {
|
||||
include_once(ABSPATH.WPINC.'/'.$file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a response in the expected format
|
||||
*
|
||||
* @param Mixed $data
|
||||
* @param String $code
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
final protected function _response($data = null, $code = 'rpcok') {
|
||||
return array(
|
||||
'response' => $code,
|
||||
'data' => $data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error in the expected format
|
||||
*
|
||||
* @param String $code
|
||||
* @param Mixed $data
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
final protected function _generic_error_response($code = 'central_unspecified', $data = null) {
|
||||
return $this->_response(
|
||||
array(
|
||||
'code' => $code,
|
||||
'data' => $data
|
||||
),
|
||||
'rpcerror'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a backup and a security credentials is required for the given request
|
||||
*
|
||||
* @param array $dir The directory location to check
|
||||
* @return array
|
||||
*/
|
||||
final protected function _get_backup_credentials_settings($dir) {
|
||||
|
||||
// Do we need to ask the user for filesystem credentials? when installing and/or deleting items in the given directory
|
||||
$filesystem_method = get_filesystem_method(array(), $dir);
|
||||
|
||||
ob_start();
|
||||
$filesystem_credentials_are_stored = request_filesystem_credentials(site_url(), $filesystem_method);
|
||||
ob_end_clean();
|
||||
$request_filesystem_credentials = ('direct' != $filesystem_method && !$filesystem_credentials_are_stored);
|
||||
|
||||
// Do we need to execute a backup process before installing/managing items
|
||||
$automatic_backups = (class_exists('UpdraftPlus_Options') && class_exists('UpdraftPlus_Addon_Autobackup') && UpdraftPlus_Options::get_updraft_option('updraft_autobackup_default', true)) ? true : false;
|
||||
|
||||
return array(
|
||||
'request_filesystem_credentials' => $request_filesystem_credentials,
|
||||
'automatic_backups' => $automatic_backups
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the information of the currently installed item (e.g. plugin or theme) through filter
|
||||
*
|
||||
* @param bool $response Indicates whether the installation was a success or failure
|
||||
* @param array $args Extra argument for the hook
|
||||
* @param array $data Contains paths used and other relevant information regarding the file
|
||||
* @return array
|
||||
*/
|
||||
final public function get_install_data($response, $args, $data) {
|
||||
|
||||
if ($response) {
|
||||
switch ($args['type']) {
|
||||
case 'plugin':
|
||||
$plugin_data = get_plugins('/'.$data['destination_name']);
|
||||
if (!empty($plugin_data)) {
|
||||
$info = reset($plugin_data);
|
||||
$key = key($plugin_data);
|
||||
|
||||
$info['slug'] = $data['destination_name'].'/'.$key;
|
||||
$this->installed_data = $info;
|
||||
}
|
||||
break;
|
||||
case 'theme':
|
||||
$theme = wp_get_theme($data['destination_name']);
|
||||
if ($theme->exists()) {
|
||||
// Minimalistic info here, if you need to add additional information
|
||||
// you can add them here. For now, the "Name" and "slug" fields will suffice
|
||||
// in the succeeding process.
|
||||
$this->installed_data = array(
|
||||
'Name' => $theme->get('Name'),
|
||||
'slug' => $data['destination_name'],
|
||||
'template' => $theme->get_template()
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates either a plugin or theme through zip file upload
|
||||
*
|
||||
* @param array $params Parameter array containing information pertaining the currently uploaded item
|
||||
* @param string $type Indicates whether this current process is intended for a 'plugin' or a 'theme' item
|
||||
* @return array
|
||||
*/
|
||||
final protected function process_chunk_upload($params, $type) {
|
||||
global $updraftcentral_host_plugin, $updraftcentral_main;
|
||||
|
||||
if (!in_array($type, array('plugin', 'theme'))) {
|
||||
return $this->_generic_error_response('upload_type_not_supported');
|
||||
}
|
||||
|
||||
$permission_error = false;
|
||||
if ('plugin' === $type) {
|
||||
if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) $permission_error = true;
|
||||
} else {
|
||||
if (!current_user_can('install_themes') || !current_user_can('switch_themes')) $permission_error = true;
|
||||
}
|
||||
|
||||
if ($permission_error) {
|
||||
return $this->_generic_error_response($type.'_insufficient_permission');
|
||||
}
|
||||
|
||||
// Pull any available and writable directory where we can store
|
||||
// our data/file temporarily before running the installation process.
|
||||
$upload_dir = untrailingslashit(get_temp_dir());
|
||||
if (!is_writable($upload_dir)) {
|
||||
$upload_dir = WP_CONTENT_DIR.'/upgrade';
|
||||
|
||||
if (!is_dir($upload_dir)) {
|
||||
$wp_dir = wp_upload_dir();
|
||||
if (!empty($wp_dir['basedir'])) $upload_dir = $wp_dir['basedir'];
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found any writable directory to temporarily store our file then
|
||||
// we bail and send an error back to the caller.
|
||||
if (!is_dir($upload_dir) || !is_writable($upload_dir)) {
|
||||
return $this->_generic_error_response('upload_dir_not_available');
|
||||
}
|
||||
|
||||
// Preloads the submitted credentials to the global $_POST variable
|
||||
if (!empty($params) && isset($params['filesystem_credentials'])) {
|
||||
parse_str($params['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save uploaded file
|
||||
$filename = basename($params['filename']).md5(get_home_url());
|
||||
$is_chunked = false;
|
||||
|
||||
if (isset($params['chunks']) && 1 < (int) $params['chunks']) {
|
||||
$filename .= '.part';
|
||||
$is_chunked = true;
|
||||
}
|
||||
|
||||
if (!$is_chunked || ($is_chunked && isset($params['chunk']) && 0 === (int) $params['chunk'])) {
|
||||
// if it's not a chunk upload or if it's a chunk upload operation and the current chunk variable is zero, then it means a new upload operation has just begun therefore we should remove previous left-over file (if any and due to error during the previous upload of the same file), because it can lead to a corrupt/invalid zip file (we use file_put_contents a few lines below with FILE_APPEND attribute)
|
||||
if (file_exists($upload_dir.'/'.$filename) && !unlink($upload_dir.'/'.$filename)) return $this->_generic_error_response('unable_to_delete_existing_file');
|
||||
}
|
||||
|
||||
if (empty($params['data'])) {
|
||||
return $this->_generic_error_response('data_empty_or_invalid');
|
||||
}
|
||||
|
||||
$result = file_put_contents($upload_dir.'/'.$filename, base64_decode($params['data']), FILE_APPEND | LOCK_EX);
|
||||
|
||||
if (false === $result) {
|
||||
return $this->_generic_error_response('unable_to_write_content');
|
||||
}
|
||||
|
||||
// Set $install_now to true for single upload and for the last chunk of a multi-chunks upload process
|
||||
$install_now = true;
|
||||
|
||||
if ($is_chunked) {
|
||||
if ($params['chunk'] == (int) $params['chunks'] - 1) {
|
||||
// If this is the last chunk of the request, then we're going to restore the
|
||||
// original filename of the file (without the '.part') since our upload is now complete.
|
||||
$orig_filename = basename($filename, '.part');
|
||||
$success = rename($upload_dir.'/'.$filename, $upload_dir.'/'.$orig_filename);
|
||||
|
||||
// If renaming the file was successful then restore the original name and override the $filename variable.
|
||||
// Overriding the $filename variable makes it easy for us to use the same variable for both
|
||||
// non-chunked and chunked zip file for the installation process.
|
||||
if ($success) {
|
||||
$filename = $orig_filename;
|
||||
} else {
|
||||
return $this->_generic_error_response('unable_to_rename_file');
|
||||
}
|
||||
} else {
|
||||
// Bypass installation for now since we're waiting for the last chunk to arrive
|
||||
// to complete the uploading of the zip file.
|
||||
$install_now = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything is already good (upload completed), thus, we proceed with the installation
|
||||
if ($install_now) {
|
||||
|
||||
// We have successfully uploaded the zip file in this location with its original filename intact.
|
||||
$zip_filepath = $upload_dir.'/'.$filename;
|
||||
|
||||
// Making sure that the file does actually exists, since we've just run through
|
||||
// a renaming process above.
|
||||
if (file_exists($zip_filepath)) {
|
||||
add_filter('upgrader_post_install', array($this, 'get_install_data'), 10, 3);
|
||||
|
||||
// WP < 3.7
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-automatic-upgrader-skin.php');
|
||||
require_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-updraftcentral-wp-upgrader.php');
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin();
|
||||
$upgrader = ('plugin' === $type) ? new UpdraftCentral_Plugin_Upgrader($skin) : new UpdraftCentral_Theme_Upgrader($skin);
|
||||
|
||||
$install_result = $upgrader->install($zip_filepath);
|
||||
remove_filter('upgrader_post_install', array($this, 'get_install_data'), 10, 3);
|
||||
|
||||
// Remove zip file on success and on error (cleanup)
|
||||
if ($install_result || is_null($install_result) || is_wp_error($install_result)) {
|
||||
@unlink($zip_filepath);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist.
|
||||
}
|
||||
|
||||
if (false === $install_result || is_wp_error($install_result)) {
|
||||
$message = $updraftcentral_host_plugin->retrieve_show_message('unable_to_connect');
|
||||
if (is_wp_error($install_result)) $message = $install_result->get_error_message();
|
||||
|
||||
return $this->_generic_error_response($type.'_install_failed', array('message' => $message));
|
||||
} else {
|
||||
// Pull installed data
|
||||
$data = $this->installed_data;
|
||||
|
||||
// For WP 3.4 the intended filter hook isn't working or not available
|
||||
// so we're going to pull the data manually.
|
||||
if ($install_result && empty($data)) {
|
||||
$result = $this->get_install_data($install_result, array('type' => $type), $skin->result);
|
||||
if ($result) {
|
||||
// Getting the installed data one more time after manually calling
|
||||
// the "get_install_data" function.
|
||||
$data = $this->installed_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
// Activate item if set
|
||||
$is_active = ('plugin' === $type) ? is_plugin_active($data['slug']) : ((wp_get_theme()->get('Name') === $data['Name']) ? true : false);
|
||||
|
||||
if ((bool) $params['activate'] && !$is_active) {
|
||||
if ('plugin' === $type) {
|
||||
if (is_multisite()) {
|
||||
$activate = activate_plugin($data['slug'], '', true);
|
||||
} else {
|
||||
$activate = activate_plugin($data['slug']);
|
||||
}
|
||||
} else {
|
||||
// In order to make it compatible with older versions of switch_theme which takes two
|
||||
// arguments we're going to pass two arguments instead of one. Latest versions have backward
|
||||
// compatibility so it's safe to do it this way.
|
||||
switch_theme($data['template'], $data['slug']);
|
||||
$activate = (wp_get_theme()->get_stylesheet() === $data['slug']) ? true : false;
|
||||
}
|
||||
|
||||
if (false === $activate || is_wp_error($activate)) {
|
||||
$wp_version = $updraftcentral_main->get_wordpress_version();
|
||||
|
||||
$message = is_wp_error($activate) ? array('message' => $activate->get_error_message()) : array('message' => sprintf($updraftcentral_host_plugin->retrieve_show_message('unable_to_activate'), $type, $type, $wp_version));
|
||||
return $this->_generic_error_response('unable_to_activate_'.$type, $message);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response(
|
||||
array(
|
||||
'installed' => true,
|
||||
'installed_data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (is_wp_error($skin->result)) {
|
||||
$code = $skin->result->get_error_code();
|
||||
$message = $skin->result->get_error_message();
|
||||
|
||||
$error_data = $skin->result->get_error_data($code);
|
||||
if (!empty($error_data)) {
|
||||
if (is_array($error_data)) $error_data = json_encode($error_data);
|
||||
|
||||
$message .= ' '.$error_data;
|
||||
}
|
||||
|
||||
return $this->_generic_error_response($code, $message);
|
||||
} else {
|
||||
return $this->_response(
|
||||
array(
|
||||
'installed' => false,
|
||||
'message' => sprintf($updraftcentral_host_plugin->retrieve_show_message('unable_to_install'), $type, $type, $type, $type, 'wp-content/'.$type.'s'),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Returning response to a chunk requests while still processing and
|
||||
// completing the file upload process. If we don't return a positive response
|
||||
// for every chunk requests then the caller will assumed an error has occurred
|
||||
// and will eventually stop the upload process.
|
||||
return $this->_response(array('in_progress' => true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
.updraftcentral_wizard_option{width:45%;float:left;text-align:center}.updraftcentral_wizard_option label{margin-bottom:8px}#updraftcentral_keys_table{display:none}.create_key_container{border:1px solid;border-radius:4px;padding:0 0 6px 6px;margin-bottom:8px}.updraftcentral-subheading{font-size:14px;margin-top:-10px;margin-bottom:20px}.updraftcentral-data-consent{font-size:13px;margin-bottom:10px}#updraftcentral_keys_table{width:100%}#updraftcentral_stage1_go{cursor:pointer}.updraftcentral_wizard_option>div{margin-top:5px}#updraftcentral_keys_table td{line-height:1.4em}#updraftcentral_keys_table .updraftcentral_key_delete{display:inline-block;margin-top:4px;margin-bottom:4px}#updraftcentral_keys_table .updraft_debugrow td{min-width:auto !important}
|
||||
/*# sourceMappingURL=central-1-25-3.min.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["central/css/central.css"],"names":[],"mappings":"AAAA;CACC,UAAU;CACV,WAAW;CACX,kBAAkB;AACnB;;AAEA;CACC,kBAAkB;AACnB;;AAEA;CACC,aAAa;AACd;;AAEA;CACC,iBAAiB;CACjB,kBAAkB;CAClB,oBAAoB;CACpB,kBAAkB;AACnB;;AAEA;CACC,eAAe;CACf,iBAAiB;CACjB,mBAAmB;AACpB;;AAEA;CACC,eAAe;CACf,mBAAmB;AACpB;;AAEA;CACC,WAAW;AACZ;;AAEA;CACC,eAAe;AAChB;;AAEA;CACC,eAAe;AAChB;;AAEA;CACC,kBAAkB;AACnB;;AAEA;CACC,qBAAqB;CACrB,eAAe;CACf,kBAAkB;AACnB;;AAEA;CACC,0BAA0B;AAC3B","file":"central-1-25-3.min.css","sourcesContent":[".updraftcentral_wizard_option {\n\twidth: 45%;\n\tfloat: left;\n\ttext-align: center;\n}\n\n.updraftcentral_wizard_option label {\n\tmargin-bottom: 8px;\n}\n\n#updraftcentral_keys_table {\n\tdisplay: none;\n}\n\n.create_key_container {\n\tborder: 1px solid;\n\tborder-radius: 4px;\n\tpadding: 0 0 6px 6px;\n\tmargin-bottom: 8px;\n}\n\n.updraftcentral-subheading {\n\tfont-size: 14px;\n\tmargin-top: -10px;\n\tmargin-bottom: 20px;\n}\n\n.updraftcentral-data-consent {\n\tfont-size: 13px;\n\tmargin-bottom: 10px;\n}\n\n#updraftcentral_keys_table {\n\twidth: 100%;\n}\n\n#updraftcentral_stage1_go {\n\tcursor: pointer;\n}\n\n.updraftcentral_wizard_option > div {\n\tmargin-top: 5px;\n}\n\n#updraftcentral_keys_table td {\n\tline-height: 1.4em;\n}\n\n#updraftcentral_keys_table .updraftcentral_key_delete {\n\tdisplay: inline-block;\n\tmargin-top: 4px;\n\tmargin-bottom: 4px;\n}\n\n#updraftcentral_keys_table .updraft_debugrow td {\n\tmin-width: auto !important;\n}\n"]}
|
||||
@@ -0,0 +1,57 @@
|
||||
.updraftcentral_wizard_option {
|
||||
width: 45%;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.updraftcentral_wizard_option label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.create_key_container {
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
padding: 0 0 6px 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.updraftcentral-subheading {
|
||||
font-size: 14px;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.updraftcentral-data-consent {
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#updraftcentral_stage1_go {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.updraftcentral_wizard_option > div {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table td {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table .updraftcentral_key_delete {
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table .updraft_debugrow td {
|
||||
min-width: auto !important;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_SET_TIME_LIMIT')) define('UPDRAFTCENTRAL_SET_TIME_LIMIT', 900);
|
||||
|
||||
// We bypass the class declaration if the class already existed. This usually happens if two or more
|
||||
// plugins integrated the same `UpdraftCentral` client folder.
|
||||
if (!class_exists('UpdraftCentral_Factory')) :
|
||||
|
||||
/**
|
||||
* Returns an instance of the host plugin class where the UpdraftCentral "central" folder is being
|
||||
* integrated.
|
||||
*/
|
||||
class UpdraftCentral_Factory {
|
||||
|
||||
/**
|
||||
* Creates a host plugin instance
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
public static function create_host() {
|
||||
|
||||
// All other plugins that wish to integrate the "central" libraries into their
|
||||
// codebase must use this filter (see WP-Optimize plugin as an example).
|
||||
$hosts = apply_filters('updraftcentral_host_plugins', array());
|
||||
|
||||
// If $hosts is empty then we return null
|
||||
if (empty($hosts)) return null;
|
||||
|
||||
// N.B. If multiple host plugins (e.g. updraftplus, wp-optimize, etc.) are currently
|
||||
// active then we only select one to handle all incoming UpdraftCentral requests for
|
||||
// this website in order to avoid conflicts and confusion especially when tracing or
|
||||
// debugging issues.
|
||||
//
|
||||
// You will know which plugin is currently serving and handling the request by checking
|
||||
// the "get_plugin_name" method of the global variable "$updraftcentral_host_plugin"
|
||||
// (e.g. $updraftcentral_host_plugin->get_plugin_name())
|
||||
//
|
||||
// N.B. You can add additional host plugins here. Just make sure that you will create
|
||||
// a host class for that particular plugin (see central/wp-optimize.php as an example).
|
||||
$mapped_classes = array(
|
||||
'updraftplus' => 'UpdraftPlus_Host',
|
||||
'wp-optimize' => 'WP_Optimize_Host',
|
||||
);
|
||||
|
||||
$path = $host_class = '';
|
||||
foreach ($hosts as $plugin) {
|
||||
// Make sure that we have a registered host class with a valid file that exist
|
||||
$host_file = dirname(__FILE__).'/'.$plugin.'.php';
|
||||
if (isset($mapped_classes[$plugin]) && file_exists($host_file)) {
|
||||
$path = $host_file;
|
||||
$host_class = $mapped_classes[$plugin];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The host file was not found under this plugin thus, we let the other plugins
|
||||
// create or build the host plugin (global) variable instead.
|
||||
if (empty($path)) return null;
|
||||
|
||||
if (!class_exists($host_class)) include_once($path);
|
||||
|
||||
// Re-check host class once again just to make sure that we have the desired
|
||||
// class loaded before calling its instance method
|
||||
if (class_exists($host_class)) {
|
||||
return call_user_func(array($host_class, 'instance'));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
$updraftcentral_host_plugin = UpdraftCentral_Factory::create_host();
|
||||
|
||||
if ($updraftcentral_host_plugin) {
|
||||
$updraftcentral_host_plugin->load_updraftcentral();
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
/**
|
||||
* The template definition for UpdraftCentral host
|
||||
*/
|
||||
abstract class UpdraftCentral_Host {
|
||||
|
||||
public $plugin_name;
|
||||
|
||||
public $translations;
|
||||
|
||||
public $error_reporting_stop_when_logged = false;
|
||||
|
||||
public $no_deprecation_warnings = false;
|
||||
|
||||
private $jobdata;
|
||||
|
||||
abstract protected function load_updraftcentral();
|
||||
abstract protected function is_host_dir_set();
|
||||
abstract protected function get_host_dir();
|
||||
abstract protected function get_version();
|
||||
abstract public function log($line, $level = 'notice', $uniq_id = false);
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action('wp_ajax_updraft_central_ajax', array($this, 'updraft_central_ajax_handler'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin name associated with this host class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_plugin_name() {
|
||||
return $this->plugin_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or shows a message from the translations collection based on its identifier key
|
||||
*
|
||||
* @param string $key The ID of the the message
|
||||
* @param bool $echo Indicate whether the message is to be shown directly (echoed) or just for retrieval
|
||||
*
|
||||
* @return string/void
|
||||
*/
|
||||
public function retrieve_show_message($key, $echo = false) {
|
||||
if (empty($key) || !isset($this->translations[$key])) return '';
|
||||
|
||||
if ($echo) {
|
||||
echo esc_html($this->translations[$key]);
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->translations[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a section to a designated area primarily used for generating UpdraftCentral keys
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function debugtools_dashboard() {
|
||||
if (!current_user_can('manage_options')) return;
|
||||
|
||||
global $updraftcentral_main;
|
||||
|
||||
if (!class_exists('UpdraftCentral_Main')) {
|
||||
if (defined('UPDRAFTCENTRAL_CLIENT_DIR') && file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/bootstrap.php')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/bootstrap.php');
|
||||
$updraftcentral_main = new UpdraftCentral_Main();
|
||||
}
|
||||
}
|
||||
|
||||
if ($updraftcentral_main) {
|
||||
$updraftcentral_main->debugtools_dashboard();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can perform key control AJAX actions
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function current_user_can_ajax() {
|
||||
return current_user_can('manage_options');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ajax requests coming from the section or area generated by the
|
||||
* "debugtools_dashboard" method (below)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updraft_central_ajax_handler() {
|
||||
global $updraftcentral_main;
|
||||
|
||||
$nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
|
||||
if (empty($nonce) || !wp_verify_nonce($nonce, 'updraftcentral-request-nonce') || !$this->current_user_can_ajax() || empty($_REQUEST['subaction'])) die('Security check');
|
||||
|
||||
if (is_a($updraftcentral_main, 'UpdraftCentral_Main')) {
|
||||
|
||||
$subaction = $_REQUEST['subaction'];
|
||||
if ($this->is_action_whitelisted($subaction) && is_callable(array($updraftcentral_main, $subaction))) {
|
||||
|
||||
// Undo WP's slashing of POST data
|
||||
$data = $this->wp_unslash($_POST);
|
||||
|
||||
// TODO: Once all commands come through here and through updraft_send_command(), the data should always come from this attribute (once updraft_send_command() is modified appropriately).
|
||||
if (isset($data['action_data'])) $data = $data['action_data'];
|
||||
try {
|
||||
|
||||
$results = call_user_func(array($updraftcentral_main, $subaction), $data);
|
||||
} catch (Exception $e) {
|
||||
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during '.$subaction.' subaction. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
echo json_encode(array(
|
||||
'fatal_error' => true,
|
||||
'fatal_error_message' => $log_message
|
||||
));
|
||||
die;
|
||||
// @codingStandardsIgnoreLine
|
||||
} catch (Error $e) {
|
||||
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during '.$subaction.' subaction. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
echo json_encode(array(
|
||||
'fatal_error' => true,
|
||||
'fatal_error_message' => $log_message
|
||||
));
|
||||
die;
|
||||
}
|
||||
if (is_wp_error($results)) {
|
||||
$results = array(
|
||||
'result' => false,
|
||||
'error_code' => $results->get_error_code(),
|
||||
'error_message' => $results->get_error_message(),
|
||||
'error_data' => $results->get_error_data(),
|
||||
);
|
||||
}
|
||||
|
||||
if (is_string($results)) {
|
||||
// A handful of legacy methods, and some which are directly the source for iframes, for which JSON is not appropriate.
|
||||
echo $results; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- We don't escape here to avoid double escaping and keep the HTML code needed by the receiver of this request.
|
||||
} else {
|
||||
echo json_encode($results);
|
||||
}
|
||||
die;
|
||||
}
|
||||
}
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether the submitted action is valid and allowed for execution over AJAX
|
||||
*
|
||||
* @param string $action The action to execute
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_action_whitelisted($action) {
|
||||
$allowed_actions = array('delete_key', 'get_log', 'create_key');
|
||||
return in_array($action, $allowed_actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the filter used by UpdraftCentral to log errors or certain events
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_logline_filter() {
|
||||
return 'updraftcentral_logline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an RPC object, and sets some defaults on it that we always want
|
||||
*
|
||||
* @param string $indicator_name indicator name
|
||||
* @return array
|
||||
*/
|
||||
public function get_udrpc($indicator_name = 'migrator.updraftplus.com') {
|
||||
global $updraftplus;
|
||||
$updraftplus->ensure_phpseclib();
|
||||
if (!class_exists('UpdraftPlus_Remote_Communications_V2')) include_once($this->get_host_dir().'/vendor/team-updraft/common-libs/src/updraft-rpc/class-udrpc2.php');
|
||||
$ud_rpc = new UpdraftPlus_Remote_Communications_V2($indicator_name);
|
||||
$ud_rpc->set_can_generate(true);
|
||||
return $ud_rpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Noop method.
|
||||
* Depending on the host plugin this method may or may not be used.
|
||||
*
|
||||
* N.B. The UpdraftPlus plugin is using and overriding this method in its host file.
|
||||
*
|
||||
* @param boolean $register Indicate whether to add or remote filter hooks
|
||||
* @ignore
|
||||
*/
|
||||
// @codingStandardsIgnoreLine
|
||||
public function register_wp_http_option_hooks($register = true) {}
|
||||
|
||||
/**
|
||||
* Remove slashes from a string or array of strings.
|
||||
*
|
||||
* The function wp_unslash() is WP 3.6+, so therefore we have a compatibility method here
|
||||
*
|
||||
* @param String|Array $value String or array of strings to unslash.
|
||||
* @return String|Array Unslashed $value
|
||||
*/
|
||||
public function wp_unslash($value) {
|
||||
return function_exists('wp_unslash') ? wp_unslash($value) : stripslashes_deep($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a log line based from the PHP error information
|
||||
*
|
||||
* @param Integer $errno Error number
|
||||
* @param String $errstr Error string
|
||||
* @param String $errfile Error file
|
||||
* @param String $errline Line number where the error occurred
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function php_error_to_logline($errno, $errstr, $errfile, $errline) {
|
||||
switch ($errno) {
|
||||
case 1:
|
||||
$e_type = 'E_ERROR';
|
||||
break;
|
||||
case 2:
|
||||
$e_type = 'E_WARNING';
|
||||
break;
|
||||
case 4:
|
||||
$e_type = 'E_PARSE';
|
||||
break;
|
||||
case 8:
|
||||
$e_type = 'E_NOTICE';
|
||||
break;
|
||||
case 16:
|
||||
$e_type = 'E_CORE_ERROR';
|
||||
break;
|
||||
case 32:
|
||||
$e_type = 'E_CORE_WARNING';
|
||||
break;
|
||||
case 64:
|
||||
$e_type = 'E_COMPILE_ERROR';
|
||||
break;
|
||||
case 128:
|
||||
$e_type = 'E_COMPILE_WARNING';
|
||||
break;
|
||||
case 256:
|
||||
$e_type = 'E_USER_ERROR';
|
||||
break;
|
||||
case 512:
|
||||
$e_type = 'E_USER_WARNING';
|
||||
break;
|
||||
case 1024:
|
||||
$e_type = 'E_USER_NOTICE';
|
||||
break;
|
||||
case 2048:
|
||||
$e_type = 'E_STRICT';
|
||||
break;
|
||||
case 4096:
|
||||
$e_type = 'E_RECOVERABLE_ERROR';
|
||||
break;
|
||||
case 8192:
|
||||
$e_type = 'E_DEPRECATED';
|
||||
break;
|
||||
case 16384:
|
||||
$e_type = 'E_USER_DEPRECATED';
|
||||
break;
|
||||
case 30719:
|
||||
$e_type = 'E_ALL';
|
||||
break;
|
||||
default:
|
||||
$e_type = "E_UNKNOWN ($errno)";
|
||||
break;
|
||||
}
|
||||
|
||||
if (false !== stripos($errstr, 'table which is not valid in this version of Gravity Forms')) return false;
|
||||
|
||||
if (!is_string($errstr)) $errstr = serialize($errstr);
|
||||
|
||||
if (0 === strpos($errfile, ABSPATH)) $errfile = substr($errfile, strlen(ABSPATH));
|
||||
|
||||
if ('E_DEPRECATED' == $e_type && !empty($this->no_deprecation_warnings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return "PHP event: code $e_type: $errstr (line $errline, $errfile)";
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP error handler
|
||||
*
|
||||
* @param Integer $errno Error number
|
||||
* @param String $errstr Error string
|
||||
* @param String $errfile Error file
|
||||
* @param String $errline Line number where the error occurred
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function php_error($errno, $errstr, $errfile, $errline) {
|
||||
if (0 == error_reporting()) return true;
|
||||
$logline = $this->php_error_to_logline($errno, $errstr, $errfile, $errline);
|
||||
if (false !== $logline) $this->log($logline, 'notice', 'php_event');
|
||||
// Pass it up the chain
|
||||
return $this->error_reporting_stop_when_logged;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1,436 @@
|
||||
/**
|
||||
* Send an action over AJAX. A wrapper around jQuery.ajax. In future, all consumers can be reviewed to simplify some of the options, where there is historical cruft.
|
||||
* N.B. updraft_iframe_modal() below uses the AJAX URL for the iframe's src attribute
|
||||
*
|
||||
* @param {string} action - the action to send
|
||||
* @param {*} data - data to send
|
||||
* @param {Function} callback - will be called with the results
|
||||
* @param {object} options -further options. Relevant properties include:
|
||||
* - [json_parse=true] - whether to JSON parse the results
|
||||
* - [alert_on_error=true] - whether to show an alert box if there was a problem (otherwise, suppress it)
|
||||
* - [action='updraft_ajax'] - what to send as the action parameter on the AJAX request (N.B. action parameter to this function goes as the 'subaction' parameter on the AJAX request)
|
||||
* - [nonce=updraft_credentialtest_nonce] - the nonce value to send.
|
||||
* - [nonce_key='nonce'] - the key value for the nonce field
|
||||
* - [timeout=null] - set a timeout after this number of seconds (or if null, none is set)
|
||||
* - [async=true] - control whether the request is asynchronous (almost always wanted) or blocking (would need to have a specific reason)
|
||||
* - [type='POST'] - GET or POST
|
||||
*/
|
||||
function updraftcentral_send_command(action, data, callback, options) {
|
||||
|
||||
default_options = {
|
||||
json_parse: true,
|
||||
alert_on_error: true,
|
||||
action: 'updraft_central_ajax',
|
||||
nonce_key: 'nonce',
|
||||
timeout: null,
|
||||
async: true,
|
||||
type: 'POST'
|
||||
}
|
||||
|
||||
if ('undefined' !== typeof uclion.updraftcentral_request_nonce && uclion.updraftcentral_request_nonce) {
|
||||
default_options.nonce = uclion.updraftcentral_request_nonce;
|
||||
}
|
||||
|
||||
if ('undefined' === typeof options) options = {};
|
||||
|
||||
for (var opt in default_options) {
|
||||
if (!options.hasOwnProperty(opt)) { options[opt] = default_options[opt]; }
|
||||
}
|
||||
|
||||
var ajax_data = {
|
||||
action: options.action,
|
||||
subaction: action,
|
||||
};
|
||||
|
||||
ajax_data[options.nonce_key] = options.nonce;
|
||||
ajax_data.action_data = data;
|
||||
|
||||
var ajax_opts = {
|
||||
type: options.type,
|
||||
url: ajaxurl,
|
||||
data: ajax_data,
|
||||
success: function(response, status) {
|
||||
if (options.json_parse) {
|
||||
try {
|
||||
var resp = central_parse_json(response);
|
||||
} catch (e) {
|
||||
if ('function' == typeof options.error_callback) {
|
||||
return options.error_callback(response, e, 502, resp);
|
||||
} else {
|
||||
console.log(e);
|
||||
console.log(response);
|
||||
if (options.alert_on_error) { alert(uclion.unexpectedresponse+' '+response); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (resp.hasOwnProperty('fatal_error')) {
|
||||
if ('function' == typeof options.error_callback) {
|
||||
// 500 is internal server error code
|
||||
return options.error_callback(response, status, 500, resp);
|
||||
} else {
|
||||
console.error(resp.fatal_error_message);
|
||||
if (options.alert_on_error) { alert(resp.fatal_error_message); }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ('function' == typeof callback) callback(resp, status, response);
|
||||
} else {
|
||||
if ('function' == typeof callback) callback(response, status);
|
||||
}
|
||||
},
|
||||
error: function(response, status, error_code) {
|
||||
if ('function' == typeof options.error_callback) {
|
||||
options.error_callback(response, status, error_code);
|
||||
} else {
|
||||
console.log("updraftcentral_send_command: error: "+status+" ("+error_code+")");
|
||||
console.log(response);
|
||||
}
|
||||
},
|
||||
dataType: 'text',
|
||||
async: options.async
|
||||
};
|
||||
|
||||
if (null != options.timeout) { ajax_opts.timeout = options.timeout; }
|
||||
|
||||
jQuery.ajax(ajax_opts);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON string, including automatically detecting unwanted extra input and skipping it
|
||||
*
|
||||
* @param {string} json_mix_str - JSON string which need to parse and convert to object
|
||||
* @param {boolean} analyse - if true, then the return format will contain information on the parsing, and parsing will skip attempting to JSON.parse() the entire string (will begin with trying to locate the actual JSON)
|
||||
*
|
||||
* @throws SyntaxError|String (including passing on what JSON.parse may throw) if a parsing error occurs.
|
||||
*
|
||||
* @returns Mixed parsed JSON object. Will only return if parsing is successful (otherwise, will throw). If analyse is true, then will rather return an object with properties (mixed)parsed, (integer)json_start_pos and (integer)json_end_pos
|
||||
*/
|
||||
function central_parse_json(json_mix_str, analyse) {
|
||||
|
||||
analyse = ('undefined' === typeof analyse) ? false : true;
|
||||
|
||||
// Just try it - i.e. the 'default' case where things work (which can include extra whitespace/line-feeds, and simple strings, etc.).
|
||||
if (!analyse) {
|
||||
try {
|
||||
var result = JSON.parse(json_mix_str);
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.log(uclion.plugin_name+': Exception when trying to parse JSON (1) - will attempt to fix/re-parse based upon first/last curly brackets');
|
||||
console.log(json_mix_str);
|
||||
}
|
||||
}
|
||||
|
||||
var json_start_pos = json_mix_str.indexOf('{');
|
||||
var json_last_pos = json_mix_str.lastIndexOf('}');
|
||||
|
||||
// Case where some php notice may be added after or before json string
|
||||
if (json_start_pos > -1 && json_last_pos > -1) {
|
||||
var json_str = json_mix_str.slice(json_start_pos, json_last_pos + 1);
|
||||
try {
|
||||
var parsed = JSON.parse(json_str);
|
||||
if (!analyse) { console.log(uclion.plugin_name+': JSON re-parse successful'); }
|
||||
return analyse ? { parsed: parsed, json_start_pos: json_start_pos, json_last_pos: json_last_pos + 1 } : parsed;
|
||||
} catch (e) {
|
||||
console.log(uclion.plugin_name+': Exception when trying to parse JSON (2) - will attempt to fix/re-parse based upon bracket counting');
|
||||
|
||||
var cursor = json_start_pos;
|
||||
var open_count = 0;
|
||||
var last_character = '';
|
||||
var inside_string = false;
|
||||
|
||||
// Don't mistake this for a real JSON parser. Its aim is to improve the odds in real-world cases seen, not to arrive at universal perfection.
|
||||
while ((open_count > 0 || cursor == json_start_pos) && cursor <= json_last_pos) {
|
||||
|
||||
var current_character = json_mix_str.charAt(cursor);
|
||||
|
||||
if (!inside_string && '{' == current_character) {
|
||||
open_count++;
|
||||
} else if (!inside_string && '}' == current_character) {
|
||||
open_count--;
|
||||
} else if ('"' == current_character && '\\' != last_character) {
|
||||
inside_string = inside_string ? false : true;
|
||||
}
|
||||
|
||||
last_character = current_character;
|
||||
cursor++;
|
||||
}
|
||||
console.log("Started at cursor="+json_start_pos+", ended at cursor="+cursor+" with result following:");
|
||||
console.log(json_mix_str.substring(json_start_pos, cursor));
|
||||
|
||||
try {
|
||||
var parsed = JSON.parse(json_mix_str.substring(json_start_pos, cursor));
|
||||
console.log(uclion.plugin_name+': JSON re-parse successful');
|
||||
return analyse ? { parsed: parsed, json_start_pos: json_start_pos, json_last_pos: cursor } : parsed;
|
||||
} catch (e) {
|
||||
// Throw it again, so that our function works just like JSON.parse() in its behaviour.
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw uclion.plugin_name+": could not parse the JSON";
|
||||
|
||||
}
|
||||
|
||||
jQuery(function($) {
|
||||
$('#updraftcentral_keys').on('click', 'a.updraftcentral_keys_show', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).remove();
|
||||
$('#updraftcentral_keys_table').slideDown();
|
||||
});
|
||||
|
||||
$('#updraftcentral_keycreate_altmethod_moreinfo_get').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).remove();
|
||||
$('#updraftcentral_keycreate_altmethod_moreinfo').slideDown();
|
||||
});
|
||||
|
||||
function updraftcentral_keys_setupform(on_page_load) {
|
||||
var is_other = jQuery('#updraftcentral_mothership_other').is(':checked') ? true : false;
|
||||
if (is_other) {
|
||||
jQuery('#updraftcentral_keycreate_mothership').prop('disabled', false);
|
||||
if (on_page_load) {
|
||||
jQuery('#updraftcentral_keycreate_mothership_firewalled_container').show();
|
||||
} else {
|
||||
jQuery('.updraftcentral_wizard_self_hosted_stage2').show();
|
||||
jQuery('#updraftcentral_keycreate_mothership_firewalled_container').slideDown();
|
||||
jQuery('#updraftcentral_keycreate_mothership').trigger('focus');
|
||||
}
|
||||
} else {
|
||||
jQuery('#updraftcentral_keycreate_mothership').prop('disabled', true);
|
||||
if (!on_page_load) {
|
||||
jQuery('.updraftcentral_wizard_self_hosted_stage2').hide();
|
||||
updraftcentral_stage2_go();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updraftcentral_stage2_go() {
|
||||
// Reset the error message before we continue
|
||||
jQuery('#updraftcentral_wizard_stage1_error').text('');
|
||||
|
||||
var host = '';
|
||||
|
||||
if (jQuery('#updraftcentral_mothership_updraftpluscom').is(':checked')) {
|
||||
jQuery('.updraftcentral_keycreate_description').hide();
|
||||
host = 'updraftplus.com';
|
||||
} else if (jQuery('#updraftcentral_mothership_other').is(':checked')) {
|
||||
jQuery('.updraftcentral_keycreate_description').show();
|
||||
var mothership = jQuery('#updraftcentral_keycreate_mothership').val();
|
||||
if ('' == mothership) {
|
||||
jQuery('#updraftcentral_wizard_stage1_error').text(uclion.updraftcentral_wizard_empty_url);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var url = new URL(mothership);
|
||||
host = url.hostname;
|
||||
} catch (e) {
|
||||
// Try and grab the host name a different way if it failed because of no URL object (e.g. Firefox version 25 and below).
|
||||
if ('undefined' === typeof URL) {
|
||||
host = jQuery('<a>').prop('href', mothership).prop('hostname');
|
||||
}
|
||||
if (!host || 'undefined' !== typeof URL) {
|
||||
jQuery('#updraftcentral_wizard_stage1_error').text(uclion.updraftcentral_wizard_invalid_url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_keycreate_description').val(host);
|
||||
|
||||
jQuery('.updraftcentral_wizard_stage1').hide();
|
||||
jQuery('.updraftcentral_wizard_stage2').show();
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', 'input[type="radio"]', function() {
|
||||
updraftcentral_keys_setupform(false);
|
||||
});
|
||||
// Initial setup (for browsers, e.g. Firefox, that remember form selection state but not DOM state, which can leave an inconsistent state)
|
||||
updraftcentral_keys_setupform(true);
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_view_log', function(e) {
|
||||
e.preventDefault();
|
||||
jQuery('#updraftcentral_view_log_container').block({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+uclion.central_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+uclion.fetching+'</div>'});
|
||||
try {
|
||||
updraftcentral_send_command('get_log', null, function(response) {
|
||||
jQuery('#updraftcentral_view_log_container').unblock();
|
||||
if (response.hasOwnProperty('log_contents')) {
|
||||
jQuery('#updraftcentral_view_log_contents').html('<div style="border:1px solid;padding: 2px;max-height: 400px; overflow-y:scroll;">'+response.log_contents+'</div>');
|
||||
} else {
|
||||
console.log(response);
|
||||
}
|
||||
}, { error_callback: function(response, status, error_code, resp) {
|
||||
jQuery('#updraftcentral_view_log_container').unblock();
|
||||
if (typeof resp !== 'undefined' && resp.hasOwnProperty('fatal_error')) {
|
||||
console.error(resp.fatal_error_message);
|
||||
alert(resp.fatal_error_message);
|
||||
} else {
|
||||
var error_message = "updraftcentral_send_command: error: "+status+" ("+error_code+")";
|
||||
console.log(error_message);
|
||||
alert(error_message);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
jQuery('#updraft_central_key').html();
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
// UpdraftCentral
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_wizard_go', function(e) {
|
||||
jQuery('#updraftcentral_wizard_go').hide();
|
||||
jQuery('.updraftcentral_wizard_success').remove();
|
||||
jQuery('.create_key_container').show();
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_stage1_go', function(e) {
|
||||
e.preventDefault();
|
||||
jQuery('.updraftcentral_wizard_stage2').hide();
|
||||
jQuery('.updraftcentral_wizard_stage1').show();
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_stage2_go', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
updraftcentral_stage2_go();
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_keycreate_go', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var is_other = jQuery('#updraftcentral_mothership_other').is(':checked') ? true : false;
|
||||
|
||||
var key_description = jQuery('#updraftcentral_keycreate_description').val();
|
||||
var key_size = jQuery('#updraftcentral_keycreate_keysize').val();
|
||||
|
||||
var where_send = '__updraftpluscom';
|
||||
|
||||
data = {
|
||||
key_description: key_description,
|
||||
key_size: key_size,
|
||||
};
|
||||
|
||||
if (is_other) {
|
||||
where_send = jQuery('#updraftcentral_keycreate_mothership').val();
|
||||
if (where_send.substring(0, 4) != 'http') {
|
||||
alert(uclion.enter_mothership_url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data.mothership_firewalled = jQuery('#updraftcentral_keycreate_mothership_firewalled').is(':checked') ? 1 : 0;
|
||||
data.where_send = where_send;
|
||||
|
||||
jQuery('.create_key_container').hide();
|
||||
jQuery('.updraftcentral_wizard_stage1').show();
|
||||
jQuery('.updraftcentral_wizard_stage2').hide();
|
||||
|
||||
jQuery('#updraftcentral_keys').block({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+uclion.central_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+uclion.creating_please_allow+'</div>'});
|
||||
|
||||
try {
|
||||
updraftcentral_send_command('create_key', data, function(resp) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
try {
|
||||
if (resp.hasOwnProperty('error')) {
|
||||
alert(resp.error);
|
||||
console.log(resp);
|
||||
return;
|
||||
}
|
||||
alert(resp.r);
|
||||
|
||||
if (resp.hasOwnProperty('bundle') && resp.hasOwnProperty('keys_guide')) {
|
||||
jQuery('#updraftcentral_keys_content').html(resp.keys_guide);
|
||||
jQuery('#updraftcentral_keys_content').append('<div class="updraftcentral_wizard_success">'+resp.r+'<br><textarea id="updraftcentral-key" onclick="this.select();" style="width:620px; height:165px; word-wrap:break-word; border: 1px solid #aaa; border-radius: 3px; padding:4px;">'+resp.bundle+'</textarea><button id="updraftplus-copy" class="button button-secondary" style="display: block;">'+uclion.copy_to_clipboard+'</button></div>');
|
||||
} else {
|
||||
console.log(resp);
|
||||
}
|
||||
|
||||
if (resp.hasOwnProperty('keys_table')) {
|
||||
jQuery('#updraftcentral_keys_content').append(resp.keys_table);
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_wizard_go').show();
|
||||
|
||||
} catch (err) {
|
||||
alert(uclion.unexpectedresponse+' '+response);
|
||||
console.log(err);
|
||||
}
|
||||
}, { error_callback: function(response, status, error_code, resp) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
if (typeof resp !== 'undefined' && resp.hasOwnProperty('fatal_error')) {
|
||||
console.error(resp.fatal_error_message);
|
||||
alert(resp.fatal_error_message);
|
||||
} else {
|
||||
var error_message = "updraftcentral_send_command: error: "+status+" ("+error_code+")";
|
||||
console.log(error_message);
|
||||
alert(error_message);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
jQuery('#updraft_central_key').html();
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var updraft_copy_modal_buttons = {};
|
||||
updraft_copy_modal_buttons[updraftlion.close] = function() {
|
||||
jQuery(this).dialog("close");
|
||||
};
|
||||
|
||||
jQuery("#updraft-copy-modal").dialog({
|
||||
autoOpen: false,
|
||||
resizeOnWindowResize: true,
|
||||
scrollWithViewport: true,
|
||||
resizeAccordingToViewport: true,
|
||||
modal: true,
|
||||
buttons: updraft_copy_modal_buttons,
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys_content').on('click', '#updraftplus-copy', function(e) {
|
||||
e.preventDefault();
|
||||
var ele = jQuery('#updraftcentral-key');
|
||||
if (ele[0].value) {
|
||||
navigator.clipboard.writeText(ele[0].value).then(function() {
|
||||
alert(uclion.key_copied);
|
||||
}, function(err) {
|
||||
jQuery('#updraft-copy-modal').dialog('open');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '.updraftcentral_key_delete', function(e) {
|
||||
e.preventDefault();
|
||||
var key_id = jQuery(this).data('key_id');
|
||||
if ('undefined' == typeof key_id) {
|
||||
console.log("UpdraftPlus: .updraftcentral_key_delete clicked, but no key ID found");
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_keys').block({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+uclion.central_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+uclion.deleting+'</div>'});
|
||||
|
||||
updraftcentral_send_command('delete_key', { key_id: key_id }, function(response) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
if (response.hasOwnProperty('keys_table')) {
|
||||
jQuery('#updraftcentral_keys_content').html(response.keys_table);
|
||||
}
|
||||
}, { error_callback: function(response, status, error_code, resp) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
if (typeof resp !== 'undefined' && resp.hasOwnProperty('fatal_error')) {
|
||||
console.error(resp.fatal_error_message);
|
||||
alert(resp.fatal_error_message);
|
||||
} else {
|
||||
var error_message = "updraftcentral_send_command: error: "+status+" ("+error_code+")";
|
||||
console.log(error_message);
|
||||
alert(error_message);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* This class is the basic glue between the lower-level Remote Communications (RPC) class in UpdraftCentral, and the host plugin. It does not contain actual commands themselves; the class names to use for actual commands are passed in as a parameter to the constructor.
|
||||
*/
|
||||
class UpdraftCentral_Listener {
|
||||
|
||||
public $udrpc_version;
|
||||
|
||||
private $host = null;
|
||||
|
||||
private $receivers = array();
|
||||
|
||||
private $extra_info = array();
|
||||
|
||||
private $php_events = array();
|
||||
|
||||
private $commands = array();
|
||||
|
||||
private $current_udrpc = null;
|
||||
|
||||
private $command_classes;
|
||||
|
||||
private $auto_logged_in_cookie;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Array $keys - keys to set up listeners for
|
||||
* @param Array $command_classes - commands
|
||||
*/
|
||||
public function __construct($keys = array(), $command_classes = array()) {
|
||||
global $updraftcentral_host_plugin;
|
||||
$this->host = $updraftcentral_host_plugin;
|
||||
|
||||
// It seems impossible for this condition to result in a return; but it seems Plesk can do something odd within the control panel that causes a problem - see HS#6276
|
||||
if (!is_a($this->host, 'UpdraftCentral_Host')) return;
|
||||
|
||||
$this->command_classes = $command_classes;
|
||||
|
||||
foreach ($keys as $name_hash => $key) {
|
||||
// publickey_remote isn't necessarily set yet, depending on the key exchange method
|
||||
if (!is_array($key) || empty($key['extra_info']) || empty($key['publickey_remote'])) continue;
|
||||
$indicator = $name_hash.'.central.updraftplus.com';
|
||||
$ud_rpc = $this->host->get_udrpc($indicator);
|
||||
$this->udrpc_version = $ud_rpc->version;
|
||||
|
||||
// Only turn this on if you are comfortable with potentially anything appearing in your PHP error log
|
||||
if (defined('UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG') && UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG) $ud_rpc->set_debug(true);
|
||||
|
||||
$this->receivers[$indicator] = $ud_rpc;
|
||||
$this->extra_info[$indicator] = isset($key['extra_info']) ? $key['extra_info'] : null;
|
||||
$ud_rpc->set_key_local($key['key']);
|
||||
$ud_rpc->set_key_remote($key['publickey_remote']);
|
||||
// Create listener (which causes WP actions to be fired when messages are received)
|
||||
$ud_rpc->activate_replay_protection();
|
||||
if (!empty($key['extra_info']) && isset($key['extra_info']['mothership'])) {
|
||||
$mothership = $key['extra_info']['mothership'];
|
||||
$url = '';
|
||||
if ('__updraftpluscom' == $mothership) {
|
||||
$url = 'https://teamupdraft.com';
|
||||
} elseif (false != ($parsed = parse_url($key['extra_info']['mothership'])) && is_array($parsed)) {
|
||||
$url = $parsed['scheme'].'://'.$parsed['host'];
|
||||
}
|
||||
if (!empty($url)) $ud_rpc->set_allow_cors_from(array($url));
|
||||
}
|
||||
$ud_rpc->create_listener();
|
||||
}
|
||||
|
||||
// If we ever need to expand beyond a single GET action, this can/should be generalised and put into the commands class
|
||||
if (!empty($_GET['udcentral_action']) && 'login' == $_GET['udcentral_action']) {
|
||||
// auth_redirect() does not return, according to the documentation; but the code shows that it can
|
||||
// auth_redirect();
|
||||
|
||||
if (!empty($_GET['login_id']) && is_numeric($_GET['login_id']) && !empty($_GET['login_key'])) {
|
||||
$login_user = get_user_by('id', $_GET['login_id']);
|
||||
|
||||
// THis is included so we can get $wp_version
|
||||
include_once(ABSPATH.WPINC.'/version.php');
|
||||
|
||||
if (is_a($login_user, 'WP_User') || (version_compare($wp_version, '3.5', '<') && !empty($login_user->ID))) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
|
||||
// Allow site implementers to disable this functionality
|
||||
$allow_autologin = apply_filters('updraftcentral_allow_autologin', true, $login_user);
|
||||
if ($allow_autologin) {
|
||||
$login_key = get_user_meta($login_user->ID, 'updraftcentral_login_key', true);
|
||||
if (is_array($login_key) && !empty($login_key['created']) && $login_key['created'] > time() - 60 && !empty($login_key['key']) && $login_key['key'] == $_GET['login_key']) {
|
||||
$autologin = empty($login_key['redirect_url']) ? network_admin_url() : $login_key['redirect_url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($autologin)) {
|
||||
// Allow use once only
|
||||
delete_user_meta($login_user->ID, 'updraftcentral_login_key');
|
||||
$this->autologin_user($login_user, $autologin);
|
||||
}
|
||||
}
|
||||
|
||||
add_filter('udrpc_action', array($this, 'udrpc_action'), 10, 5);
|
||||
add_filter('updraftcentral_get_command_info', array($this, 'updraftcentral_get_command_info'), 10, 2);
|
||||
add_filter('updraftcentral_get_updraftplus_status', array($this, 'get_updraftplus_status'), 10, 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdraftPlus plugin status whether it has been installed or activated
|
||||
*
|
||||
* @param mixed $data Default data to return
|
||||
* @return array
|
||||
*/
|
||||
public function get_updraftplus_status($data) {
|
||||
|
||||
// Handle cases of users who rename their plugin folders
|
||||
if (class_exists('UpdraftPlus')) {
|
||||
$data['is_updraftplus_installed'] = true;
|
||||
$data['is_updraftplus_active'] = true;
|
||||
} else {
|
||||
if (!function_exists('get_plugins')) require_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$plugins = get_plugins();
|
||||
$key = 'updraftplus/updraftplus.php';
|
||||
|
||||
if (array_key_exists($key, $plugins)) {
|
||||
$data['is_updraftplus_installed'] = true;
|
||||
if (is_plugin_active($key)) $data['is_updraftplus_active'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves command class information and includes class file if class
|
||||
* is currently not available.
|
||||
*
|
||||
* @param mixed $response The default response to return if the submitted command does not exists
|
||||
* @param string $command The command to parse and check
|
||||
* @return array Contains the following command information "command_php_class", "class_prefix" and "command"
|
||||
*/
|
||||
public function updraftcentral_get_command_info($response, $command) {
|
||||
if (!preg_match('/^([a-z0-9]+)\.(.*)$/', $command, $matches)) return $response;
|
||||
$class_prefix = $matches[1];
|
||||
$command = $matches[2];
|
||||
|
||||
// Other plugins might have registered the filter rather later so we need to make
|
||||
// sure that we get all the commands intended for UpdraftCentral.
|
||||
$this->command_classes = apply_filters('updraftcentral_remotecontrol_command_classes', $this->command_classes);
|
||||
|
||||
// We only handle some commands - the others, we let something else deal with
|
||||
if (!isset($this->command_classes[$class_prefix])) return $response;
|
||||
|
||||
$command_php_class = $this->command_classes[$class_prefix];
|
||||
$command_base_class_at = apply_filters('updraftcentral_command_base_class_at', UPDRAFTCENTRAL_CLIENT_DIR.'/commands.php');
|
||||
|
||||
if (!class_exists('UpdraftCentral_Commands')) include_once($command_base_class_at);
|
||||
|
||||
// Second parameter has been passed since
|
||||
do_action('updraftcentral_command_class_wanted', $command_php_class);
|
||||
|
||||
if (!class_exists($command_php_class)) {
|
||||
if (file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/modules/'.$class_prefix.'.php')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/modules/'.$class_prefix.'.php');
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'command_php_class' => $command_php_class,
|
||||
'class_prefix' => $class_prefix,
|
||||
'command' => $command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* In response to auto logging in the user; set a corresponding logged_in cookie to the $login_user_cookie class variable
|
||||
*
|
||||
* @param String $cookie Authentication cookie
|
||||
* @param Integer $user_id User ID
|
||||
* @param Integer $expiration The time the cookie expires as a UNIX timestamp
|
||||
* @param String $scheme Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'
|
||||
*/
|
||||
public function set_global_logged_in_cookie($cookie, $user_id, $expiration, $scheme) {
|
||||
if ('logged_in' === $scheme) {
|
||||
$this->auto_logged_in_cookie = $cookie;
|
||||
}
|
||||
return $cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do verification before calling this method
|
||||
*
|
||||
* @param WP_User|Object $user user object for autologin
|
||||
* @param boolean $redirect_url Redirect URL
|
||||
*/
|
||||
private function autologin_user($user, $redirect_url = false) {
|
||||
if (!is_user_logged_in()) {
|
||||
// $user = get_user_by('id', $user_id);
|
||||
// Don't check that it's a WP_User - that's WP 3.5+ only
|
||||
if (!is_object($user) || empty($user->ID)) return;
|
||||
wp_set_current_user($user->ID, $user->user_login);
|
||||
add_filter('auth_cookie', array($this, 'set_global_logged_in_cookie'), 10, 4);
|
||||
wp_set_auth_cookie($user->ID);
|
||||
remove_filter('auth_cookie', array($this, 'set_global_logged_in_cookie'), 10, 4);
|
||||
do_action('wp_login', $user->user_login, $user);
|
||||
}
|
||||
if ($redirect_url) {
|
||||
// the wp_set_auth_cookie() above uses setcookie() function but the corresponding LOGGED_IN_COOKIE variable is visible and can only be accessible on the next page load
|
||||
// so we set the auth cookie into the superglobal $_COOKIE variable manually, we do this because the previously non logged-in user is now being auto-logged in and wp_create_nonce() needs the value of LOGGED_IN_COOKIE variable to produce a correct nonce
|
||||
if ($this->auto_logged_in_cookie) $_COOKIE[LOGGED_IN_COOKIE] = $this->auto_logged_in_cookie;
|
||||
$redirect_url = add_query_arg('restore_initiation_nonce', wp_create_nonce('updraftplus_udcentral_initiate_restore'), $redirect_url);
|
||||
if ($this->auto_logged_in_cookie) unset($_COOKIE[LOGGED_IN_COOKIE]);
|
||||
wp_safe_redirect($redirect_url);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WP filter udrpc_action
|
||||
*
|
||||
* @param Array $response - the unfiltered response that will be returned
|
||||
* @param String $command - the command being called
|
||||
* @param Array $data - the parameters to the command
|
||||
* @param String $key_name_indicator - the UC key that is in use
|
||||
* @param Object $ud_rpc - the UDRP object
|
||||
*
|
||||
* @return Array - filtered response
|
||||
*/
|
||||
public function udrpc_action($response, $command, $data, $key_name_indicator, $ud_rpc) {
|
||||
try {
|
||||
|
||||
if (empty($this->receivers[$key_name_indicator])) return $response;
|
||||
|
||||
// This can be used to detect an UpdraftCentral context
|
||||
if (!defined('UPDRAFTCENTRAL_COMMAND')) define('UPDRAFTCENTRAL_COMMAND', $command);
|
||||
|
||||
$this->initialise_listener_error_handling();
|
||||
|
||||
// UpdraftCentral needs this extra information especially now that the UpdraftCentral
|
||||
// libraries can be totally embedded in other plugins (e.g. WP-Optimize, etc.) thus,
|
||||
// that makes the UpdraftPlus plugin optional.
|
||||
//
|
||||
// This will give UpdraftCentral a proper way of disabling the backup feature
|
||||
// for this site if the UpdraftPlus plugin is currently not installed or activated.
|
||||
//
|
||||
// In addition, we need to attached the host plugin who is handling the UpdraftCentral requests
|
||||
global $updraftcentral_host_plugin;
|
||||
$extra = apply_filters('updraftcentral_get_updraftplus_status', array(
|
||||
'is_updraftplus_installed' => false,
|
||||
'is_updraftplus_active' => false,
|
||||
'host_plugin' => $updraftcentral_host_plugin->plugin_name,
|
||||
));
|
||||
|
||||
$command_info = apply_filters('updraftcentral_get_command_info', false, $command);
|
||||
if (!$command_info) {
|
||||
if (isset($response['data']) && is_array($response['data'])) $response['data']['extra'] = $extra;
|
||||
return $response;
|
||||
}
|
||||
|
||||
$class_prefix = $command_info['class_prefix'];
|
||||
$command = $command_info['command'];
|
||||
$command_php_class = $command_info['command_php_class'];
|
||||
|
||||
if (empty($this->commands[$class_prefix])) {
|
||||
if (class_exists($command_php_class)) {
|
||||
$this->commands[$class_prefix] = new $command_php_class($this);
|
||||
}
|
||||
}
|
||||
|
||||
$command_class = isset($this->commands[$class_prefix]) ? $this->commands[$class_prefix] : new stdClass;
|
||||
|
||||
if ('_' == substr($command, 0, 1) || !is_a($command_class, $command_php_class) || (!method_exists($command_class, $command) && !method_exists($command_class, '__call'))) {
|
||||
if (defined('UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG') && UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG) error_log("Unknown RPC command received: ".$command);
|
||||
|
||||
return $this->return_rpc_message(array('response' => 'rpcerror', 'data' => array('code' => 'unknown_rpc_command', 'data' => array('prefix' => $class_prefix, 'command' => $command, 'class' => $command_php_class))));
|
||||
}
|
||||
|
||||
$extra_info = isset($this->extra_info[$key_name_indicator]) ? $this->extra_info[$key_name_indicator] : null;
|
||||
|
||||
// Make it so that current_user_can() checks can apply + work
|
||||
if (!empty($extra_info['user_id'])) wp_set_current_user($extra_info['user_id']);
|
||||
|
||||
$this->current_udrpc = $ud_rpc;
|
||||
|
||||
do_action('updraftcentral_listener_pre_udrpc_action', $command, $command_class, $data, $extra_info);
|
||||
|
||||
// Allow the command class to perform any boiler-plate actions.
|
||||
if (is_callable(array($command_class, '_pre_action'))) call_user_func(array($command_class, '_pre_action'), $command, $data, $extra_info);
|
||||
|
||||
// Despatch
|
||||
$msg = apply_filters('updraftcentral_listener_udrpc_action', call_user_func(array($command_class, $command), $data, $extra_info), $command_class, $class_prefix, $command, $data, $extra_info);
|
||||
|
||||
if (is_callable(array($command_class, '_post_action'))) call_user_func(array($command_class, '_post_action'), $command, $data, $extra_info);
|
||||
|
||||
do_action('updraftcentral_listener_post_udrpc_action', $command, $command_class, $data, $extra_info);
|
||||
|
||||
if (isset($msg['data']) && is_array($msg['data'])) {
|
||||
$msg['data']['extra'] = $extra;
|
||||
}
|
||||
|
||||
return $this->return_rpc_message($msg);
|
||||
} catch (Exception $e) {
|
||||
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during UpdraftCentral command execution. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
|
||||
return $this->return_rpc_message(array('response' => 'rpcerror', 'data' => array('code' => 'rpc_fatal_error', 'data' => array('command' => $command, 'message' => $log_message))));
|
||||
// @codingStandardsIgnoreLine
|
||||
} catch (Error $e) {
|
||||
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during UpdraftCentral command execution. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
|
||||
return $this->return_rpc_message(array('response' => 'rpcerror', 'data' => array('code' => 'rpc_fatal_error', 'data' => array('command' => $command, 'message' => $log_message))));
|
||||
}
|
||||
}
|
||||
|
||||
public function get_current_udrpc() {
|
||||
return $this->current_udrpc;
|
||||
}
|
||||
|
||||
private function initialise_listener_error_handling() {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$this->host->error_reporting_stop_when_logged = true;
|
||||
$error_levels = version_compare(PHP_VERSION, '8.4.0', '>=') ? E_ALL : E_ALL & ~E_STRICT;
|
||||
set_error_handler(array($this->host, 'php_error'), $error_levels);
|
||||
$this->php_events = array();
|
||||
@ob_start();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Might be a bigger picture that I am missing but do we need to silence errors here?
|
||||
add_filter($updraftcentral_host_plugin->get_logline_filter(), array($this, 'updraftcentral_logline'), 10, 4);
|
||||
if (!$updraftcentral_host_plugin->get_debug_mode()) return;
|
||||
}
|
||||
|
||||
public function updraftcentral_logline($line, $nonce, $level, $uniq_id) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Unused parameter is present because the method is used as a WP filter.
|
||||
if ('notice' === $level && 'php_event' === $uniq_id) {
|
||||
$this->php_events[] = $line;
|
||||
}
|
||||
return $line;
|
||||
}
|
||||
|
||||
public function return_rpc_message($msg) {
|
||||
if (is_array($msg) && isset($msg['response']) && 'error' == $msg['response']) {
|
||||
$this->host->log('Unexpected response code in remote communications: '.serialize($msg));
|
||||
}
|
||||
|
||||
$caught_output = @ob_get_contents();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Might be a bigger picture that I am missing but do we need to silence errors here?
|
||||
@ob_end_clean();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Might be a bigger picture that I am missing but do we need to silence errors here?
|
||||
// If turning output-catching off, turn this on instead:
|
||||
// $caught_output = ''; @ob_end_flush();
|
||||
|
||||
// If there's higher-level output buffering going on, then get rid of that
|
||||
if (ob_get_level()) ob_end_clean();
|
||||
|
||||
if ($caught_output) {
|
||||
if (!isset($msg['data'])) $msg['data'] = null;
|
||||
$msg['data'] = array('caught_output' => $caught_output, 'previous_data' => $msg['data']);
|
||||
$already_rearranged_data = true;
|
||||
}
|
||||
|
||||
if (!empty($this->php_events)) {
|
||||
if (!isset($msg['data'])) $msg['data'] = null;
|
||||
if (!empty($already_rearranged_data)) {
|
||||
$msg['data']['php_events'] = array();
|
||||
} else {
|
||||
$msg['data'] = array('php_events' => array(), 'previous_data' => $msg['data']);
|
||||
}
|
||||
foreach ($this->php_events as $logline) {
|
||||
$msg['data']['php_events'][] = $logline;
|
||||
}
|
||||
}
|
||||
restore_error_handler();
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Analytics Commands
|
||||
*
|
||||
* @method array ga_checker()
|
||||
* @method array get_access_token()
|
||||
* @method array set_authorization_code()
|
||||
*/
|
||||
class UpdraftCentral_Analytics_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $scope = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/analytics.readonly';
|
||||
|
||||
private $endpoint = 'https://accounts.google.com/o/oauth2/auth';
|
||||
|
||||
private $token_info_endpoint = 'https://www.googleapis.com/oauth2/v1/tokeninfo';
|
||||
|
||||
private $access_key = 'updraftcentral_auth_server_access';
|
||||
|
||||
private $auth_endpoint;
|
||||
|
||||
private $client_id;
|
||||
|
||||
private $view_key = 'updraftcentral_analytics_views';
|
||||
|
||||
private $tracking_id_key = 'updraftcentral_analytics_tracking_id';
|
||||
|
||||
private $expiration;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->auth_endpoint = defined('UPDRAFTPLUS_GOOGLE_ANALYTICS_CALLBACK_URL') ? UPDRAFTPLUS_GOOGLE_ANALYTICS_CALLBACK_URL : 'https://auth.updraftplus.com/auth/googleanalytics';
|
||||
$this->client_id = defined('UPDRAFTPLUS_GOOGLE_ANALYTICS_CLIENT_ID') ? UPDRAFTPLUS_GOOGLE_ANALYTICS_CLIENT_ID : '306245874349-6s896c3tjpra26ns3dpplhqcl6rv6qlb.apps.googleusercontent.com';
|
||||
|
||||
// Set transient expiration - default for 24 hours
|
||||
$this->expiration = 86400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether Google Analytics (GA) is installed or setup
|
||||
*
|
||||
* N.B. This check assumes GA is installed either using "wp_head" or "wp_footer" (e.g. attached
|
||||
* to the <head/> or somewhere before </body>). It does not recursively check all the pages
|
||||
* of the website to find if GA is installed on each or one of those pages, but only on the main/root page.
|
||||
*
|
||||
* @return array $result An array containing "ga_installed" property which returns "true" if GA (Google Analytics) is installed, "false" otherwise.
|
||||
*/
|
||||
public function ga_checker() {
|
||||
|
||||
try {
|
||||
|
||||
// Retrieves the tracking code/id if available
|
||||
$tracking_id = $this->get_tracking_id();
|
||||
$installed = true;
|
||||
|
||||
// If tracking code/id is currently not available then we
|
||||
// parse the needed information from the buffered content through
|
||||
// the "wp_head" and "wp_footer" hooks.
|
||||
if (false === $tracking_id) {
|
||||
$info = $this->extract_tracking_id();
|
||||
|
||||
$installed = $info['installed'];
|
||||
$tracking_id = $info['tracking_id'];
|
||||
}
|
||||
|
||||
// Get access token to be use to generate the report.
|
||||
$access_token = $this->_get_token();
|
||||
|
||||
if (empty($access_token)) {
|
||||
// If we don't get a valid access token then that would mean
|
||||
// the access has been revoked by the user or UpdraftCentral was not authorized yet
|
||||
// to access the user's analytics data, thus, we're clearing
|
||||
// any previously stored user access so we're doing some housekeeping here.
|
||||
$this->clear_user_access();
|
||||
}
|
||||
|
||||
// Wrap and combined information for the requesting
|
||||
// client's consumption
|
||||
$result = array(
|
||||
'ga_installed' => $installed,
|
||||
'tracking_id' => $tracking_id,
|
||||
'client_id' => $this->client_id,
|
||||
'redirect_uri' => $this->auth_endpoint,
|
||||
'scope' => $this->scope,
|
||||
'access_token' => $access_token,
|
||||
'endpoint' => $this->endpoint
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts Google Tracking ID from contents rendered through the "wp_head" and "wp_footer" action hooks
|
||||
*
|
||||
* @internal
|
||||
* @return array $result An array containing the result of the extraction.
|
||||
*/
|
||||
private function extract_tracking_id() {
|
||||
|
||||
// Define result array
|
||||
$result = array();
|
||||
|
||||
// Retrieve header content
|
||||
ob_start();
|
||||
do_action('wp_head');
|
||||
$header_content = ob_get_clean();
|
||||
|
||||
// Extract analytics information if available.
|
||||
$output = $this->parse_content($header_content);
|
||||
$result['installed'] = $output['installed'];
|
||||
$result['tracking_id'] = $output['tracking_id'];
|
||||
|
||||
// If it was not found, then now try the footer
|
||||
if (empty($result['tracking_id'])) {
|
||||
// Retrieve footer content
|
||||
ob_start();
|
||||
do_action('wp_footer');
|
||||
$footer_content = ob_get_clean();
|
||||
$output = $this->parse_content($footer_content);
|
||||
$result['installed'] = $output['installed'];
|
||||
$result['tracking_id'] = $output['tracking_id'];
|
||||
}
|
||||
|
||||
if (!empty($result['tracking_id'])) {
|
||||
set_transient($this->tracking_id_key, $result['tracking_id'], $this->expiration);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets access token
|
||||
*
|
||||
* Validates whether the system currently have a valid token to use when connecting to Google Analytics API.
|
||||
* If not, then it will send a token request based on the authorization code we stored during the
|
||||
* authorization phase. Otherwise, it will return an empty token.
|
||||
*
|
||||
* @return array $result An array containing the Google Analytics API access token.
|
||||
*/
|
||||
public function get_access_token() {
|
||||
|
||||
try {
|
||||
|
||||
// Loads or request a valid token to use
|
||||
$access_token = $this->_get_token();
|
||||
|
||||
if (!empty($access_token)) {
|
||||
$result = array('access_token' => $access_token);
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'ga_token_retrieval_failed', 'values' => array());
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any previously stored user access
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear_user_access() {
|
||||
return delete_option($this->access_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves user is and access token received from the auth server
|
||||
*
|
||||
* @param array $query Parameter array containing the user id and access token from the auth server.
|
||||
* @return array $result An array containing a "success" or "failure" message as a result of the current process.
|
||||
*/
|
||||
public function save_user_access($query) {
|
||||
|
||||
try {
|
||||
|
||||
$token = get_option($this->access_key, false);
|
||||
$result = array();
|
||||
|
||||
if (false === $token) {
|
||||
$token = array(
|
||||
'user_id' => base64_decode(urldecode($query['user_id'])),
|
||||
'access_token' => base64_decode(urldecode($query['access_token']))
|
||||
);
|
||||
|
||||
if (false !== update_option($this->access_key, $token)) {
|
||||
$result = array('error' => false, 'message' => 'ga_access_saved', 'values' => array());
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'ga_access_saving_failed', 'values' => array($query['access_token']));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the tracking code/id manually (user input)
|
||||
*
|
||||
* @param array $query Parameter array containing the tracking code/id to save.
|
||||
* @return array $result An array containing the result of the process.
|
||||
*/
|
||||
public function save_tracking_id($query) {
|
||||
try {
|
||||
$tracking_id = $query['tracking_id'];
|
||||
$saved = false;
|
||||
|
||||
if (!empty($tracking_id)) {
|
||||
$saved = set_transient($this->tracking_id_key, $tracking_id, $this->expiration);
|
||||
}
|
||||
|
||||
$result = array('saved' => $saved);
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves any available access token either previously saved info or
|
||||
* from a new request from the Google Server.
|
||||
*
|
||||
* @internal
|
||||
* @return string $authorization_code
|
||||
*/
|
||||
private function _get_token() {
|
||||
|
||||
// Retrieves the tracking code/id if available
|
||||
$tracking_id = $this->get_tracking_id();
|
||||
$access_token = '';
|
||||
|
||||
$token = get_option($this->access_key, false);
|
||||
if (false !== $token) {
|
||||
$access_token = isset($token['access_token']) ? $token['access_token'] : '';
|
||||
$user_id = isset($token['user_id']) ? $token['user_id'] : '';
|
||||
|
||||
if ((!empty($access_token) && !$this->_token_valid($access_token)) || (!empty($user_id) && empty($access_token) && !empty($tracking_id))) {
|
||||
if (!empty($user_id)) {
|
||||
$args = array(
|
||||
'headers' => apply_filters('updraftplus_auth_headers', array())
|
||||
);
|
||||
|
||||
$response = wp_remote_get($this->auth_endpoint.'?user_id='.$user_id.'&code=ud_googleanalytics_code', $args);
|
||||
if (is_wp_error($response)) {
|
||||
throw new Exception($response->get_error_message()); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- The escaping should be happening when the exception is printed
|
||||
} else {
|
||||
if (is_array($response)) {
|
||||
|
||||
$body = json_decode($response['body'], true);
|
||||
$token_response = array();
|
||||
|
||||
if (is_array($body) && !isset($body['error'])) {
|
||||
$token_response = json_decode(base64_decode($body[0]), true);
|
||||
}
|
||||
|
||||
if (is_array($token_response) && isset($token_response['access_token'])) {
|
||||
$access_token = $token_response['access_token'];
|
||||
} else {
|
||||
// If we don't get any valid response then that would mean that the
|
||||
// permission was already revoked. Thus, we need to re-authorize the
|
||||
// user before using the analytics feature once again.
|
||||
$access_token = '';
|
||||
}
|
||||
|
||||
$token['access_token'] = $access_token;
|
||||
update_option($this->access_key, $token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether the access token is still valid for use
|
||||
*
|
||||
* @internal
|
||||
* @param string $token The access token to be check and validated
|
||||
* @return bool
|
||||
* @throws Exception If an error has occurred while connecting to the Google Server.
|
||||
*/
|
||||
private function _token_valid($token) {
|
||||
|
||||
$response = wp_remote_get($this->token_info_endpoint.'?access_token='.$token);
|
||||
if (is_wp_error($response)) {
|
||||
throw new Exception($response->get_error_message()); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- The escaping should be happening when the exception is printed
|
||||
} else {
|
||||
if (is_array($response)) {
|
||||
$response = json_decode($response['body'], true);
|
||||
if (!empty($response)) {
|
||||
if (!isset($response['error']) && !isset($response['error_description'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and extracts the google analytics information (NEEDED)
|
||||
*
|
||||
* @internal
|
||||
* @param string $content The content to parse
|
||||
* @return array An array containing the status of the process along with the tracking code/id
|
||||
*/
|
||||
private function parse_content($content) {
|
||||
|
||||
$installed = false;
|
||||
$gtm_installed = false;
|
||||
$tracking_id = '';
|
||||
$script_file_found = false;
|
||||
$tracking_id_found = false;
|
||||
|
||||
// Pull google analytics script file(s)
|
||||
preg_match_all('/<script\b[^>]*>([\s\S]*?)<\/script>/i', $content, $scripts);
|
||||
for ($i=0; $i < count($scripts[0]); $i++) {
|
||||
// Check for Google Analytics file
|
||||
if (stristr($scripts[0][$i], 'ga.js') || stristr($scripts[0][$i], 'analytics.js')) {
|
||||
$script_file_found = true;
|
||||
}
|
||||
|
||||
// Check for Google Tag Manager file
|
||||
// N.B. We are not checking for GTM but this check will be useful when
|
||||
// showing the notice to the user if we haven't found Google Analytics
|
||||
// directly being installed on the page.
|
||||
if (stristr($scripts[0][$i], 'gtm.js')) {
|
||||
$gtm_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Pull tracking code
|
||||
preg_match_all('/UA-[0-9]{5,}-[0-9]{1,}/i', $content, $codes);
|
||||
if (count($codes) > 0) {
|
||||
if (!empty($codes[0])) {
|
||||
$tracking_id_found = true;
|
||||
$tracking_id = $codes[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
// If we found both the script and the tracking code then it is safe
|
||||
// to say that Google Analytics (GA) is installed. Thus, we're returning
|
||||
// "true" as a response.
|
||||
if ($script_file_found && $tracking_id_found) {
|
||||
$installed = true;
|
||||
}
|
||||
|
||||
// Return result of process.
|
||||
return array(
|
||||
'installed' => $installed,
|
||||
'gtm_installed' => $gtm_installed,
|
||||
'tracking_id' => $tracking_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the "analytics_tracking_id" transient
|
||||
*
|
||||
* @internal
|
||||
* @return mixed Returns the value of the saved transient. Returns "false" if the transient does not exist.
|
||||
*/
|
||||
private function get_tracking_id() {
|
||||
return get_transient($this->tracking_id_key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current tracking id
|
||||
*
|
||||
* @return array $result An array containing the Google Tracking ID.
|
||||
*/
|
||||
public function get_current_tracking_id() {
|
||||
try {
|
||||
|
||||
// Get current site transient stored for this key
|
||||
$tracking_id = get_transient($this->tracking_id_key);
|
||||
|
||||
// Checks whether we have a valid token
|
||||
$access_token = $this->_get_token();
|
||||
if (empty($access_token)) {
|
||||
$tracking_id = '';
|
||||
}
|
||||
|
||||
if (false === $tracking_id) {
|
||||
$result = $this->extract_tracking_id();
|
||||
} else {
|
||||
$result = array(
|
||||
'installed' => true,
|
||||
'tracking_id' => $tracking_id
|
||||
);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears user access from database
|
||||
*
|
||||
* @return array $result An array containing the "Remove" confirmation whether the action succeeded or not.
|
||||
*/
|
||||
public function remove_user_access() {
|
||||
try {
|
||||
|
||||
// Clear user access
|
||||
$is_cleared = $this->clear_user_access();
|
||||
|
||||
if (false !== $is_cleared) {
|
||||
$result = array('removed' => true);
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'user_access_remove_failed', 'values' => array());
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Backups Commands
|
||||
*/
|
||||
class UpdraftCentral_Backups_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdraftPlus plugin status, UpdraftVault storage usage status, Next backup
|
||||
* schedule, etc. Used primarily by UpdraftCentral background process.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_status() {
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
$response = array(
|
||||
'status' => 'error',
|
||||
'error_code' => 'insufficient_permission',
|
||||
);
|
||||
} else {
|
||||
|
||||
if (!function_exists('get_mu_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$mu_plugins = get_mu_plugins();
|
||||
|
||||
$is_premium = false;
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/udaddons')) $is_premium = true;
|
||||
|
||||
// Set default response
|
||||
$response = array(
|
||||
'updraftplus_version' => '',
|
||||
'is_premium' => $is_premium,
|
||||
'installed' => false,
|
||||
'active' => false,
|
||||
'backup_count' => 0,
|
||||
'has_mu_plugins' => !empty($mu_plugins) ? true : false,
|
||||
'last_backup' => array(
|
||||
'backup_nonce' => '',
|
||||
'has_errors' => false,
|
||||
'has_warnings' => false,
|
||||
'has_succeeded' => false,
|
||||
),
|
||||
'updraftvault' => array(
|
||||
'site_connected' => false,
|
||||
'storage' => array('quota_used' => '0 MB', 'quota' => '0 MB', 'percentage_usage' => '0.0%'),
|
||||
),
|
||||
'meta' => array(),
|
||||
);
|
||||
|
||||
if (class_exists('UpdraftPlus')) {
|
||||
global $updraftplus;
|
||||
|
||||
$response['updraftplus_version'] = $updraftplus->version;
|
||||
$response['updraftvault'] = $this->get_updraftvault_status();
|
||||
$response['installed'] = true;
|
||||
$response['active'] = true;
|
||||
$response['meta'] = $this->get_filesystem_credentials_info();
|
||||
|
||||
$schedule = $this->get_next_backup_schedule();
|
||||
if ($schedule) {
|
||||
$response['next_backup_schedule'] = $schedule;
|
||||
}
|
||||
|
||||
$backup_history = UpdraftPlus_Backup_History::add_jobdata(UpdraftPlus_Backup_History::get_history());
|
||||
|
||||
$response['backup_count'] = count($backup_history);
|
||||
|
||||
$updraft_last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
|
||||
if ($updraft_last_backup) {
|
||||
$response['last_backup']['backup_nonce'] = $updraft_last_backup['backup_nonce'];
|
||||
if (isset($updraft_last_backup['backup_time'])) {
|
||||
$response['last_backup']['backup_date'] = gmdate('n/j/Y', $updraft_last_backup['backup_time']);
|
||||
}
|
||||
|
||||
$errors = 0;
|
||||
$warnings = 0;
|
||||
|
||||
if (is_array($updraft_last_backup['errors'])) {
|
||||
foreach ($updraft_last_backup['errors'] as $err) {
|
||||
$level = (is_array($err)) ? $err['level'] : 'error';
|
||||
if ('warning' == $level) {
|
||||
$warnings++;
|
||||
} elseif ('error' == $level) {
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors > 0) $response['last_backup']['has_errors'] = true;
|
||||
if ($warnings > 0) $response['last_backup']['has_warnings'] = true;
|
||||
if (isset($updraft_last_backup['success']) && $updraft_last_backup['success']) $response['last_backup']['has_succeeded'] = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!function_exists('get_plugins')) require_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$plugins = get_plugins();
|
||||
$key = 'updraftplus/updraftplus.php';
|
||||
|
||||
if (array_key_exists($key, $plugins)) {
|
||||
$response['installed'] = true;
|
||||
if (is_plugin_active($key)) $response['active'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next backup schedule for Files and Database backups
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_next_backup_schedule() {
|
||||
|
||||
// Get the next (nearest) scheduled backups
|
||||
$files = wp_next_scheduled('updraft_backup');
|
||||
$db = wp_next_scheduled('updraft_backup_database');
|
||||
|
||||
if ($files && $db) {
|
||||
$timestamp = min($files, $db); // Get the nearest schedule among the two schedules
|
||||
} elseif ($files && !$db) {
|
||||
$timestamp = $files;
|
||||
} elseif (!$files && $db) {
|
||||
$timestamp = $db;
|
||||
} else {
|
||||
$timestamp = null;
|
||||
}
|
||||
|
||||
if (!empty($timestamp)) {
|
||||
return gmdate('g:i A - D', $timestamp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdrafVault storage usage status
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_updraftvault_status() {
|
||||
|
||||
if (!class_exists('UpdraftCentral_UpdraftVault_Commands')) {
|
||||
include_once(UPDRAFTPLUS_DIR.'/includes/updraftvault.php');
|
||||
}
|
||||
|
||||
$updraftvault = new UpdraftCentral_UpdraftVault_Commands($this->rc);
|
||||
$creds = $updraftvault->get_credentials();
|
||||
|
||||
$site_connected = false;
|
||||
$storage = array('quota_used' => '0 MB', 'quota' => '0 MB', 'percentage_usage' => '0.0%');
|
||||
$remote_service = false;
|
||||
|
||||
if (isset($creds['data'])) {
|
||||
if (!isset($creds['data']['error']) && isset($creds['data']['accesskey'])) {
|
||||
$site_connected = true;
|
||||
|
||||
$storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array('updraftvault'));
|
||||
|
||||
if (isset($storage_objects_and_ids['updraftvault']['instance_settings'])) {
|
||||
$instance_settings = $storage_objects_and_ids['updraftvault']['instance_settings'];
|
||||
$instance_id = key($instance_settings);
|
||||
$opts = $instance_settings[$instance_id];
|
||||
|
||||
if (!class_exists('UpdraftPlus_BackupModule_updraftvault')) {
|
||||
include_once(UPDRAFTPLUS_DIR.'/methods/updraftvault.php');
|
||||
}
|
||||
|
||||
$vault = new UpdraftPlus_BackupModule_updraftvault();
|
||||
$vault->set_options($opts, false, $instance_id);
|
||||
|
||||
$quota_root = $opts['quota_root'];
|
||||
$quota = $opts['quota'];
|
||||
|
||||
if (empty($quota_root)) {
|
||||
// This next line is wrong: it lists the files *in this site's sub-folder*, rather than the whole Vault
|
||||
$current_files = $vault->listfiles('');
|
||||
} else {
|
||||
$current_files = $vault->listfiles_with_path($quota_root, '', true);
|
||||
}
|
||||
|
||||
if (!is_wp_error($current_files) && is_array($current_files)) {
|
||||
$quota_used = 0;
|
||||
foreach ($current_files as $file) {
|
||||
$quota_used += $file['size'];
|
||||
}
|
||||
|
||||
$storage = array(
|
||||
'quota_used' => round($quota_used / 1048576, 1).' MB',
|
||||
'quota' => round($quota / 1048576, 1).' MB',
|
||||
'percentage_usage' => sprintf('%.1f', 100*$quota_used / $quota).'%',
|
||||
);
|
||||
|
||||
$remote_service = array(
|
||||
'name' => 'updraft_include_remote_service_updraftvault',
|
||||
'value' => $instance_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'site_connected' => $site_connected,
|
||||
'storage' => $storage,
|
||||
'remote_service' => $remote_service,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information whether filesystem credentials (e.g. FTP/SSH) are required
|
||||
* when updating plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_filesystem_credentials_info() {
|
||||
|
||||
if (!function_exists('get_filesystem_method')) {
|
||||
include_once(ABSPATH.'/wp-admin/includes/file.php');
|
||||
}
|
||||
|
||||
$filesystem_method = get_filesystem_method(array(), WP_PLUGIN_DIR);
|
||||
|
||||
ob_start();
|
||||
$filesystem_credentials_are_stored = request_filesystem_credentials(site_url());
|
||||
$filesystem_form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
|
||||
ob_end_clean();
|
||||
|
||||
$request_filesystem_credentials = ('direct' != $filesystem_method && !$filesystem_credentials_are_stored);
|
||||
|
||||
return array(
|
||||
'request_filesystem_credentials' => $request_filesystem_credentials,
|
||||
'filesystem_form' => base64_encode($filesystem_form),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the backup progress in terms of entities completed. Used primarily by UpdraftCentral
|
||||
* for polling backup progress in the background.
|
||||
*
|
||||
* @param array $params Submitted arguments for the current request
|
||||
* @return array
|
||||
*/
|
||||
public function get_backup_progress($params) {
|
||||
|
||||
$nonce = isset($params['nonce']) ? $params['nonce'] : false;
|
||||
$response = array('nonce' => $params['nonce']);
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
$response['status'] = 'error';
|
||||
$response['error_code'] = 'insufficient_permission';
|
||||
} else {
|
||||
global $updraftplus;
|
||||
|
||||
if ($nonce && $updraftplus && is_a($updraftplus, 'UpdraftPlus')) {
|
||||
|
||||
// Check the job is not still running.
|
||||
$jobdata = $updraftplus->jobdata_getarray($nonce);
|
||||
|
||||
$response['status'] = 'idle'; // It's very rare to receive this in the UI as status. If it happens then that would mean that no backup has been done for the given nonce even if we initially received it from the "backupnow" request. Possible cause would be, is that the server is too busy or something happened in between calls.
|
||||
|
||||
if (!empty($jobdata)) {
|
||||
$response['status'] = 'in-progress';
|
||||
|
||||
$file_entities = 0;
|
||||
$db_entities = 0;
|
||||
$processed = 0;
|
||||
|
||||
if (isset($jobdata['backup_database']) && 'no' != $jobdata['backup_database']) {
|
||||
$backup_database = $jobdata['backup_database'];
|
||||
$db_entities += count($backup_database);
|
||||
|
||||
foreach ($backup_database as $whichdb => $info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- In this check we only need the status contained in the $info for now.
|
||||
$status = $info; // For default: 'wp'
|
||||
if (is_array($info)) {
|
||||
$status = $info['status'];
|
||||
}
|
||||
|
||||
if ('finished' == $status) {
|
||||
$processed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($jobdata['backup_files']) && 'no' != $jobdata['backup_files']) {
|
||||
$file_entities = count($jobdata['job_file_entities']);
|
||||
|
||||
$backup_files = $jobdata['backup_files'];
|
||||
if ('finished' == $backup_files) {
|
||||
$processed += $file_entities;
|
||||
} elseif (isset($jobdata['filecreating_substatus'])) {
|
||||
$substatus = $jobdata['filecreating_substatus'];
|
||||
$processed += max(0, intval($substatus['i']) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
$response['progress'] = array(
|
||||
'file_entities' => $file_entities,
|
||||
'db_entities' => $db_entities,
|
||||
'total_entities' => $file_entities+$db_entities,
|
||||
'processed' => $processed,
|
||||
'percentage' => floor(($processed/($file_entities+$db_entities))*100),
|
||||
'nonce' => $nonce,
|
||||
);
|
||||
|
||||
UpdraftPlus_Options::update_updraft_option('updraft_last_backup_progress', $response['progress'], false);
|
||||
} else {
|
||||
$last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
|
||||
if ($nonce == $last_backup['backup_nonce']) {
|
||||
$response['status'] = 'finished';
|
||||
$response['progress'] = array('percentage' => 100);
|
||||
$response['progress']['errors'] = $last_backup['errors'];
|
||||
|
||||
$errors = 0;
|
||||
$warnings = 0;
|
||||
|
||||
if (!empty($last_backup['errors']) && is_array($last_backup['errors'])) {
|
||||
foreach ($last_backup['errors'] as $err) {
|
||||
$level = (is_array($err)) ? $err['level'] : 'error';
|
||||
if ('warning' == $level) {
|
||||
$warnings++;
|
||||
} elseif ('error' == $level) {
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response['progress']['has_errors'] = ($errors > 0) ? true : false;
|
||||
$response['progress']['has_warnings'] = ($warnings > 0) ? true : false;
|
||||
} else {
|
||||
// We might be too early to check the `updraft_last_backup` thus, we'll
|
||||
// give it a few rounds to check by setting the status to "in-progress"
|
||||
// and returning the last backup progress.
|
||||
$last_progress = UpdraftPlus_Options::get_updraft_option('updraft_last_backup_progress');
|
||||
if ($nonce == $last_progress['nonce']) {
|
||||
$response['status'] = 'in-progress';
|
||||
$response['progress'] = $last_progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,842 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
class UpdraftCentral_Comments_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
/**
|
||||
* The _search_comments function searches all available comments based
|
||||
* on the following query parameters (type, status, search)
|
||||
*
|
||||
* Search Parameters/Filters:
|
||||
* type - comment types can be 'comment', 'trackback' and 'pingback', defaults to 'comment'
|
||||
* status - comment status can be 'hold' or unapprove, 'approve', 'spam', 'trash'
|
||||
* search - user generated content or keyword
|
||||
*
|
||||
* @param array $query The query to search comments
|
||||
* @return array
|
||||
*/
|
||||
private function _search_comments($query) {
|
||||
|
||||
// Basic parameters to the query and should display
|
||||
// the results in descending order (latest comments) first
|
||||
// based on their generated IDs
|
||||
|
||||
$args = array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'DESC',
|
||||
'type' => $query['type'],
|
||||
'status' => $query['status'],
|
||||
'search' => esc_attr($query['search']),
|
||||
);
|
||||
|
||||
$query = new WP_Comment_Query;
|
||||
$found_comments = $query->query($args);
|
||||
|
||||
$comments = array();
|
||||
foreach ($found_comments as $comment) {
|
||||
|
||||
// We're returning a collection of comment in an array,
|
||||
// in sync with the originator of the request on the ui side
|
||||
// so, we're pulling it one by one into the array before
|
||||
// returning it.
|
||||
|
||||
if (!in_array($comment, $comments)) {
|
||||
array_push($comments, $comment);
|
||||
}
|
||||
}
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* The _calculate_pages function generates and builds the pagination links
|
||||
* based on the current search parameters/filters. Please see _search_comments
|
||||
* for the breakdown of these parameters.
|
||||
*
|
||||
* @param array $query Query to generate pagination links
|
||||
* @return array
|
||||
*/
|
||||
private function _calculate_pages($query) {
|
||||
$per_page_options = array(10, 20, 30, 40, 50);
|
||||
|
||||
if (!empty($query)) {
|
||||
if (!empty($query['search'])) {
|
||||
return array(
|
||||
'page_count' => 1,
|
||||
'page_no' => 1
|
||||
);
|
||||
}
|
||||
|
||||
$pages = array();
|
||||
$page_query = new WP_Comment_Query;
|
||||
|
||||
// Here, we're pulling the comments based on the
|
||||
// two parameters namely type and status.
|
||||
//
|
||||
// The number of results/comments found will then
|
||||
// be use to compute for the number of pages to be
|
||||
// displayed as navigation links when browsing all
|
||||
// comments from the frontend.
|
||||
|
||||
$comments = $page_query->query(array(
|
||||
'type' => $query['type'],
|
||||
'status' => $query['status']
|
||||
));
|
||||
|
||||
$total_comments = count($comments);
|
||||
$page_count = ceil($total_comments / $query['per_page']);
|
||||
|
||||
if ($page_count > 1) {
|
||||
for ($i = 0; $i < $page_count; $i++) {
|
||||
if ($i + 1 == $query['page_no']) {
|
||||
$paginator_item = array(
|
||||
'value' => $i+1,
|
||||
'setting' => 'disabled'
|
||||
);
|
||||
} else {
|
||||
$paginator_item = array(
|
||||
'value' => $i+1
|
||||
);
|
||||
}
|
||||
array_push($pages, $paginator_item);
|
||||
}
|
||||
|
||||
if ($query['page_no'] >= $page_count) {
|
||||
$page_next = array(
|
||||
'value' => $page_count,
|
||||
'setting' => 'disabled'
|
||||
);
|
||||
} else {
|
||||
$page_next = array(
|
||||
'value' => $query['page_no'] + 1
|
||||
);
|
||||
}
|
||||
|
||||
if (1 === $query['page_no']) {
|
||||
$page_prev = array(
|
||||
'value' => 1,
|
||||
'setting' => 'disabled'
|
||||
);
|
||||
} else {
|
||||
$page_prev = array(
|
||||
'value' => $query['page_no'] - 1
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'page_no' => $query['page_no'],
|
||||
'per_page' => $query['per_page'],
|
||||
'page_count' => $page_count,
|
||||
'pages' => $pages,
|
||||
'page_next' => $page_next,
|
||||
'page_prev' => $page_prev,
|
||||
'total_results' => $total_comments,
|
||||
'per_page_options' => $per_page_options
|
||||
);
|
||||
|
||||
} else {
|
||||
return array(
|
||||
'page_no' => $query['page_no'],
|
||||
'per_page' => $query['per_page'],
|
||||
'page_count' => $page_count,
|
||||
'total_results' => $total_comments,
|
||||
'per_page_options' => $per_page_options
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return array(
|
||||
'per_page_options' => $per_page_options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_blog_sites function pulls blog sites available for the current WP instance.
|
||||
* If Multisite is enabled on the server, then sites under the network will be pulled, otherwise, it will return an empty array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_blog_sites() {
|
||||
|
||||
if (!is_multisite()) return array();
|
||||
|
||||
// Initialize array container
|
||||
$sites = $network_sites = array();
|
||||
|
||||
// Check to see if latest get_sites (available on WP version >= 4.6) function is
|
||||
// available to pull any available sites from the current WP instance. If not, then
|
||||
// we're going to use the fallback function wp_get_sites (for older version).
|
||||
|
||||
if (function_exists('get_sites') && class_exists('WP_Site_Query')) {
|
||||
$network_sites = get_sites();
|
||||
} else {
|
||||
if (function_exists('wp_get_sites')) {
|
||||
$network_sites = wp_get_sites();
|
||||
}
|
||||
}
|
||||
|
||||
// We only process if sites array is not empty, otherwise, bypass
|
||||
// the next block.
|
||||
|
||||
if (!empty($network_sites)) {
|
||||
foreach ($network_sites as $site) {
|
||||
|
||||
// Here we're checking if the site type is an array, because
|
||||
// we're pulling the blog_id property based on the type of
|
||||
// site returned.
|
||||
// get_sites returns an array of object, whereas the wp_get_sites
|
||||
// function returns an array of array.
|
||||
|
||||
$blog_id = (is_array($site)) ? $site['blog_id'] : $site->blog_id;
|
||||
|
||||
|
||||
// We're saving the blog_id and blog name as an associative item
|
||||
// into the sites array, that will be used as "Sites" option in
|
||||
// the frontend.
|
||||
|
||||
$sites[$blog_id] = get_blog_details($blog_id)->blogname;
|
||||
}
|
||||
}
|
||||
|
||||
return $sites;
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_wp_option function pulls current blog options
|
||||
* from the database using either following functions:
|
||||
* - get_blog_option (for multisite)
|
||||
* - get_option (for ordinary blog)
|
||||
*
|
||||
* @param array $blog_id This is the specific blog ID
|
||||
* @param array $setting specifies settings
|
||||
* @return array
|
||||
*/
|
||||
private function _get_wp_option($blog_id, $setting) {
|
||||
return is_multisite() ? get_blog_option($blog_id, $setting) : get_option($setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_comments function pull all the comments from the database
|
||||
* based on the current search parameters/filters. Please see _search_comments
|
||||
* for the breakdown of these parameters.
|
||||
*
|
||||
* @param array $query Specific query to pull comments
|
||||
* @return array
|
||||
*/
|
||||
public function get_comments($query) {
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($query['blog_id'])) $blog_id = $query['blog_id'];
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull comments from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!empty($query['search'])) {
|
||||
// If a search keyword is present, then we'll call the _search_comments
|
||||
// function to process the query.
|
||||
|
||||
$comments = $this->_search_comments($query);
|
||||
} else {
|
||||
// Set default parameter values if the designated
|
||||
// parameters are empty.
|
||||
|
||||
if (empty($query['per_page'])) {
|
||||
$query['per_page'] = 10;
|
||||
}
|
||||
if (empty($query['page_no'])) {
|
||||
$query['page_no'] = 1;
|
||||
}
|
||||
if (empty($query['type'])) {
|
||||
$query['type'] = '';
|
||||
}
|
||||
if (empty($query['status'])) {
|
||||
$query['status'] = '';
|
||||
}
|
||||
|
||||
// Since WP_Comment_Query parameters doesn't have a "page" attribute, we
|
||||
// need to compute for the offset to get the exact content based on the
|
||||
// current page and the number of items per page.
|
||||
|
||||
$offset = ((int) $query['page_no'] - 1) * (int) $query['per_page'];
|
||||
$args = array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'DESC',
|
||||
'number' => $query['per_page'],
|
||||
'offset' => $offset,
|
||||
'type' => $query['type'],
|
||||
'status' => $query['status']
|
||||
);
|
||||
|
||||
$comments_query = new WP_Comment_Query;
|
||||
$comments = $comments_query->query($args);
|
||||
}
|
||||
|
||||
// If no comments are found based on the current query then
|
||||
// we return with error.
|
||||
|
||||
if (empty($comments)) {
|
||||
$result = array('message' => 'comments_not_found');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Otherwise, we're going to process each comment
|
||||
// before we return it to the one issuing the request.
|
||||
//
|
||||
// Process in the sense that we add additional related info
|
||||
// such as the post tile where the comment belongs to, the
|
||||
// comment status, a formatted date field, and to which parent comment
|
||||
// does the comment was intended to be as a reply.
|
||||
|
||||
foreach ($comments as &$comment) {
|
||||
$comment = get_comment($comment->comment_ID, ARRAY_A);
|
||||
if ($comment) {
|
||||
$post = get_post($comment['comment_post_ID']);
|
||||
|
||||
if ($post) $comment['in_response_to'] = $post->post_title;
|
||||
if (!empty($comment['comment_parent'])) {
|
||||
$parent_comment = get_comment($comment['comment_parent'], ARRAY_A);
|
||||
if ($parent_comment) $comment['in_reply_to'] = $parent_comment['comment_author'];
|
||||
}
|
||||
|
||||
// We're formatting the comment_date to be exactly the same
|
||||
// with that of WP Comments table (e.g. 2016/12/21 at 10:30 PM)
|
||||
|
||||
$comment['comment_date'] = date('Y/m/d \a\t g:i a', strtotime($comment['comment_date']));
|
||||
|
||||
$status = wp_get_comment_status($comment['comment_ID']);
|
||||
if ($status) {
|
||||
$comment['comment_status'] = $status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We return the following to the one issuing
|
||||
// the request.
|
||||
|
||||
$result = array(
|
||||
'comments' => $comments,
|
||||
'paging' => $this->_calculate_pages($query)
|
||||
);
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_comment_filters function builds a array of options
|
||||
* to be use as filters for the search function on the frontend.
|
||||
*/
|
||||
public function get_comment_filters() {
|
||||
// Options for comment_types field
|
||||
$comment_types = apply_filters('admin_comment_types_dropdown', array(
|
||||
'comment' => __('Comments'),// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core.
|
||||
'pings' => __('Pings'),// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core.
|
||||
));
|
||||
|
||||
// Options for comment_status field
|
||||
$comment_statuses = array(
|
||||
'approve' => __('Approve'),// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core.
|
||||
'hold' => __('Hold or Unapprove', 'updraftplus'),
|
||||
'trash' => __('Trash', 'updraftplus'),
|
||||
'spam' => __('Spam', 'updraftplus'),
|
||||
);
|
||||
|
||||
// Pull sites options if available.
|
||||
$sites = $this->get_blog_sites();
|
||||
|
||||
$result = array(
|
||||
'sites' => $sites,
|
||||
'types' => $comment_types,
|
||||
'statuses' => $comment_statuses,
|
||||
'paging' => $this->_calculate_pages(null),
|
||||
);
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_settings function pulls the current discussion settings
|
||||
* option values.
|
||||
*
|
||||
* @param array $params Passing specific params for getting current discussion settings
|
||||
* @return array
|
||||
*/
|
||||
public function get_settings($params) {
|
||||
global $updraftcentral_main;
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to manage and edit
|
||||
// WP options then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'manage_options')) {
|
||||
$result = array('error' => true, 'message' => 'insufficient_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Pull sites options if available.
|
||||
$sites = $this->get_blog_sites();
|
||||
|
||||
// Wrap current discussion settings values into an array item
|
||||
// named settings.
|
||||
|
||||
$result = array(
|
||||
'settings' => array(
|
||||
'default_pingback_flag' => $this->_get_wp_option($blog_id, 'default_pingback_flag'),
|
||||
'default_ping_status' => $this->_get_wp_option($blog_id, 'default_ping_status'),
|
||||
'default_comment_status' => $this->_get_wp_option($blog_id, 'default_comment_status'),
|
||||
'require_name_email' => $this->_get_wp_option($blog_id, 'require_name_email'),
|
||||
'comment_registration' => $this->_get_wp_option($blog_id, 'comment_registration'),
|
||||
'close_comments_for_old_posts' => $this->_get_wp_option($blog_id, 'close_comments_for_old_posts'),
|
||||
'close_comments_days_old' => $this->_get_wp_option($blog_id, 'close_comments_days_old'),
|
||||
'thread_comments' => $this->_get_wp_option($blog_id, 'thread_comments'),
|
||||
'thread_comments_depth' => $this->_get_wp_option($blog_id, 'thread_comments_depth'),
|
||||
'page_comments' => $this->_get_wp_option($blog_id, 'page_comments'),
|
||||
'comments_per_page' => $this->_get_wp_option($blog_id, 'comments_per_page'),
|
||||
'default_comments_page' => $this->_get_wp_option($blog_id, 'default_comments_page'),
|
||||
'comment_order' => $this->_get_wp_option($blog_id, 'comment_order'),
|
||||
'comments_notify' => $this->_get_wp_option($blog_id, 'comments_notify'),
|
||||
'moderation_notify' => $this->_get_wp_option($blog_id, 'moderation_notify'),
|
||||
'comment_moderation' => $this->_get_wp_option($blog_id, 'comment_moderation'),
|
||||
'comment_max_links' => $this->_get_wp_option($blog_id, 'comment_max_links'),
|
||||
'moderation_keys' => $this->_get_wp_option($blog_id, 'moderation_keys'),
|
||||
),
|
||||
'sites' => $sites,
|
||||
);
|
||||
|
||||
$wp_version = $updraftcentral_main->get_wordpress_version();
|
||||
if (version_compare($wp_version, '5.5.0', '<')) {
|
||||
$result['settings']['comment_whitelist'] = $this->_get_wp_option($blog_id, 'comment_whitelist');
|
||||
$result['settings']['blacklist_keys'] = $this->_get_wp_option($blog_id, 'blacklist_keys');
|
||||
} else {
|
||||
$result['settings']['comment_previously_approved'] = $this->_get_wp_option($blog_id, 'comment_previously_approved');
|
||||
$result['settings']['disallowed_keys'] = $this->_get_wp_option($blog_id, 'disallowed_keys');
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The update_settings function updates the discussion settings
|
||||
* basing on the user generated content/option from the frontend
|
||||
* form.
|
||||
*
|
||||
* @param array $params Specific params to update settings based on discussion
|
||||
* @return array
|
||||
*/
|
||||
public function update_settings($params) {
|
||||
|
||||
// Extract settings values from passed parameters.
|
||||
$settings = $params['settings'];
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to manage and edit
|
||||
// WP options then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'manage_options')) {
|
||||
$result = array('error' => true, 'message' => 'insufficient_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're sanitizing the input fields before we save them to the database
|
||||
// for safety and security reason. The "explode" and "implode" functions are meant
|
||||
// to maintain the line breaks associated with a textarea input/value.
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
|
||||
// We're using update_blog_option and update_option altogether to update the current
|
||||
// discussion settings.
|
||||
|
||||
if (is_multisite()) {
|
||||
update_blog_option($blog_id, $key, implode("\n", array_map('sanitize_text_field', explode("\n", $value))));
|
||||
} else {
|
||||
update_option($key, implode("\n", array_map('sanitize_text_field', explode("\n", $value))));
|
||||
}
|
||||
}
|
||||
|
||||
// We're not checking for errors here, but instead we're directly returning a success (error = false)
|
||||
// status always, because WP's update_option will return fail if values were not changed, meaning
|
||||
// previous values were not changed by the user's current request, not an actual exception thrown.
|
||||
// Thus, giving a false positive message or report to the frontend.
|
||||
|
||||
$result = array('error' => false, 'message' => 'settings_updated', 'values' => array());
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_comment function pulls a single comment based
|
||||
* on a comment ID.
|
||||
*
|
||||
* @param array $params Specific params for getting a single comment
|
||||
* @return array
|
||||
*/
|
||||
public function get_comment($params) {
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'insufficient_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull comments from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
// Get comment by comment_ID parameter and return result as an array.
|
||||
$result = array(
|
||||
'comment' => get_comment($params['comment_id'], ARRAY_A)
|
||||
);
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The reply_comment function creates a new comment as a reply
|
||||
* to a certain/selected comment.
|
||||
*
|
||||
* @param array $params Specific params to create a new comment reply
|
||||
* @return array
|
||||
*/
|
||||
public function reply_comment($params) {
|
||||
|
||||
// Extract reply info from the passed parameters
|
||||
$reply = $params['comment'];
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'comment_reply_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
|
||||
// Get comment by comment_ID parameter.
|
||||
$comment = get_comment($reply['comment_id']);
|
||||
if ($comment) {
|
||||
|
||||
// Get the currently logged in user
|
||||
$user = wp_get_current_user();
|
||||
|
||||
// If the current comment was not approved yet then
|
||||
// we need to approve it before we create a reply to
|
||||
// to the comment, mimicking exactly the WP behaviour
|
||||
// in terms of creating a reply to a comment.
|
||||
|
||||
if (empty($comment->comment_approved)) {
|
||||
$update_data = array(
|
||||
'comment_ID' => $reply['comment_id'],
|
||||
'comment_approved' => 1
|
||||
);
|
||||
wp_update_comment($update_data);
|
||||
}
|
||||
|
||||
// Build new comment parameters based on current user info and
|
||||
// the target comment for the reply.
|
||||
$data = array(
|
||||
'comment_post_ID' => $comment->comment_post_ID,
|
||||
'comment_author' => $user->display_name,
|
||||
'comment_author_email' => $user->user_email,
|
||||
'comment_author_url' => $user->user_url,
|
||||
'comment_content' => $reply['message'],
|
||||
'comment_parent' => $reply['comment_id'],
|
||||
'user_id' => $user->ID,
|
||||
'comment_date' => current_time('mysql'),
|
||||
'comment_approved' => 1
|
||||
);
|
||||
|
||||
// Create new comment based on the parameters above, and return
|
||||
// the status accordingly.
|
||||
|
||||
if (wp_insert_comment($data)) {
|
||||
$result = array('error' => false, 'message' => 'comment_replied_with_comment_author', 'values' => array($comment->comment_author));
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_reply_failed_with_error', 'values' => array($comment->comment_ID));
|
||||
}
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_does_not_exists_error', 'values' => array($reply['comment_id']));
|
||||
}
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The edit_comment function saves new information for the
|
||||
* currently selected comment.
|
||||
*
|
||||
* @param array $params Specific params for editing a comment
|
||||
* @return array
|
||||
*/
|
||||
public function edit_comment($params) {
|
||||
|
||||
// Extract new comment info from the passed parameters
|
||||
$comment = $params['comment'];
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'comment_edit_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
|
||||
// Get current comment details
|
||||
$original_comment = get_comment($comment['comment_id']);
|
||||
if ($original_comment) {
|
||||
$data = array();
|
||||
|
||||
// Replace "comment_id" with "comment_ID" since WP does not recognize
|
||||
// the small case "id".
|
||||
$comment['comment_ID'] = $original_comment->comment_ID;
|
||||
unset($comment['comment_id']);
|
||||
|
||||
// Here, we're sanitizing the input fields before we save them to the database
|
||||
// for safety and security reason. The "explode" and "implode" functions are meant
|
||||
// to maintain the line breaks associated with a textarea input/value.
|
||||
|
||||
foreach ($comment as $key => $value) {
|
||||
$data[$key] = implode("\n", array_map('sanitize_text_field', explode("\n", $value)));
|
||||
}
|
||||
|
||||
// Update existing comment based on the passed parameter fields and
|
||||
// return the status accordingly.
|
||||
|
||||
if (wp_update_comment($data)) {
|
||||
$result = array('error' => false, 'message' => 'comment_edited_with_comment_author', 'values' => array($original_comment->comment_author));
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_edit_failed_with_error', 'values' => array($original_comment->comment_ID));
|
||||
}
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_does_not_exists_error', 'values' => array($comment['comment_id']));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The update_comment_status function is a generic handler for the following
|
||||
* comment actions:
|
||||
*
|
||||
* - approve comment
|
||||
* - unapprove comment
|
||||
* - set comment as spam
|
||||
* - move comment to trash
|
||||
* - delete comment permanently
|
||||
* - unset comment as spam
|
||||
* - restore comment
|
||||
*
|
||||
* @param array $params Specific params to update comment status
|
||||
* @return array
|
||||
*/
|
||||
public function update_comment_status($params) {
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'comment_change_status_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
|
||||
// We make sure that we still have a valid comment from the server
|
||||
// before we apply the currently selected action.
|
||||
|
||||
$comment = get_comment($params['comment_id']);
|
||||
if ($comment) {
|
||||
$post = get_post($comment->comment_post_ID);
|
||||
|
||||
if ($post) $comment->in_response_to = $post->post_title;
|
||||
if (!empty($comment->comment_parent)) {
|
||||
$parent_comment = get_comment($comment->comment_parent);
|
||||
if ($parent_comment) $comment->in_reply_to = $parent_comment->comment_author;
|
||||
}
|
||||
|
||||
// We're formatting the comment_date to be exactly the same
|
||||
// with that of WP Comments table (e.g. 2016/12/21 at 10:30 PM)
|
||||
|
||||
$comment->comment_date = date('Y/m/d \a\t g:i a', strtotime($comment->comment_date));
|
||||
|
||||
$status = wp_get_comment_status($comment->comment_ID);
|
||||
if ($status) {
|
||||
$comment->comment_status = $status;
|
||||
}
|
||||
|
||||
$succeeded = false;
|
||||
$message = '';
|
||||
|
||||
// Here, we're using WP's wp_set_comment_status function to change the state
|
||||
// of the selected comment based on the current action, except for the "delete" action
|
||||
// where we use the wp_delete_comment to delete the comment permanently by passing
|
||||
// "true" to the second argument.
|
||||
|
||||
switch ($params['action']) {
|
||||
case 'approve':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'approve');
|
||||
$message = 'comment_approve_with_comment_author';
|
||||
break;
|
||||
case 'unapprove':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'hold');
|
||||
$message = 'comment_unapprove_with_comment_author';
|
||||
break;
|
||||
case 'spam':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'spam');
|
||||
$message = 'comment_spam_with_comment_author';
|
||||
break;
|
||||
case 'trash':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'trash');
|
||||
$message = 'comment_trash_with_comment_author';
|
||||
break;
|
||||
case 'delete':
|
||||
$succeeded = wp_delete_comment($params['comment_id'], true);
|
||||
$message = 'comment_delete_with_comment_author';
|
||||
break;
|
||||
case 'notspam':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'hold');
|
||||
$message = 'comment_not_spam_with_comment_author';
|
||||
break;
|
||||
case 'restore':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'hold');
|
||||
$message = 'comment_restore_with_comment_author';
|
||||
break;
|
||||
}
|
||||
|
||||
// If the current action succeeded, then we return a success message, otherwise,
|
||||
// we return an error message to the user issuing the request.
|
||||
|
||||
if ($succeeded) {
|
||||
$result = array('error' => false, 'message' => $message, 'values' => array($comment->comment_author), 'status' => $comment->comment_status, 'approved' => $comment->comment_approved);
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_change_status_failed_with_error', 'values' => array($comment->comment_ID));
|
||||
}
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_does_not_exists_error', 'values' => array($params['comment_id']));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,508 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* - A container for RPC commands (core UpdraftCentral commands). Commands map exactly onto method names (and hence this class should not implement anything else, beyond the constructor, and private methods)
|
||||
* - Return format is array('response' => (string - a code), 'data' => (mixed));
|
||||
*
|
||||
* RPC commands are not allowed to begin with an underscore. So, any private methods can be prefixed with an underscore.
|
||||
*/
|
||||
class UpdraftCentral_Core_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
/**
|
||||
* Retrieve site icon (favicon)
|
||||
*
|
||||
* @return array An array containing the site icon (favicon) byte string if available
|
||||
*/
|
||||
public function get_site_icon() {
|
||||
|
||||
if (!function_exists('get_site_icon_url')) {
|
||||
include_once(ABSPATH.'wp-includes/general-template.php');
|
||||
}
|
||||
|
||||
$site_icon_url = get_site_icon_url();
|
||||
|
||||
// If none is set in WordPress, let's try to search for the default favicon
|
||||
// within the site's directory
|
||||
if (empty($site_icon_url)) {
|
||||
|
||||
if (!function_exists('get_site_url')) {
|
||||
include_once(ABSPATH.'wp-includes/link-template.php');
|
||||
}
|
||||
|
||||
// Common favicon locations to check
|
||||
$potential_locations = array(
|
||||
'/favicon.ico',
|
||||
'/favicon.png',
|
||||
'/favicon.svg',
|
||||
'/assets/favicon.ico',
|
||||
'/assets/images/favicon.ico',
|
||||
'/apple-touch-icon.png',
|
||||
'/apple-touch-icon-precomposed.png',
|
||||
);
|
||||
|
||||
foreach ($potential_locations as $location) {
|
||||
$path = rtrim(ABSPATH, '/\\').$location;
|
||||
if (file_exists($path)) {
|
||||
$site_icon_url = get_site_url().$location;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are returning the site icon as byte string instead of URL in order to avoid
|
||||
// any hotlink protection that might prevent us to show the icon in UpdraftCentral
|
||||
// dashboard successfully.
|
||||
$site_icon = '';
|
||||
if (!empty($site_icon_url)) {
|
||||
$content = file_get_contents($site_icon_url);
|
||||
|
||||
$mime_type = '';
|
||||
foreach ($http_response_header as $value) {
|
||||
if (false !== stripos($value, 'content-type:')) {
|
||||
list(, $mime_type) = explode(':', preg_replace('/\s+/', '', $value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($content && !empty($mime_type)) {
|
||||
$site_icon = 'data: '.$mime_type.';base64,'.base64_encode($content);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response(array('site_icon' => $site_icon));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a list of submitted commands (multiplexer)
|
||||
*
|
||||
* @param Array $query An array containing the commands to execute and a flag to indicate how to handle command execution failure.
|
||||
* @return Array An array containing the results of the process.
|
||||
*/
|
||||
public function execute_commands($query) {
|
||||
|
||||
try {
|
||||
|
||||
$commands = $query['commands'];
|
||||
$command_results = array();
|
||||
$error_count = 0;
|
||||
|
||||
/**
|
||||
* Should be one of the following options:
|
||||
* 1 = Abort on first failure
|
||||
* 2 = Abort if any command fails
|
||||
* 3 = Abort if all command fails (default)
|
||||
*/
|
||||
$error_flag = isset($query['error_flag']) ? (int) $query['error_flag'] : 3;
|
||||
|
||||
|
||||
foreach ($commands as $command => $params) {
|
||||
$command_info = apply_filters('updraftcentral_get_command_info', false, $command);
|
||||
if (!$command_info) {
|
||||
list($_prefix, $_command) = explode('.', $command);
|
||||
$command_results[$_prefix][$_command] = array('response' => 'rpcerror', 'data' => array('code' => 'unknown_rpc_command', 'data' => $command));
|
||||
|
||||
$error_count++;
|
||||
if (1 === $error_flag) break;
|
||||
} else {
|
||||
|
||||
$action = $command_info['command'];
|
||||
$command_php_class = $command_info['command_php_class'];
|
||||
|
||||
// Instantiate the command class and execute the needed action
|
||||
if (class_exists($command_php_class)) {
|
||||
$instance = new $command_php_class($this->rc);
|
||||
|
||||
if (method_exists($instance, $action)) {
|
||||
$params = empty($params) ? array() : $params;
|
||||
$call_result = call_user_func(array($instance, $action), $params);
|
||||
|
||||
$command_results[$command] = $call_result;
|
||||
if ('rpcerror' === $call_result['response'] || (isset($call_result['data']['error']) && $call_result['data']['error'])) {
|
||||
$error_count++;
|
||||
if (1 === $error_flag) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 !== $error_count) {
|
||||
// N.B. These error messages should be defined in UpdraftCentral's translation file (dashboard-translations.php)
|
||||
// before actually using this multiplexer function.
|
||||
$message = 'general_command_execution_error';
|
||||
|
||||
switch ($error_flag) {
|
||||
case 1:
|
||||
$message = 'command_execution_aborted';
|
||||
break;
|
||||
case 2:
|
||||
$message = 'failed_to_execute_some_commands';
|
||||
break;
|
||||
case 3:
|
||||
if (count($commands) === $error_count) {
|
||||
$message = 'failed_to_execute_all_commands';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$result = array('error' => true, 'message' => $message, 'values' => $command_results);
|
||||
} else {
|
||||
$result = $command_results;
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the credentials entered by the user
|
||||
*
|
||||
* @param array $creds an array of filesystem credentials
|
||||
* @return array An array containing the result of the validation process.
|
||||
*/
|
||||
public function validate_credentials($creds) {
|
||||
|
||||
try {
|
||||
|
||||
$entity = $creds['entity'];
|
||||
if (isset($creds['filesystem_credentials'])) {
|
||||
parse_str($creds['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include the needed WP Core file(s)
|
||||
// template.php needed for submit_button() which is called by request_filesystem_credentials()
|
||||
$this->_admin_include('file.php', 'template.php');
|
||||
|
||||
// Directory entities that we currently need permissions
|
||||
// to update.
|
||||
$entity_directories = array(
|
||||
'plugins' => WP_PLUGIN_DIR,
|
||||
'themes' => WP_CONTENT_DIR.'/themes',
|
||||
'core' => untrailingslashit(ABSPATH)
|
||||
);
|
||||
|
||||
if ('translations' === $entity) {
|
||||
// 'en_US' don't usually have the "languages" folder, thus, we
|
||||
// check if there's a need to ask for filesystem credentials for that
|
||||
// folder if it exists, most especially for locale other than 'en_US'.
|
||||
$language_dir = WP_CONTENT_DIR.'/languages';
|
||||
if ('en_US' !== get_locale() && is_dir($language_dir)) {
|
||||
$entity_directories['translations'] = $language_dir;
|
||||
}
|
||||
}
|
||||
|
||||
$url = wp_nonce_url(site_url());
|
||||
|
||||
$passed = false;
|
||||
if (isset($entity_directories[$entity])) {
|
||||
$directory = $entity_directories[$entity];
|
||||
|
||||
// Check if credentials are valid and have sufficient
|
||||
// privileges to create and delete (e.g. write)
|
||||
ob_start();
|
||||
$credentials = request_filesystem_credentials($url, '', false, $directory);
|
||||
ob_end_clean();
|
||||
|
||||
// The "WP_Filesystem" will suffice in validating the inputted credentials
|
||||
// from UpdraftCentral, as it is already attempting to connect to the filesystem
|
||||
// using the chosen transport (e.g. ssh, ftp, etc.)
|
||||
$passed = WP_Filesystem($credentials, $directory);
|
||||
}
|
||||
|
||||
if ($passed) {
|
||||
$result = array('error' => false, 'message' => 'credentials_ok', 'values' => array());
|
||||
} else {
|
||||
// We're adding some useful error information to help troubleshooting any problems
|
||||
// that may arise in the future. If the user submitted a wrong password or username
|
||||
// it usually falls through here.
|
||||
global $wp_filesystem;
|
||||
|
||||
$errors = array();
|
||||
if (isset($wp_filesystem->errors) && is_wp_error($wp_filesystem->errors)) {
|
||||
$errors = $wp_filesystem->errors->errors;
|
||||
}
|
||||
|
||||
$result = array('error' => true, 'message' => 'failed_credentials', 'values' => array('errors' => $errors));
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FileSystem Credentials
|
||||
*
|
||||
* Extract the needed filesystem credentials (permissions) to be used
|
||||
* to update/upgrade the plugins, themes and the WP core.
|
||||
*
|
||||
* @return array $result - An array containing the creds form and some flags
|
||||
* to determine whether we need to extract the creds
|
||||
* manually from the user.
|
||||
*/
|
||||
public function get_credentials() {
|
||||
|
||||
try {
|
||||
|
||||
// Check whether user has enough permission to update entities
|
||||
if (!current_user_can('update_plugins') && !current_user_can('update_themes') && !current_user_can('update_core')) return $this->_generic_error_response('updates_permission_denied');
|
||||
|
||||
// Include the needed WP Core file(s)
|
||||
$this->_admin_include('file.php', 'template.php');
|
||||
|
||||
// A container that will hold the state (in this case, either true or false) of
|
||||
// each directory entities (plugins, themes, core) that will be used to determine
|
||||
// whether or not there's a need to show a form that will ask the user for their credentials
|
||||
// manually.
|
||||
$request_filesystem_credentials = array();
|
||||
|
||||
// A container for the filesystem credentials form if applicable.
|
||||
$filesystem_form = '';
|
||||
|
||||
// Directory entities that we currently need permissions
|
||||
// to update.
|
||||
$check_fs = array(
|
||||
'plugins' => WP_PLUGIN_DIR,
|
||||
'themes' => WP_CONTENT_DIR.'/themes',
|
||||
'core' => untrailingslashit(ABSPATH)
|
||||
);
|
||||
|
||||
// Here, we're looping through each entities and find output whether
|
||||
// we have sufficient permissions to update objects belonging to them.
|
||||
foreach ($check_fs as $entity => $dir) {
|
||||
|
||||
// We're determining which method to use when updating
|
||||
// the files in the filesystem.
|
||||
$filesystem_method = get_filesystem_method(array(), $dir);
|
||||
|
||||
// Buffering the output to pull the actual credentials form
|
||||
// currently being used by this WP instance if no sufficient permissions
|
||||
// is found.
|
||||
$url = wp_nonce_url(site_url());
|
||||
|
||||
ob_start();
|
||||
$filesystem_credentials_are_stored = request_filesystem_credentials($url, $filesystem_method);
|
||||
$form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
|
||||
|
||||
if (!empty($form)) {
|
||||
$filesystem_form = $form;
|
||||
}
|
||||
ob_end_clean();
|
||||
|
||||
// Save the state whether or not there's a need to show the
|
||||
// credentials form to the user.
|
||||
$request_filesystem_credentials[$entity] = ('direct' !== $filesystem_method && !$filesystem_credentials_are_stored);
|
||||
}
|
||||
|
||||
// Wrapping the credentials info before passing it back
|
||||
// to the client issuing the request.
|
||||
$result = array(
|
||||
'request_filesystem_credentials' => $request_filesystem_credentials,
|
||||
'filesystem_form' => $filesystem_form
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a browser-usable URL which will automatically log the user in to the site
|
||||
*
|
||||
* @param String $redirect_to - the URL to got to after logging in
|
||||
* @param Array $extra_info - valid keys are user_id, which should be a numeric user ID to log in as.
|
||||
*/
|
||||
public function get_login_url($redirect_to, $extra_info) {
|
||||
|
||||
if (is_array($extra_info) && !empty($extra_info['user_id']) && is_numeric($extra_info['user_id'])) {
|
||||
|
||||
$user_id = $extra_info['user_id'];
|
||||
|
||||
if (false == ($login_key = $this->_get_autologin_key($user_id))) return $this->_generic_error_response('user_key_failure');
|
||||
|
||||
// Default value
|
||||
$redirect_url = network_admin_url();
|
||||
if (is_array($redirect_to) && !empty($redirect_to['module'])) {
|
||||
switch ($redirect_to['module']) {
|
||||
case 'updraftplus':
|
||||
if ('initiate_restore' == $redirect_to['action'] && class_exists('UpdraftPlus_Options')) {
|
||||
$redirect_url = UpdraftPlus_Options::admin_page_url().'?page=updraftplus&udaction=initiate_restore&entities='.urlencode($redirect_to['data']['entities']).'&showdata='.urlencode($redirect_to['data']['showdata']).'&backup_timestamp='.(int) $redirect_to['data']['backup_timestamp'];
|
||||
|
||||
} elseif ('download_file' == $redirect_to['action']) {
|
||||
$findex = empty($redirect_to['data']['findex']) ? 0 : (int) $redirect_to['data']['findex'];
|
||||
// e.g. ?udcentral_action=dl&action=updraftplus_spool_file&backup_timestamp=1455101696&findex=0&what=plugins
|
||||
$redirect_url = site_url().'?udcentral_action=spool_file&action=updraftplus_spool_file&findex='.$findex.'&what='.urlencode($redirect_to['data']['what']).'&backup_timestamp='.(int) $redirect_to['data']['backup_timestamp'];
|
||||
}
|
||||
break;
|
||||
case 'direct_url':
|
||||
$redirect_url = $redirect_to['url'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$login_key = apply_filters('updraftplus_remotecontrol_login_key', array(
|
||||
'key' => $login_key,
|
||||
'created' => time(),
|
||||
'redirect_url' => $redirect_url
|
||||
), $redirect_to, $extra_info);
|
||||
|
||||
// Over-write any previous value - only one can be valid at a time)
|
||||
update_user_meta($user_id, 'updraftcentral_login_key', $login_key);
|
||||
|
||||
return $this->_response(array(
|
||||
'login_url' => network_site_url('?udcentral_action=login&login_id='.$user_id.'&login_key='.$login_key['key'])
|
||||
));
|
||||
|
||||
} else {
|
||||
return $this->_generic_error_response('user_unknown');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information derived from phpinfo()
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function phpinfo() {
|
||||
$phpinfo = $this->_get_phpinfo_array();
|
||||
|
||||
if (!empty($phpinfo)) {
|
||||
return $this->_response($phpinfo);
|
||||
}
|
||||
|
||||
return $this->_generic_error_response('phpinfo_fail');
|
||||
}
|
||||
|
||||
/**
|
||||
* The key obtained is only intended to be short-lived. Hence, there's no intention other than that it is random and only used once - only the most recent one is valid.
|
||||
*
|
||||
* @param Integer $user_id Specific user ID to get the autologin key
|
||||
* @return Array
|
||||
*/
|
||||
public function _get_autologin_key($user_id) {
|
||||
$secure_auth_key = defined('SECURE_AUTH_KEY') ? SECURE_AUTH_KEY : hash('sha256', DB_PASSWORD).'_'.rand(0, 999999999);
|
||||
if (!defined('SECURE_AUTH_KEY')) return false;
|
||||
$hash_it = $user_id.'_'.microtime(true).'_'.rand(0, 999999999).'_'.$secure_auth_key;
|
||||
$hash = hash('sha256', $hash_it);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
public function site_info() {
|
||||
global $wpdb;
|
||||
|
||||
// THis is included so we can get $wp_version
|
||||
@include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
||||
|
||||
$ud_version = is_a($this->ud, 'UpdraftPlus') ? $this->ud->version : 'none';
|
||||
|
||||
return $this->_response(array(
|
||||
'versions' => array(
|
||||
'ud' => $ud_version,
|
||||
'php' => PHP_VERSION,
|
||||
'wp' => $wp_version,// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
|
||||
'mysql' => $wpdb->db_version(),
|
||||
'udrpc_php' => $this->rc->udrpc_version,
|
||||
),
|
||||
'bloginfo' => array(
|
||||
'url' => network_site_url(),
|
||||
'name' => get_bloginfo('name'),
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* This calls the WP_Action within WP
|
||||
*
|
||||
* @param array $data Array of Data to be used within call_wp_action
|
||||
* @return array
|
||||
*/
|
||||
public function call_wordpress_action($data) {
|
||||
if (false === ($updraftplus_admin = $this->_load_ud_admin())) return $this->_generic_error_response('no_updraftplus');
|
||||
$response = $updraftplus_admin->call_wp_action($data);
|
||||
|
||||
if (empty($data["wpaction"])) {
|
||||
return $this->_generic_error_response("error", "no command sent");
|
||||
}
|
||||
|
||||
return $this->_response(array(
|
||||
"response" => $response['response'],
|
||||
"status" => $response['status'],
|
||||
"log" => $response['log']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get disk space used
|
||||
*
|
||||
* @uses UpdraftPlus_Filesystem_Functions::get_disk_space_used()
|
||||
*
|
||||
* @param String $entity - the entity to count (e.g. 'plugins', 'themes')
|
||||
*
|
||||
* @return Array - response
|
||||
*/
|
||||
public function count($entity) {
|
||||
if (!class_exists('UpdraftPlus_Filesystem_Functions')) return $this->_generic_error_response('no_updraftplus');
|
||||
$response = UpdraftPlus_Filesystem_Functions::get_disk_space_used($entity);
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://secure.php.net/phpinfo
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
private function _get_phpinfo_array() {
|
||||
if (!function_exists('phpinfo')) return null;
|
||||
ob_start();
|
||||
phpinfo(INFO_GENERAL|INFO_CREDITS|INFO_MODULES);
|
||||
$phpinfo = array('phpinfo' => array());
|
||||
|
||||
if (preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
if (strlen($match[1])) {
|
||||
$phpinfo[$match[1]] = array();
|
||||
} elseif (isset($match[3])) {
|
||||
$keys1 = array_keys($phpinfo);
|
||||
$phpinfo[end($keys1)][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3];
|
||||
} else {
|
||||
$keys1 = array_keys($phpinfo);
|
||||
$phpinfo[end($keys1)][] = $match[2];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return $phpinfo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an UpdraftPlus_Admin object
|
||||
*
|
||||
* @return UpdraftPlus_Admin|Boolean - false in case of failure
|
||||
*/
|
||||
private function _load_ud_admin() {
|
||||
if (!defined('UPDRAFTPLUS_DIR') || !is_file(UPDRAFTPLUS_DIR.'/admin.php')) return false;
|
||||
updraft_try_include_file('admin.php', 'include_once');
|
||||
global $updraftplus_admin;
|
||||
return $updraftplus_admin;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,601 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Media Commands
|
||||
*/
|
||||
class UpdraftCentral_Media_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and retrieves posts based from the submitted parameters
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function get_media_items($params) {
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
// check paged parameter; if empty set to defaults
|
||||
$paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
|
||||
$numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
|
||||
$offset = ($paged - 1) * $numberposts;
|
||||
|
||||
$args = array(
|
||||
'posts_per_page' => $numberposts,
|
||||
'paged' => $paged,
|
||||
'offset' => $offset,
|
||||
'post_type' => 'attachment',
|
||||
'post_status' => 'inherit',
|
||||
);
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$args['s'] = $params['keyword'];
|
||||
}
|
||||
|
||||
if (!empty($params['category'])) {
|
||||
if (in_array($params['category'], array('detached', 'unattached'))) {
|
||||
$attachment_ids = $this->get_unattached_ids();
|
||||
} else {
|
||||
$attachment_ids = $this->get_type_ids($params['category']);
|
||||
}
|
||||
|
||||
$args['post__in'] = $attachment_ids;
|
||||
}
|
||||
|
||||
if (!empty($params['date'])) {
|
||||
list($monthnum, $year) = explode(':', $params['date']);
|
||||
|
||||
$args['monthnum'] = $monthnum;
|
||||
$args['year'] = $year;
|
||||
}
|
||||
|
||||
$query = new WP_Query($args);
|
||||
$result = $query->posts;
|
||||
|
||||
$count_posts = (int) $query->found_posts;
|
||||
$page_count = 0;
|
||||
|
||||
if ($count_posts > 0) {
|
||||
$page_count = absint($count_posts / $numberposts);
|
||||
$remainder = absint($count_posts % $numberposts);
|
||||
$page_count = ($remainder > 0) ? ++$page_count : $page_count;
|
||||
}
|
||||
|
||||
$info = array(
|
||||
'page' => $paged,
|
||||
'pages' => $page_count,
|
||||
'results' => $count_posts,
|
||||
'items_from' => (($paged * $numberposts) - $numberposts) + 1,
|
||||
'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
|
||||
);
|
||||
|
||||
$media_items = array();
|
||||
if (!empty($result)) {
|
||||
foreach ($result as $item) {
|
||||
$media = $this->get_media_item($item, null, true);
|
||||
if (!empty($media)) {
|
||||
array_push($media_items, $media);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'items' => $media_items,
|
||||
'info' => $info,
|
||||
'options' => array(
|
||||
'date' => $this->get_date_options(),
|
||||
'type' => $this->get_type_options()
|
||||
)
|
||||
);
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we have an image editor (e.g. GD, Imagick, etc.) set in place to handle the basic editing
|
||||
* functions such as rotate, crop, etc. If not, then we hide that feature in UpdraftCentral
|
||||
*
|
||||
* @param object $media The media item/object to check
|
||||
* @return boolean
|
||||
*/
|
||||
private function has_image_editor($media) {
|
||||
// Most of the time image library are enabled by default in the php.ini but there's a possbility that users don't
|
||||
// enable them as they have no need for them at the moment or for some other reasons. Thus, we need to confirm
|
||||
// that here through the wp_get_image_editor method.
|
||||
$has_image_editor = true;
|
||||
if (!empty($media)) {
|
||||
if (!function_exists('wp_get_image_editor')) {
|
||||
require_once(ABSPATH.'wp-includes/media.php');
|
||||
}
|
||||
|
||||
if (!function_exists('_load_image_to_edit_path')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
$image_editor = wp_get_image_editor(_load_image_to_edit_path($media->ID));
|
||||
if (is_wp_error($image_editor)) {
|
||||
$has_image_editor = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $has_image_editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a single media item information
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @param array|null $extra_info Additional information from the current request
|
||||
* @param boolean $raw If set, returns the result of the fetch process unwrapped by the response array
|
||||
* @return array
|
||||
*/
|
||||
public function get_media_item($params, $extra_info = null, $raw = false) {
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
// Raw means that we need to return the result without wrapping it
|
||||
// with the "$this->_response" function which indicates that the call
|
||||
// was done locally (within the class) and not directly from UpdraftCentral.
|
||||
if ($raw && is_object($params) && isset($params->ID)) {
|
||||
$media = $params;
|
||||
} elseif (is_array($params) && !empty($params['id'])) {
|
||||
$media = get_post($params['id']);
|
||||
}
|
||||
|
||||
if (!function_exists('get_post_mime_types')) {
|
||||
global $updraftcentral_main;
|
||||
|
||||
// For a much later version of WP the "get_post_mime_types" is located
|
||||
// in a different folder. So, we make sure that we have it loaded before
|
||||
// actually using it.
|
||||
if (version_compare($updraftcentral_main->get_wordpress_version(), '3.5', '>=')) {
|
||||
require_once(ABSPATH.WPINC.'/post.php');
|
||||
} else {
|
||||
// For WP 3.4, the "get_post_mime_types" is located in the location provided below.
|
||||
require_once(ABSPATH.'wp-admin/includes/post.php');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('wp_image_editor')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image-edit.php');
|
||||
}
|
||||
|
||||
if (!function_exists('get_media_item')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/template.php');
|
||||
require_once(ABSPATH.'wp-admin/includes/media.php');
|
||||
}
|
||||
|
||||
|
||||
if ($media) {
|
||||
$thumb = wp_get_attachment_image_src($media->ID, 'thumbnail', true);
|
||||
if (!empty($thumb)) $media->thumb_url = $thumb[0];
|
||||
|
||||
$media->url = wp_get_attachment_url($media->ID);
|
||||
$media->parent_post_title = get_the_title($media->post_parent);
|
||||
$media->author = get_the_author_meta('display_name', $media->post_author);
|
||||
$media->filename = basename($media->url);
|
||||
$media->date = date('Y/m/d', strtotime($media->post_date));
|
||||
$media->upload_date = mysql2date(get_option('date_format'), $media->post_date);
|
||||
|
||||
$media->filesize = 0;
|
||||
$file = get_attached_file($media->ID);
|
||||
if (!empty($file) && file_exists($file)) {
|
||||
$media->filesize = size_format(filesize($file));
|
||||
}
|
||||
|
||||
$media->nonce = wp_create_nonce('image_editor-'.$media->ID);
|
||||
if (false !== strpos($media->post_mime_type, 'image/')) {
|
||||
$meta = wp_get_attachment_metadata($media->ID);
|
||||
|
||||
$thumb = image_get_intermediate_size($media->ID, 'thumbnail');
|
||||
$sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
|
||||
|
||||
// Pulling details
|
||||
$sizer = 1;
|
||||
if (isset($meta['width'], $meta['height'])) {
|
||||
$big = max($meta['width'], $meta['height']);
|
||||
$sizer = $big > 400 ? 400 / $big : 1;
|
||||
}
|
||||
|
||||
$constrained_dims = array();
|
||||
if ($thumb && $sub_sizes) {
|
||||
$constrained_dims = wp_constrain_dimensions($thumb['width'], $thumb['height'], 160, 120);
|
||||
}
|
||||
|
||||
$rotate_supported = false;
|
||||
if (function_exists('imagerotate') || wp_image_editor_supports(array('mime_type' => get_post_mime_type($media->ID), 'methods' => array('rotate')))) {
|
||||
$rotate_supported = true;
|
||||
}
|
||||
|
||||
// Check for alternative text if present
|
||||
$alt = get_post_meta($media->ID, '_wp_attachment_image_alt', true);
|
||||
$media->alt = !empty($alt) ? $alt : '';
|
||||
|
||||
// Check whether edited images are restorable
|
||||
$backup_sizes = get_post_meta($media->ID, '_wp_attachment_backup_sizes', true);
|
||||
$can_restore = !empty($backup_sizes) && isset($backup_sizes['full-orig']) && basename($meta['file']) != $backup_sizes['full-orig']['file'];
|
||||
|
||||
$image_edit_overwrite = (!defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE) ? 0 : 1;
|
||||
$media->misc = array(
|
||||
'sizer' => $sizer,
|
||||
'rand' => rand(1, 99999),
|
||||
'constrained_dims' => $constrained_dims,
|
||||
'rotate_supported' => (int) $rotate_supported,
|
||||
'thumb' => $thumb,
|
||||
'meta' => $meta,
|
||||
'alt_text' => $alt,
|
||||
'can_restore' => $can_restore,
|
||||
'image_edit_overwrite' => $image_edit_overwrite
|
||||
);
|
||||
|
||||
$media->has_image_editor = $this->has_image_editor($media);
|
||||
}
|
||||
}
|
||||
|
||||
return $raw ? $media : $this->_response(array('item' => $media));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and retrieves posts based from the submitted parameters
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function get_posts($params) {
|
||||
$error = $this->_validate_capabilities(array('edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
// check paged parameter; if empty set to defaults
|
||||
$paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
|
||||
$numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
|
||||
$offset = ($paged - 1) * $numberposts;
|
||||
|
||||
$args = array(
|
||||
'posts_per_page' => $numberposts,
|
||||
'paged' => $paged,
|
||||
'offset' => $offset,
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish,private,draft,pending,future',
|
||||
);
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$args['s'] = $params['keyword'];
|
||||
}
|
||||
|
||||
$query = new WP_Query($args);
|
||||
$result = $query->posts;
|
||||
|
||||
$count_posts = (int) $query->found_posts;
|
||||
$page_count = 0;
|
||||
|
||||
if ($count_posts > 0) {
|
||||
$page_count = absint($count_posts / $numberposts);
|
||||
$remainder = absint($count_posts % $numberposts);
|
||||
$page_count = ($remainder > 0) ? ++$page_count : $page_count;
|
||||
}
|
||||
|
||||
$info = array(
|
||||
'page' => $paged,
|
||||
'pages' => $page_count,
|
||||
'results' => $count_posts,
|
||||
'items_from' => (($paged * $numberposts) - $numberposts) + 1,
|
||||
'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
|
||||
);
|
||||
|
||||
$posts = array();
|
||||
if (!empty($result)) {
|
||||
foreach ($result as $post) {
|
||||
array_push($posts, array('ID' => $post->ID, 'title' => $post->post_title));
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'posts' => $posts,
|
||||
'info' => $info
|
||||
);
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves media changes from UpdraftCentral
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function save_media_item($params) {
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
$args = array(
|
||||
'post_title' => $params['image_title'],
|
||||
'post_excerpt' => $params['image_caption'],
|
||||
'post_content' => $params['image_description']
|
||||
);
|
||||
|
||||
if (!empty($params['new'])) {
|
||||
$args['post_type'] = 'attachment';
|
||||
$media_id = wp_insert_post($args, true);
|
||||
} else {
|
||||
$args['ID'] = $params['id'];
|
||||
$args['post_modified'] = date('Y-m-d H:i:s');
|
||||
$args['post_modified_gmt'] = gmdate('Y-m-d H:i:s');
|
||||
|
||||
$media_id = wp_update_post($args, true);
|
||||
}
|
||||
|
||||
if (!empty($media_id)) {
|
||||
// Update alternative text if not empty
|
||||
if (!empty($params['image_alternative_text'])) {
|
||||
update_post_meta($media_id, '_wp_attachment_image_alt', $params['image_alternative_text']);
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'status' => 'success',
|
||||
'item' => $this->get_media_item(array('id' => $media_id), null, true)
|
||||
);
|
||||
} else {
|
||||
$result = array('status' => 'failed');
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes media action (e.g. attach, detach and delete)
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function execute_media_action($params) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
$result = array();
|
||||
switch ($params['do']) {
|
||||
case 'attach':
|
||||
global $wpdb;
|
||||
$query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = %d WHERE `post_type` = 'attachment' AND ID = %d", $params['parent_id'], $params['id']));
|
||||
|
||||
if (false === $query_result) {
|
||||
$result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_attach_media');
|
||||
} else {
|
||||
$result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('media_attached');
|
||||
}
|
||||
break;
|
||||
case 'detach':
|
||||
global $wpdb;
|
||||
$query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = 0 WHERE `post_type` = 'attachment' AND ID = %d", $params['id']));
|
||||
|
||||
if (false === $query_result) {
|
||||
$result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_detach_media');
|
||||
} else {
|
||||
$result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('media_detached');
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$failed_items = array();
|
||||
foreach ($params['ids'] as $id) {
|
||||
// Delete permanently
|
||||
if (false === wp_delete_attachment($id, true)) {
|
||||
$failed_items[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($failed_items)) {
|
||||
$result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_delete_media');
|
||||
$result['items'] = $failed_items;
|
||||
} else {
|
||||
$result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('selected_media_deleted');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a collection of formatted dates found for the given post statuses.
|
||||
* It will be used as options for the date filter when managing the media items in UpdraftCentral.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_date_options() {
|
||||
global $wpdb;
|
||||
$options = array();
|
||||
|
||||
$date_options = $wpdb->get_col("SELECT DATE_FORMAT(`post_date`, '%M %Y') as `formatted_post_date` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `formatted_post_date` ORDER BY `post_date` DESC");
|
||||
|
||||
if (!empty($date_options)) {
|
||||
foreach ($date_options as $monthyear) {
|
||||
$timestr = strtotime($monthyear);
|
||||
$options[] = array('label' => date('F Y', $timestr), 'value' => date('n:Y', $timestr));
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves mime types that will be use as filter option in UpdraftCentral
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_type_options() {
|
||||
global $wpdb, $updraftcentral_host_plugin, $updraftcentral_main;
|
||||
|
||||
$options = array();
|
||||
if (!function_exists('get_post_mime_types')) {
|
||||
// For a much later version of WP the "get_post_mime_types" is located
|
||||
// in a different folder. So, we make sure that we have it loaded before
|
||||
// actually using it.
|
||||
if (version_compare($updraftcentral_main->get_wordpress_version(), '3.5', '>=')) {
|
||||
require_once(ABSPATH.WPINC.'/post.php');
|
||||
} else {
|
||||
// For WP 3.4, the "get_post_mime_types" is located in the location provided below.
|
||||
require_once(ABSPATH.'wp-admin/includes/post.php');
|
||||
}
|
||||
}
|
||||
|
||||
$post_mime_types = get_post_mime_types();
|
||||
$type_options = $wpdb->get_col("SELECT `post_mime_type` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `post_mime_type` ORDER BY `post_mime_type` DESC");
|
||||
|
||||
foreach ($post_mime_types as $mime_type => $label) {
|
||||
if (!wp_match_mime_types($mime_type, $type_options)) continue;
|
||||
$options[] = array('label' => $label[0], 'value' => esc_attr($mime_type));
|
||||
}
|
||||
|
||||
$options[] = array('label' => $updraftcentral_host_plugin->retrieve_show_message('unattached'), 'value' => 'detached');
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves media items that haven't been attached to any posts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_unattached_ids() {
|
||||
global $wpdb;
|
||||
return $wpdb->get_col("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_parent` = '0'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves IDs of media items that has the given mime type
|
||||
*
|
||||
* @param string $type The mime type to search for
|
||||
* @return array
|
||||
*/
|
||||
private function get_type_ids($type) {
|
||||
global $wpdb;
|
||||
return $wpdb->get_col($wpdb->prepare("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_mime_type` LIKE %s", $type.'/%'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have the required fields submitted and the user has
|
||||
* the capabilities to execute the requested action
|
||||
*
|
||||
* @param array $capabilities The capabilities to check and validate
|
||||
*
|
||||
* @return array|void
|
||||
*/
|
||||
private function _validate_capabilities($capabilities) {
|
||||
foreach ($capabilities as $capability) {
|
||||
if (!current_user_can($capability)) {
|
||||
return $this->_generic_error_response('insufficient_permission');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the $_REQUEST global variable with the submitted data
|
||||
*
|
||||
* @param array $params Submitted data received from UpdraftCentral
|
||||
* @return array
|
||||
*/
|
||||
private function populate_request($params) {
|
||||
if (!empty($params)) {
|
||||
foreach ($params as $key => $value) {
|
||||
$_REQUEST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles image editing requests coming from UpdraftCentral
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function image_editor($params) {
|
||||
$error = $this->_validate_capabilities(array('edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
$attachment_id = (int) $params['postid'];
|
||||
$this->populate_request($params);
|
||||
|
||||
if (!function_exists('load_image_to_edit')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
include_once(ABSPATH.'wp-admin/includes/image-edit.php');
|
||||
$msg = false;
|
||||
switch ($params['do']) {
|
||||
case 'save':
|
||||
case 'scale':
|
||||
$msg = wp_save_image($attachment_id);
|
||||
break;
|
||||
case 'restore':
|
||||
$msg = wp_restore_image($attachment_id);
|
||||
break;
|
||||
}
|
||||
|
||||
$msg = (false !== $msg) ? json_encode($msg) : $msg;
|
||||
return $this->_response(array('content' => $msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles image preview requests coming from UpdraftCentral
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function image_preview($params) {
|
||||
$error = $this->_validate_capabilities(array('edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
if (!function_exists('load_image_to_edit')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
include_once(ABSPATH.'wp-admin/includes/image-edit.php');
|
||||
$this->populate_request($params);
|
||||
$post_id = (int) $params['postid'];
|
||||
|
||||
ob_start();
|
||||
stream_preview_image($post_id);
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $this->_response(array('content' => base64_encode($content)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
// Load the posts command class since we're going to be extending it for our page module service/command
|
||||
// class in order to minimize redundant shareable methods.
|
||||
if (!class_exists('UpdraftCentral_Posts_Commands')) require_once('posts.php');
|
||||
|
||||
/**
|
||||
* Handles Pages Commands
|
||||
*/
|
||||
class UpdraftCentral_Pages_Commands extends UpdraftCentral_Posts_Commands {
|
||||
|
||||
protected $post_type = 'page';
|
||||
}
|
||||
@@ -0,0 +1,700 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles UpdraftCentral Plugin Commands which basically handles
|
||||
* the installation and activation of a plugin
|
||||
*/
|
||||
class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->_admin_include('plugin.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'plugin-install.php', 'update.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates a plugin through upload
|
||||
*
|
||||
* @param array $params Parameter array containing information pertaining the currently uploaded plugin
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function upload_plugin($params) {
|
||||
return $this->process_chunk_upload($params, 'plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the plugin is currently installed and activated.
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the plugin to check
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function is_plugin_installed($query) {
|
||||
|
||||
if (!isset($query['plugin']))
|
||||
return $this->_generic_error_response('plugin_name_required');
|
||||
|
||||
|
||||
$result = $this->_get_plugin_info($query);
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies currently requested action for plugin processing
|
||||
*
|
||||
* @param string $action The action to apply (e.g. activate or install)
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _apply_plugin_action($action, $query) {
|
||||
|
||||
$result = array();
|
||||
switch ($action) {
|
||||
case 'activate':
|
||||
case 'network_activate':
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['installed']) {
|
||||
$activate = activate_plugin($info['plugin_path']);
|
||||
if (is_wp_error($activate)) {
|
||||
$result = $this->_generic_error_response('generic_response_error', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'generic_response_error',
|
||||
'error_message' => $activate->get_error_message(),
|
||||
'info' => $this->_get_plugin_info($query)
|
||||
));
|
||||
} else {
|
||||
$result = array('activated' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('plugin_not_installed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'plugin_not_installed',
|
||||
'error_message' => __('The plugin you wish to activate is either not installed or has been removed recently.', 'updraftplus'),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'deactivate':
|
||||
case 'network_deactivate':
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['active']) {
|
||||
deactivate_plugins($info['plugin_path']);
|
||||
if (!is_plugin_active($info['plugin_path'])) {
|
||||
$result = array('deactivated' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('deactivate_plugin_failed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'deactivate_plugin_failed',
|
||||
'error_message' => __('There appears to be a problem deactivating the intended plugin.', 'updraftplus').' '.__('Please check your permissions and try again.', 'updraftplus'),
|
||||
'info' => $this->_get_plugin_info($query)
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('not_active', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'not_active',
|
||||
'error_message' => __('The plugin you wish to deactivate is currently not active or is already deactivated.', 'updraftplus'),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'install':
|
||||
$api = plugins_api('plugin_information', array(
|
||||
'slug' => $query['slug'],
|
||||
'fields' => array(
|
||||
'short_description' => false,
|
||||
'sections' => false,
|
||||
'requires' => false,
|
||||
'rating' => false,
|
||||
'ratings' => false,
|
||||
'downloaded' => false,
|
||||
'last_updated' => false,
|
||||
'added' => false,
|
||||
'tags' => false,
|
||||
'compatibility' => false,
|
||||
'homepage' => false,
|
||||
'donate_link' => false,
|
||||
)
|
||||
));
|
||||
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if (is_wp_error($api)) {
|
||||
$result = $this->_generic_error_response('generic_response_error', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'generic_response_error',
|
||||
'error_message' => $api->get_error_message(),
|
||||
'info' => $info
|
||||
));
|
||||
} else {
|
||||
$installed = $info['installed'];
|
||||
|
||||
$error_code = $error_message = '';
|
||||
if (!$installed) {
|
||||
// WP < 3.7
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) include_once(dirname(dirname(__FILE__)).'/classes/class-automatic-upgrader-skin.php');
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin();
|
||||
$upgrader = new Plugin_Upgrader($skin);
|
||||
|
||||
$download_link = $api->download_link;
|
||||
$installed = $upgrader->install($download_link);
|
||||
|
||||
if (is_wp_error($installed)) {
|
||||
$error_code = $installed->get_error_code();
|
||||
$error_message = $installed->get_error_message();
|
||||
} elseif (is_wp_error($skin->result)) {
|
||||
$error_code = $skin->result->get_error_code();
|
||||
$error_message = $skin->result->get_error_message();
|
||||
|
||||
$error_data = $skin->result->get_error_data($error_code);
|
||||
if (!empty($error_data)) {
|
||||
if (is_array($error_data)) $error_data = json_encode($error_data);
|
||||
$error_message .= ' '.$error_data;
|
||||
}
|
||||
} elseif (is_null($installed) || !$installed) {
|
||||
global $wp_filesystem;
|
||||
$upgrade_messages = $skin->get_upgrade_messages();
|
||||
|
||||
if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
|
||||
|
||||
// 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->get_error_code()) {
|
||||
$error_code = $wp_filesystem->errors->get_error_code();
|
||||
$error_message = $wp_filesystem->errors->get_error_message();
|
||||
} elseif (!empty($upgrade_messages)) {
|
||||
// We're only after for the last feedback that we received from the install process. Mostly,
|
||||
// that is where the last error has been inserted.
|
||||
$messages = $skin->get_upgrade_messages();
|
||||
$error_code = 'install_failed';
|
||||
$error_message = end($messages);
|
||||
} else {
|
||||
$error_code = 'unable_to_connect_to_filesystem';
|
||||
$error_message = __('Unable to connect to the filesystem.', 'updraftplus').' '.__('Please confirm your credentials.', 'updraftplus');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$installed || is_wp_error($installed)) {
|
||||
$result = $this->_generic_error_response('plugin_install_failed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => $error_code,
|
||||
'error_message' => $error_message,
|
||||
'info' => $this->_get_plugin_info($query)
|
||||
));
|
||||
} else {
|
||||
$result = array('installed' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preloads the submitted credentials to the global $_POST variable
|
||||
*
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*/
|
||||
private function _preload_credentials($query) {
|
||||
if (!empty($query) && isset($query['filesystem_credentials'])) {
|
||||
parse_str($query['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have the required fields submitted and the user has
|
||||
* the capabilities to execute the requested action
|
||||
*
|
||||
* @param array $query The submitted information
|
||||
* @param array $fields The required fields to check
|
||||
* @param array $capabilities The capabilities to check and validate
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
private function _validate_fields_and_capabilities($query, $fields, $capabilities) {
|
||||
|
||||
$error = '';
|
||||
if (!empty($fields)) {
|
||||
for ($i=0; $i<count($fields); $i++) {
|
||||
$field = $fields[$i];
|
||||
|
||||
if (!isset($query[$field])) {
|
||||
if ('keyword' === $field) {
|
||||
$error = $this->_generic_error_response('keyword_required');
|
||||
} else {
|
||||
$error = $this->_generic_error_response('plugin_'.$query[$field].'_required');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error) && !empty($capabilities)) {
|
||||
for ($i=0; $i<count($capabilities); $i++) {
|
||||
if (!current_user_can($capabilities[$i])) {
|
||||
$error = $this->_generic_error_response('plugin_insufficient_permission');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing an action for multiple items
|
||||
*
|
||||
* @param array $query Parameter array containing a list of plugins to process
|
||||
* @return array Contains the results of the bulk process
|
||||
*/
|
||||
public function process_action_in_bulk($query) {
|
||||
$action = isset($query['action']) ? $query['action'] : '';
|
||||
$items = isset($query['args']) ? $query['args']['items'] : array();
|
||||
|
||||
$results = array();
|
||||
if (!empty($action) && !empty($items) && is_array($items)) {
|
||||
foreach ($items as $value) {
|
||||
if (method_exists($this, $action)) {
|
||||
$results[] = $this->$action($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the plugin to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function activate_plugin($query) {
|
||||
|
||||
$fields = array('plugin');
|
||||
$permissions = array('activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_activate' : 'activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the plugin to deactivate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function deactivate_plugin($query) {
|
||||
|
||||
$fields = array('plugin');
|
||||
$permissions = array('activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_deactivate' : 'deactivate', $query);
|
||||
if (empty($result['deactivated'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install and activates the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_activate_plugin($query) {
|
||||
|
||||
$fields = array('plugin', 'slug');
|
||||
$permissions = array('install_plugins', 'activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action('install', $query);
|
||||
if (!empty($result['installed']) && $result['installed']) {
|
||||
$result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_activate' : 'activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_plugin($query) {
|
||||
|
||||
$fields = array('plugin', 'slug');
|
||||
$permissions = array('install_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action('install', $query);
|
||||
if (empty($result['installed'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall/delete the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function delete_plugin($query) {
|
||||
|
||||
$fields = array('plugin');
|
||||
$permissions = array('delete_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['installed']) {
|
||||
// Deactivate first before delete to invalidate the activate
|
||||
// state/status prior to deleting the item. Otherwise, WordPress will keep
|
||||
// that state, and as soon as you install the same plugin it will be automatically
|
||||
// activated since it's previous state was kept.
|
||||
deactivate_plugins($info['plugin_path']);
|
||||
|
||||
$deleted = delete_plugins(array($info['plugin_path']));
|
||||
if ($deleted) {
|
||||
$result = array('deleted' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
} else {
|
||||
return $this->_generic_error_response('delete_plugin_failed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'delete_plugin_failed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('plugin_not_installed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'plugin_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates/upgrade the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function update_plugin($query) {
|
||||
|
||||
$fields = array('plugin', 'slug');
|
||||
$permissions = array('update_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
// Make sure that we still have the plugin installed before running
|
||||
// the update process
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['installed']) {
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$update_command = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
$result = $update_command->update_plugin($info['plugin_path'], $query['slug']);
|
||||
if (!empty($result['error'])) {
|
||||
$result['values'] = array('plugin' => $query['plugin'], 'info' => $info);
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('plugin_not_installed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'plugin_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin information along with its active and install status
|
||||
*
|
||||
* @internal
|
||||
* @param array $query Contains either the plugin name or slug or both to be used when retrieving information
|
||||
* @return array
|
||||
*/
|
||||
private function _get_plugin_info($query) {
|
||||
|
||||
$info = array(
|
||||
'active' => false,
|
||||
'installed' => false
|
||||
);
|
||||
|
||||
// Clear plugin cache so that newly installed/downloaded plugins
|
||||
// gets reflected when calling "get_plugins"
|
||||
if (function_exists('wp_clean_plugins_cache')) {
|
||||
wp_clean_plugins_cache();
|
||||
}
|
||||
|
||||
// Gets all plugins available.
|
||||
$get_plugins = get_plugins();
|
||||
|
||||
// Loops around each plugin available.
|
||||
foreach ($get_plugins as $key => $value) {
|
||||
$slug = $this->extract_slug_from_info($key, $value);
|
||||
|
||||
// If the plugin name matches that of the specified name, it will gather details.
|
||||
// In case name check isn't enough, we'll use slug to verify if the plugin being queried is actually installed.
|
||||
//
|
||||
// Reason for name check failure:
|
||||
// Due to plugin name inconsistencies - where wordpress.org registered plugin name is different
|
||||
// from the actual plugin files's metadata (found inside the plugin's PHP file itself).
|
||||
if ((!empty($query['plugin']) && html_entity_decode($value['Name']) === html_entity_decode($query['plugin'])) || (!empty($query['slug']) && $slug === $query['slug'])) {
|
||||
$info['installed'] = true;
|
||||
$info['active'] = is_plugin_active($key);
|
||||
$info['plugin_path'] = $key;
|
||||
$info['data'] = $value;
|
||||
$info['name'] = $value['Name'];
|
||||
$info['slug'] = $slug;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the slug from the plugin data
|
||||
*
|
||||
* @param string $key They key of the current info
|
||||
* @param array $info Data pulled from the plugin file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function extract_slug_from_info($key, $info) {
|
||||
if (!is_array($info) || empty($info) || empty($key)) return '';
|
||||
|
||||
$temp = explode('/', $key);
|
||||
|
||||
// With WP standards textdomain must always be equal to the plugin's folder name
|
||||
// but for premium plugins this may not always be the case thus, we extract the folder
|
||||
// name from the key as the default slug.
|
||||
$slug = basename($temp[0], '.php');
|
||||
|
||||
if (!empty($info['TextDomain']) && 1 === count($temp)) {
|
||||
// For plugin without folder we compare the extracted slug with the 'TextDomain'
|
||||
// and if they're not equal then 'TextDomain' will assume as slug.
|
||||
if ($slug != $info['TextDomain']) $slug = $info['TextDomain'];
|
||||
}
|
||||
|
||||
// If in case the user kept the hello-dolly plugin then we'll make sure that it gets
|
||||
// the proper slug for it, otherwise, we'll end up with the wrong slug 'hello' instead of
|
||||
// 'hello-dolly'. Wrong slug will produce error in UpdraftCentral when running it against
|
||||
// wordpress.org for further information retrieval.
|
||||
$slug = ('Hello Dolly' === $info['Name']) ? 'hello-dolly' : $slug;
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all available plugins with additional attributes and settings needed by UpdraftCentral
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function load_plugins($query) {
|
||||
|
||||
$permissions = array('install_plugins', 'activate_plugins');
|
||||
if (is_multisite() && !is_super_admin(get_current_user_id())) $permissions = array('activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, array(), $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$website = get_bloginfo('name');
|
||||
$results = array();
|
||||
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$updates = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
// Get plugins for update
|
||||
$plugin_updates = $updates->get_item_updates('plugins');
|
||||
|
||||
// Get all plugins
|
||||
$plugins = get_plugins();
|
||||
|
||||
if (is_multisite() && !is_super_admin(get_current_user_id())) {
|
||||
|
||||
// If the "Plugins" menu is disabled for the subsites on a multisite
|
||||
// network then we return an empty "plugins" array.
|
||||
$menu_items = get_site_option('menu_items');
|
||||
if (empty($menu_items) || !isset($menu_items['plugins'])) {
|
||||
$plugins = array();
|
||||
} else {
|
||||
$show_network_active = apply_filters('show_network_active_plugins', current_user_can('manage_network_plugins'));
|
||||
|
||||
$filtered_plugins = array();
|
||||
foreach ($plugins as $file => $data) {
|
||||
if (is_network_only_plugin($file) && !is_plugin_active($file)) {
|
||||
if ($show_network_active) $filtered_plugins[$file] = $data;
|
||||
} elseif (is_plugin_active_for_network($file)) {
|
||||
if ($show_network_active) $filtered_plugins[$file] = $data;
|
||||
} else {
|
||||
$filtered_plugins[$file] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
$plugins = $filtered_plugins;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($plugins as $key => $value) {
|
||||
$slug = $this->extract_slug_from_info($key, $value);
|
||||
|
||||
$plugin = new stdClass();
|
||||
$plugin->name = $value['Name'];
|
||||
$plugin->description = $value['Description'];
|
||||
$plugin->slug = $slug;
|
||||
$plugin->version = $value['Version'];
|
||||
$plugin->author = $value['Author'];
|
||||
$plugin->status = is_plugin_active($key) ? 'active' : 'inactive';
|
||||
$plugin->website = $website;
|
||||
$plugin->multisite = is_multisite();
|
||||
$plugin->site_url = trailingslashit(get_bloginfo('url'));
|
||||
|
||||
if (!empty($plugin_updates[$key])) {
|
||||
$update_info = $plugin_updates[$key];
|
||||
|
||||
if (version_compare($update_info->Version, $update_info->update->new_version, '<')) {
|
||||
if (!empty($update_info->update->new_version)) $plugin->latest_version = $update_info->update->new_version;
|
||||
if (!empty($update_info->update->package)) $plugin->download_link = $update_info->update->package;
|
||||
if (!empty($update_info->update->sections)) $plugin->sections = $update_info->update->sections;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($plugin->short_description) && !empty($plugin->description)) {
|
||||
// Only pull the first sentence as short description, it should be enough rather than displaying
|
||||
// an empty description or a full blown one which the user can access anytime if they press on
|
||||
// the view details link in UpdraftCentral.
|
||||
$temp = explode('.', $plugin->description);
|
||||
$short_description = $temp[0];
|
||||
|
||||
// Adding the second sentence wouldn't hurt, in case the first sentence is too short.
|
||||
if (isset($temp[1])) $short_description .= '.'.$temp[1];
|
||||
|
||||
$plugin->short_description = $short_description.'.';
|
||||
}
|
||||
|
||||
$results[] = $plugin;
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'plugins' => $results,
|
||||
'is_super_admin' => is_super_admin(),
|
||||
);
|
||||
|
||||
$result = array_merge($result, $this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the backup and security credentials settings for this website
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function get_plugin_requirements() {
|
||||
return $this->_response($this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,721 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles UpdraftCentral Theme Commands which basically handles
|
||||
* the installation and activation of a theme
|
||||
*/
|
||||
class UpdraftCentral_Theme_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->_admin_include('theme.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'theme-install.php', 'update.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates a theme through upload
|
||||
*
|
||||
* @param array $params Parameter array containing information pertaining the currently uploaded theme
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function upload_theme($params) {
|
||||
return $this->process_chunk_upload($params, 'theme');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the theme is currently installed and activated.
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to check
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function is_theme_installed($query) {
|
||||
|
||||
if (!isset($query['theme']))
|
||||
return $this->_generic_error_response('theme_name_required');
|
||||
|
||||
|
||||
$result = $this->_get_theme_info($query['theme']);
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies currently requested action for theme processing
|
||||
*
|
||||
* @param string $action The action to apply (e.g. activate or install)
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _apply_theme_action($action, $query) {
|
||||
|
||||
$result = array();
|
||||
switch ($action) {
|
||||
case 'activate':
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
switch_theme($info['slug']);
|
||||
if (wp_get_theme()->get_stylesheet() === $info['slug']) {
|
||||
$result = array('activated' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_activated', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_activated',
|
||||
'error_message' => __('There appears to be a problem activating or switching to the intended theme.', 'updraftplus').' '.__('Please check your permissions and try again.', 'updraftplus'),
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => __('The theme you wish to activate is either not installed or has been removed recently.', 'updraftplus'),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'network_enable':
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
if (current_user_can('manage_network_themes')) {
|
||||
// Make sure that network_enable_theme is present and callable since
|
||||
// it is only available at 4.6. If not, we'll do things the old fashion way
|
||||
if (is_callable(array('WP_Theme', 'network_enable_theme'))) {
|
||||
WP_Theme::network_enable_theme($info['slug']);
|
||||
} else {
|
||||
$allowed_themes = get_site_option('allowedthemes');
|
||||
$allowed_themes[$info['slug']] = true;
|
||||
|
||||
update_site_option('allowedthemes', $allowed_themes);
|
||||
}
|
||||
}
|
||||
|
||||
$allowed = WP_Theme::get_allowed_on_network();
|
||||
if (is_array($allowed) && !empty($allowed[$info['slug']])) {
|
||||
$result = array('enabled' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_enabled', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_enabled',
|
||||
'error_message' => __('There appears to be a problem enabling the intended theme on your network.', 'updraftplus').' '.__('Please kindly check your permission and try again.', 'updraftplus'),
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => __('The theme you wish to enable on your network is either not installed or has been removed recently.', 'updraftplus'),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'network_disable':
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
if (current_user_can('manage_network_themes')) {
|
||||
// Make sure that network_disable_theme is present and callable since
|
||||
// it is only available at 4.6. If not, we'll do things the old fashion way
|
||||
if (is_callable(array('WP_Theme', 'network_disable_theme'))) {
|
||||
WP_Theme::network_disable_theme($info['slug']);
|
||||
} else {
|
||||
$allowed_themes = get_site_option('allowedthemes');
|
||||
if (isset($allowed_themes[$info['slug']])) {
|
||||
unset($allowed_themes[$info['slug']]);
|
||||
}
|
||||
|
||||
update_site_option('allowedthemes', $allowed_themes);
|
||||
}
|
||||
}
|
||||
|
||||
$allowed = WP_Theme::get_allowed_on_network();
|
||||
if (is_array($allowed) && empty($allowed[$info['slug']])) {
|
||||
$result = array('disabled' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_disabled', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_disabled',
|
||||
'error_message' => __('There appears to be a problem disabling the intended theme from your network.', 'updraftplus').' '.__('Please kindly check your permission and try again.', 'updraftplus'),
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => __('The theme you wish to disable from your network is either not installed or has been removed recently.', 'updraftplus'),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'install':
|
||||
$api = themes_api('theme_information', array(
|
||||
'slug' => $query['slug'],
|
||||
'fields' => array(
|
||||
'description' => true,
|
||||
'sections' => false,
|
||||
'rating' => true,
|
||||
'ratings' => true,
|
||||
'downloaded' => true,
|
||||
'downloadlink' => true,
|
||||
'last_updated' => true,
|
||||
'screenshot_url' => true,
|
||||
'parent' => true,
|
||||
)
|
||||
));
|
||||
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if (is_wp_error($api)) {
|
||||
$result = $this->_generic_error_response('generic_response_error', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => $api->get_error_message(),
|
||||
'info' => $info
|
||||
));
|
||||
} else {
|
||||
$installed = $info['installed'];
|
||||
|
||||
$error_code = $error_message = '';
|
||||
if (!$installed) {
|
||||
// WP < 3.7
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) include_once(dirname(dirname(__FILE__)).'/classes/class-automatic-upgrader-skin.php');
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin();
|
||||
$upgrader = new Theme_Upgrader($skin);
|
||||
|
||||
$download_link = $api->download_link;
|
||||
$installed = $upgrader->install($download_link);
|
||||
|
||||
if (is_wp_error($installed)) {
|
||||
$error_code = $installed->get_error_code();
|
||||
$error_message = $installed->get_error_message();
|
||||
} elseif (is_wp_error($skin->result)) {
|
||||
$error_code = $skin->result->get_error_code();
|
||||
$error_message = $skin->result->get_error_message();
|
||||
|
||||
$error_data = $skin->result->get_error_data($error_code);
|
||||
if (!empty($error_data)) {
|
||||
if (is_array($error_data)) $error_data = json_encode($error_data);
|
||||
$error_message .= ' '.$error_data;
|
||||
}
|
||||
} elseif (is_null($installed) || !$installed) {
|
||||
global $wp_filesystem;
|
||||
$upgrade_messages = $skin->get_upgrade_messages();
|
||||
|
||||
if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
|
||||
|
||||
// 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->get_error_code()) {
|
||||
$error_code = $wp_filesystem->errors->get_error_code();
|
||||
$error_message = $wp_filesystem->errors->get_error_message();
|
||||
} elseif (!empty($upgrade_messages)) {
|
||||
// We're only after for the last feedback that we received from the install process. Mostly,
|
||||
// that is where the last error has been inserted.
|
||||
$messages = $skin->get_upgrade_messages();
|
||||
$error_code = 'install_failed';
|
||||
$error_message = end($messages);
|
||||
} else {
|
||||
$error_code = 'unable_to_connect_to_filesystem';
|
||||
$error_message = __('Unable to connect to the filesystem.', 'updraftplus').' '.__('Please confirm your credentials.', 'updraftplus');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$installed || is_wp_error($installed)) {
|
||||
$result = $this->_generic_error_response('theme_install_failed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => $error_code,
|
||||
'error_message' => $error_message,
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
} else {
|
||||
$result = array('installed' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preloads the submitted credentials to the global $_POST variable
|
||||
*
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*/
|
||||
private function _preload_credentials($query) {
|
||||
if (!empty($query) && isset($query['filesystem_credentials'])) {
|
||||
parse_str($query['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have the required fields submitted and the user has
|
||||
* the capabilities to execute the requested action
|
||||
*
|
||||
* @param array $query The submitted information
|
||||
* @param array $fields The required fields to check
|
||||
* @param array $capabilities The capabilities to check and validate
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
private function _validate_fields_and_capabilities($query, $fields, $capabilities) {
|
||||
|
||||
$error = '';
|
||||
if (!empty($fields)) {
|
||||
for ($i=0; $i<count($fields); $i++) {
|
||||
$field = $fields[$i];
|
||||
|
||||
if (!isset($query[$field])) {
|
||||
if ('keyword' === $field) {
|
||||
$error = $this->_generic_error_response('keyword_required');
|
||||
} else {
|
||||
$error = $this->_generic_error_response('theme_'.$query[$field].'_required');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error) && !empty($capabilities)) {
|
||||
for ($i=0; $i<count($capabilities); $i++) {
|
||||
if (!current_user_can($capabilities[$i])) {
|
||||
$error = $this->_generic_error_response('theme_insufficient_permission');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing an action for multiple items
|
||||
*
|
||||
* @param array $query Parameter array containing a list of themes to process
|
||||
* @return array Contains the results of the bulk process
|
||||
*/
|
||||
public function process_action_in_bulk($query) {
|
||||
$action = isset($query['action']) ? $query['action'] : '';
|
||||
$items = isset($query['args']) ? $query['args']['items'] : array();
|
||||
|
||||
$results = array();
|
||||
if (!empty($action) && !empty($items) && is_array($items)) {
|
||||
foreach ($items as $value) {
|
||||
if (method_exists($this, $action)) {
|
||||
$results[] = $this->$action($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function activate_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables theme for network
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function network_enable_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('network_enable', $query);
|
||||
if (empty($result['enabled'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables theme from network
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function network_disable_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('network_disable', $query);
|
||||
if (empty($result['disabled'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install and activates the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_activate_theme($query) {
|
||||
|
||||
$fields = array('theme', 'slug');
|
||||
$permissions = array('install_themes', 'switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('install', $query);
|
||||
if (!empty($result['installed']) && $result['installed']) {
|
||||
$result = $this->_apply_theme_action('activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_theme($query) {
|
||||
|
||||
$fields = array('theme', 'slug');
|
||||
$permissions = array('install_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('install', $query);
|
||||
if (empty($result['installed'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall/delete the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function delete_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('delete_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
$deleted = delete_theme($info['slug']);
|
||||
|
||||
if ($deleted) {
|
||||
$result = array('deleted' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
return $this->_generic_error_response('delete_theme_failed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'delete_theme_failed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates/upgrade the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function update_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('update_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
// Make sure that we still have the theme installed before running
|
||||
// the update process
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$update_command = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
$result = $update_command->update_theme($info['slug']);
|
||||
if (!empty($result['error'])) {
|
||||
$result['values'] = array('theme' => $query['theme'], 'info' => $info);
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the theme information along with its active and install status
|
||||
*
|
||||
* @internal
|
||||
* @param array $theme The name of the theme to pull the information from
|
||||
* @return array Contains the theme information
|
||||
*/
|
||||
private function _get_theme_info($theme) {
|
||||
|
||||
$info = array(
|
||||
'active' => false,
|
||||
'installed' => false
|
||||
);
|
||||
|
||||
// Clear theme cache so that newly installed/downloaded themes
|
||||
// gets reflected when calling "get_themes"
|
||||
if (function_exists('wp_clean_themes_cache')) {
|
||||
wp_clean_themes_cache();
|
||||
}
|
||||
|
||||
// Gets all themes available.
|
||||
$themes = wp_get_themes();
|
||||
$current_theme_slug = basename(get_stylesheet_directory());
|
||||
|
||||
// Loops around each theme available.
|
||||
foreach ($themes as $slug => $value) {
|
||||
$name = $value->get('Name');
|
||||
$theme_name = !empty($name) ? $name : $slug;
|
||||
|
||||
// If the theme name matches that of the specified name, it will gather details.
|
||||
if ($theme_name === $theme) {
|
||||
$info['installed'] = true;
|
||||
$info['active'] = ($slug === $current_theme_slug) ? true : false;
|
||||
$info['slug'] = $slug;
|
||||
$info['data'] = $value;
|
||||
$info['name'] = $theme_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all available themes with additional attributes and settings needed by UpdraftCentral
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function load_themes($query) {
|
||||
|
||||
$permissions = array('install_themes', 'switch_themes');
|
||||
$args = array();
|
||||
if (is_multisite() && !is_super_admin(get_current_user_id())) {
|
||||
$permissions = array('switch_themes');
|
||||
$args = array('allowed' => true, 'blog_id' => get_current_blog_id());
|
||||
}
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, array(), $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$website = get_bloginfo('name');
|
||||
$results = array();
|
||||
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$updates = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
// Get themes for update
|
||||
$theme_updates = (array) $updates->get_item_updates('themes');
|
||||
|
||||
// Get all themes
|
||||
$themes = wp_get_themes($args);
|
||||
$current_theme_slug = basename(get_stylesheet_directory());
|
||||
|
||||
foreach ($themes as $slug => $value) {
|
||||
$name = $value->get('Name');
|
||||
$theme_name = !empty($name) ? $name : $slug;
|
||||
|
||||
$theme = new stdClass();
|
||||
$theme->name = $theme_name;
|
||||
$theme->description = $value->get('Description');
|
||||
$theme->slug = $slug;
|
||||
$theme->version = $value->get('Version');
|
||||
$theme->author = $value->get('Author');
|
||||
$theme->status = ($slug === $current_theme_slug) ? 'active' : 'inactive';
|
||||
|
||||
$template = $value->get('Template');
|
||||
$theme->child_theme = !empty($template) ? true : false;
|
||||
$theme->website = $website;
|
||||
$theme->multisite = is_multisite();
|
||||
$theme->site_url = trailingslashit(get_bloginfo('url'));
|
||||
|
||||
if ($theme->child_theme) {
|
||||
$parent_theme = wp_get_theme($template);
|
||||
$parent_name = $parent_theme->get('Name');
|
||||
|
||||
$theme->parent = !empty($parent_name) ? $parent_name : $parent_theme->get_stylesheet();
|
||||
}
|
||||
|
||||
if (!empty($theme_updates[$slug])) {
|
||||
$update_info = $theme_updates[$slug];
|
||||
|
||||
if (version_compare($theme->version, $update_info->update['new_version'], '<')) {
|
||||
if (!empty($update_info->update['new_version'])) $theme->latest_version = $update_info->update['new_version'];
|
||||
if (!empty($update_info->update['package'])) $theme->download_link = $update_info->update['package'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($theme->short_description) && !empty($theme->description)) {
|
||||
// Only pull the first sentence as short description, it should be enough rather than displaying
|
||||
// an empty description or a full blown one which the user can access anytime if they press on
|
||||
// the view details link in UpdraftCentral.
|
||||
$temp = explode('.', $theme->description);
|
||||
$short_description = $temp[0];
|
||||
|
||||
// Adding the second sentence wouldn't hurt, in case the first sentence is too short.
|
||||
if (isset($temp[1])) $short_description .= '.'.$temp[1];
|
||||
|
||||
$theme->short_description = $short_description.'.';
|
||||
}
|
||||
|
||||
$results[] = $theme;
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'themes' => $results,
|
||||
'theme_updates' => $theme_updates,
|
||||
'is_super_admin' => is_super_admin(),
|
||||
);
|
||||
|
||||
$result = array_merge($result, $this->_get_backup_credentials_settings(get_theme_root()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the backup and security credentials settings for this website
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function get_theme_requirements() {
|
||||
return $this->_response($this->_get_backup_credentials_settings(get_theme_root()));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,632 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Users Commands
|
||||
*/
|
||||
class UpdraftCentral_Users_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
/**
|
||||
* Compares two user object whether one is lesser than, equal to, greater than the other
|
||||
*
|
||||
* @internal
|
||||
* @param array $a First user in the comparison
|
||||
* @param array $b Second user in the comparison
|
||||
* @return integer Comparison results (0 = equal, -1 = less than, 1 = greater than)
|
||||
*/
|
||||
private function compare_user_id($a, $b) {
|
||||
if ($a->ID === $b->ID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($a->ID < $b->ID) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches users based from the keyword submitted
|
||||
*
|
||||
* @internal
|
||||
* @param array $query Parameter array containing the filter and keyword fields
|
||||
* @return array Contains the list of users found as well as the total users count
|
||||
*/
|
||||
private function _search_users($query) {
|
||||
$this->_admin_include('user.php');
|
||||
$query1 = new WP_User_Query(array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'role'=> $query["role"],
|
||||
'search' => '*' . esc_attr($query["search"]) . '*',
|
||||
'search_columns' => array('user_login', 'user_email')
|
||||
));
|
||||
$query2 = new WP_User_Query(array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'role'=> $query["role"],
|
||||
'meta_query'=>array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => 'first_name',
|
||||
'value' => $query["search"],
|
||||
'compare' => 'LIKE'
|
||||
),
|
||||
array(
|
||||
'key' => 'last_name',
|
||||
'value' => $query["search"],
|
||||
'compare' => 'LIKE'
|
||||
),
|
||||
)
|
||||
));
|
||||
|
||||
if (empty($query1->results) && empty($query2->results)) {
|
||||
return array("message" => "users_not_found");
|
||||
} else {
|
||||
$found_users = array_merge($query1->results, $query2->results);
|
||||
$temp = array();
|
||||
foreach ($found_users as $new_user) {
|
||||
if (!isset($temp[$new_user->ID])) {
|
||||
$temp[$new_user->ID] = $new_user;
|
||||
}
|
||||
};
|
||||
|
||||
$users = array_values($temp);
|
||||
|
||||
// Sort users:
|
||||
usort($users, array($this, 'compare_user_id'));
|
||||
$offset = ((int) $query['page_no'] * (int) $query['per_page']) - (int) $query['per_page'];
|
||||
$user_list = array_slice($users, $offset, $query['per_page']);
|
||||
|
||||
return array(
|
||||
'users' => $user_list,
|
||||
'total_users' => count($users)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of pages needed to construct the pagination links
|
||||
*
|
||||
* @internal
|
||||
* @param array $query
|
||||
* @param array $total_users The total number of users found from the WP_User_Query query
|
||||
* @return array Contains information needed to construct the pagination links
|
||||
*/
|
||||
private function _calculate_pages($query, $total_users) {
|
||||
|
||||
$per_page_options = array(10, 20, 30, 40, 50);
|
||||
|
||||
if (!empty($query)) {
|
||||
|
||||
$pages = array();
|
||||
$page_count = ceil($total_users / $query["per_page"]);
|
||||
if ($page_count > 1) {
|
||||
|
||||
for ($i = 0; $i < $page_count; $i++) {
|
||||
if ($i + 1 == $query['page_no']) {
|
||||
$paginator_item = array(
|
||||
"value"=>$i+1,
|
||||
"setting"=>"disabled"
|
||||
);
|
||||
} else {
|
||||
$paginator_item = array(
|
||||
"value"=>$i+1
|
||||
);
|
||||
}
|
||||
array_push($pages, $paginator_item);
|
||||
};
|
||||
|
||||
if ($query['page_no'] >= $page_count) {
|
||||
$page_next = array(
|
||||
"value"=>$page_count,
|
||||
"setting"=>"disabled"
|
||||
);
|
||||
} else {
|
||||
$page_next = array(
|
||||
"value"=>$query['page_no'] + 1
|
||||
);
|
||||
};
|
||||
if (1 === $query['page_no']) {
|
||||
$page_prev = array(
|
||||
"value"=>1,
|
||||
"setting"=>"disabled"
|
||||
);
|
||||
} else {
|
||||
$page_prev = array(
|
||||
"value"=>$query['page_no'] - 1
|
||||
);
|
||||
};
|
||||
|
||||
return array(
|
||||
"page_no" => $query['page_no'],
|
||||
"per_page" => $query["per_page"],
|
||||
"page_count" => $page_count,
|
||||
"pages" => $pages,
|
||||
"page_next" => $page_next,
|
||||
"page_prev" => $page_prev,
|
||||
"total_results" => $total_users,
|
||||
"per_page_options" => $per_page_options
|
||||
);
|
||||
|
||||
} else {
|
||||
return array(
|
||||
"page_no" => $query['page_no'],
|
||||
"per_page" => $query["per_page"],
|
||||
"page_count" => $page_count,
|
||||
"total_results" => $total_users,
|
||||
"per_page_options" => $per_page_options
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return array(
|
||||
"per_page_options" => $per_page_options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the username exists
|
||||
*
|
||||
* @param array $params Contains the user name to check and validate
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function check_username($params) {
|
||||
$this->_admin_include('user.php');
|
||||
$username = $params['user_name'];
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($params['site_id'])) {
|
||||
$blog_id = $params['site_id'];
|
||||
}
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = function_exists('switch_to_blog') ? switch_to_blog($blog_id) : false;
|
||||
|
||||
if (username_exists($username) && is_user_member_of_blog(username_exists($username), $blog_id)) {
|
||||
$result = array("valid" => false, "message" => 'username_exists');
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (!validate_username($username)) {
|
||||
$result = array("valid" => false, "message" => 'username_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
$result = array("valid" => true, "message" => 'username_valid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls blog sites available
|
||||
* for the current WP instance.
|
||||
* If the site is a multisite, then sites under the network
|
||||
* will be pulled, otherwise, it will return an empty array.
|
||||
*
|
||||
* @return Array - an array of sites
|
||||
*/
|
||||
private function _get_blog_sites() {
|
||||
|
||||
if (!is_multisite()) return array();
|
||||
|
||||
// Initialize array container
|
||||
$sites = $network_sites = array();
|
||||
|
||||
// Check to see if latest get_sites (available on WP version >= 4.6) function is
|
||||
// available to pull any available sites from the current WP instance. If not, then
|
||||
// we're going to use the fallback function wp_get_sites (for older version).
|
||||
if (function_exists('get_sites') && class_exists('WP_Site_Query')) {
|
||||
$network_sites = get_sites();
|
||||
} else {
|
||||
if (function_exists('wp_get_sites')) {
|
||||
$network_sites = wp_get_sites();
|
||||
}
|
||||
}
|
||||
|
||||
// We only process if sites array is not empty, otherwise, bypass
|
||||
// the next block.
|
||||
if (!empty($network_sites)) {
|
||||
foreach ($network_sites as $site) {
|
||||
|
||||
// Here we're checking if the site type is an array, because
|
||||
// we're pulling the blog_id property based on the type of
|
||||
// site returned.
|
||||
// get_sites returns an array of object, whereas the wp_get_sites
|
||||
// function returns an array of array.
|
||||
$blog_id = is_array($site) ? $site['blog_id'] : $site->blog_id;
|
||||
|
||||
|
||||
// We're saving the blog_id and blog name as an associative item
|
||||
// into the sites array, that will be used as "Sites" option in
|
||||
// the frontend.
|
||||
$sites[$blog_id] = get_blog_details($blog_id)->blogname;
|
||||
}
|
||||
}
|
||||
|
||||
return $sites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the email exists
|
||||
*
|
||||
* @param array $params Contains the email to check and validate
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function check_email($params) {
|
||||
$this->_admin_include('user.php');
|
||||
$email = $params['email'];
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['site_id']) && 0 !== $params['site_id']) {
|
||||
$blog_id = $params['site_id'];
|
||||
}
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (is_email($email) === false) {
|
||||
$result = array("valid" => false, "message" => 'email_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (email_exists($email) && is_user_member_of_blog(email_exists($email), $blog_id)) {
|
||||
$result = array("valid" => false, "message" => 'email_exists');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
$result = array("valid" => true, "message" => 'email_valid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_users function pull all the users from the database
|
||||
* based on the current search parameters/filters. Please see _search_users
|
||||
* for the breakdown of these parameters.
|
||||
*
|
||||
* @param array $query Parameter array containing the filter and keyword fields
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function get_users($query) {
|
||||
$this->_admin_include('user.php');
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($query['site_id']) && 0 !== $query['site_id']) $blog_id = $query['site_id'];
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
// Set default:
|
||||
if (empty($query["per_page"])) {
|
||||
$query["per_page"] = 10;
|
||||
}
|
||||
if (empty($query['page_no'])) {
|
||||
$query['page_no'] = 1;
|
||||
}
|
||||
if (empty($query["role"])) {
|
||||
$query["role"] = "";
|
||||
}
|
||||
|
||||
$users = array();
|
||||
$total_users = 0;
|
||||
|
||||
if (!empty($query["search"])) {
|
||||
$search_results = $this->_search_users($query);
|
||||
|
||||
if (isset($search_results['users'])) {
|
||||
$users = $search_results['users'];
|
||||
$total_users = $search_results['total_users'];
|
||||
}
|
||||
} else {
|
||||
$user_query = new WP_User_Query(array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'number' => $query["per_page"],
|
||||
'paged'=> $query['page_no'],
|
||||
'role'=> $query["role"]
|
||||
));
|
||||
|
||||
if (empty($user_query->results)) {
|
||||
$result = array("message" => 'users_not_found');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$users = $user_query->results;
|
||||
$total_users = $user_query->get_total();
|
||||
}
|
||||
|
||||
foreach ($users as &$user) {
|
||||
$user_object = get_userdata($user->ID);
|
||||
if (method_exists($user_object, 'to_array')) {
|
||||
$user = $user_object->to_array();
|
||||
$user["roles"] = $user_object->roles;
|
||||
$user["first_name"] = $user_object->first_name;
|
||||
$user["last_name"] = $user_object->last_name;
|
||||
$user["description"] = $user_object->description;
|
||||
} else {
|
||||
$user = $user_object;
|
||||
}
|
||||
}
|
||||
|
||||
$result = array(
|
||||
"users"=>$users,
|
||||
"paging" => $this->_calculate_pages($query, $total_users)
|
||||
);
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new user for the current blog
|
||||
*
|
||||
* @param array $user User information to add
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function add_user($user) {
|
||||
$this->_admin_include('user.php');
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($user['site_id']) && 0 !== $user['site_id']) $blog_id = $user['site_id'];
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!current_user_can('create_users') && !is_super_admin()) {
|
||||
$result = array('error' => true, 'message' => 'user_create_no_permission', 'data' => array('multisite' => is_multisite()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (is_email($user["user_email"]) === false) {
|
||||
$result = array("error" => true, "message" => "email_invalid");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (email_exists($user["user_email"]) && is_user_member_of_blog(email_exists($user["user_email"]), $blog_id)) {
|
||||
$result = array("error" => true, "message" => "email_exists");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (username_exists($user["user_login"]) && is_user_member_of_blog(username_exists($user["user_login"]), $blog_id)) {
|
||||
$result = array("error" => true, "message" => "username_exists");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (!validate_username($user["user_login"])) {
|
||||
$result = array("error" => true, "message" => 'username_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (isset($user['site_id']) && !current_user_can('manage_network_users')) {
|
||||
$result = array("error" => true, "message" => 'user_create_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (email_exists($user["user_email"]) && !is_user_member_of_blog(email_exists($user["user_email"]), $blog_id)) {
|
||||
$user_id = email_exists($user["user_email"]);
|
||||
} else {
|
||||
$user_id = wp_insert_user($user);
|
||||
}
|
||||
$role = $user['role'];
|
||||
if (is_multisite()) {
|
||||
add_existing_user_to_blog(array('user_id' => $user_id, 'role' => $role));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
if ($user_id > 0) {
|
||||
$result = array("error" => false, "message" => "user_created_with_user_name", "values" => array($user['user_login']));
|
||||
return $this->_response($result);
|
||||
} else {
|
||||
$result = array("error" => true, "message" => "user_create_failed", "values" => array($user));
|
||||
}
|
||||
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* [delete_user - UCP: users.delete_user]
|
||||
*
|
||||
* This function is used to check to make sure the user_id is valid and that it has has user delete permissions.
|
||||
* If there are no issues, the user is deleted.
|
||||
*
|
||||
* current_user_can: This check the user permissions from UCP
|
||||
* get_userdata: This get the user data on the data from user_id in the $user_id array
|
||||
* wp_delete_user: Deleting users on the User ID (user_id) and, IF Specified, the Assigner ID (assign_user_id).
|
||||
*
|
||||
* @param [type] $params [description] THis is an Array of params sent over from UpdraftCentral
|
||||
* @return [type] Array [description] This will send back an error array along with message if there are any issues with the user_id
|
||||
*/
|
||||
public function delete_user($params) {
|
||||
$this->_admin_include('user.php');
|
||||
$user_id = $params['user_id'];
|
||||
$assign_user_id = $params["assign_user_id"];
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['site_id']) && 0 !== $params['site_id']) $blog_id = $params['site_id'];
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!current_user_can('delete_users') && !is_super_admin()) {
|
||||
$result = array('error' => true, 'message' => 'user_delete_no_permission', 'data' => array('multisite' => is_multisite()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (get_userdata($user_id) === false) {
|
||||
$result = array("error" => true, "message" => "user_not_found");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (wp_delete_user($user_id, $assign_user_id)) {
|
||||
$result = array("error" => false, "message" => "user_deleted");
|
||||
} else {
|
||||
$result = array("error" => true, "message" => "user_delete_failed");
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits existing user information
|
||||
*
|
||||
* @param array $user User information to save
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function edit_user($user) {
|
||||
$this->_admin_include('user.php');
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($user['site_id']) && 0 !== $user['site_id']) $blog_id = $user['site_id'];
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!current_user_can('edit_users') && !is_super_admin() && get_current_user_id() !== $user["ID"]) {
|
||||
$result = array('error' => true, 'message' => 'user_edit_no_permission', 'data' => array('multisite' => is_multisite()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (false === get_userdata($user["ID"])) {
|
||||
$result = array("error" => true, "message" => "user_not_found");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (get_current_user_id() == $user["ID"]) {
|
||||
unset($user["role"]);
|
||||
}
|
||||
|
||||
/* Validate Username*/
|
||||
if (!validate_username($user["user_login"])) {
|
||||
$result = array("error" => true, "message" => 'username_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
/* Validate Email if not the same*/
|
||||
|
||||
$remote_user = get_userdata($user["ID"]);
|
||||
$old_email = $remote_user->user_email;
|
||||
|
||||
if ($user['user_email'] !== $old_email) {
|
||||
if (is_email($user['user_email']) === false) {
|
||||
$result = array("error" => true, "message" => 'email_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (email_exists($user['user_email'])) {
|
||||
$result = array("error" => true, "message" => 'email_exists');
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$user_id = wp_update_user($user);
|
||||
if (is_wp_error($user_id)) {
|
||||
$result = array("error" => true, "message" => "user_edit_failed_with_error", "values" => array($user_id));
|
||||
} else {
|
||||
$result = array("error" => false, "message" => "user_edited_with_user_name", "values" => array($user["user_login"]));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves available roles to be used as filter options
|
||||
*
|
||||
* @return array An array containing all available roles
|
||||
*/
|
||||
public function get_roles() {
|
||||
$this->_admin_include('user.php');
|
||||
$roles = array_reverse(get_editable_roles());
|
||||
return $this->_response($roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information to be use as filters
|
||||
*
|
||||
* @return array An array containing the filter fields and their data
|
||||
*/
|
||||
public function get_user_filters() {
|
||||
$this->_admin_include('user.php');
|
||||
|
||||
// Pull sites options if available.
|
||||
$sites = $this->_get_blog_sites();
|
||||
|
||||
$result = array(
|
||||
"sites" => $sites,
|
||||
"roles" => array_reverse(get_editable_roles()),
|
||||
"paging" => $this->_calculate_pages(null, 0),
|
||||
);
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('Security check');
|
||||
|
||||
// Translations for UpdraftCentral
|
||||
return array(
|
||||
'updraftcentral_connection' => __('UpdraftCentral Connection', 'updraftplus'),
|
||||
'updraftcentral_connection_successful' => __('An UpdraftCentral connection has been made successfully.', 'updraftplus'),
|
||||
'updraftcentral_connection_failed' => __('A new UpdraftCentral connection has not been made.', 'updraftplus'),
|
||||
'unknown_key' => __('The key referred to was unknown.', 'updraftplus'),
|
||||
'not_logged_in' => __('You are not logged into this WordPress site in your web browser.', 'updraftplus'),
|
||||
'must_visit_url' => __('You must visit this URL in the same browser and login session as you created the key in.', 'updraftplus'),
|
||||
'security_check' => __('Security check.', 'updraftplus'),
|
||||
'must_visit_link' => __('You must visit this link in the same browser and login session as you created the key in.', 'updraftplus'),
|
||||
'connection_already_made' => __('This connection appears to already have been made.', 'updraftplus'),
|
||||
'close' => __('Close', 'updraftplus'),
|
||||
'nothing_yet_logged' => __('(Nothing yet logged)', 'updraftplus'),
|
||||
'invalid_url' => __('An invalid URL was entered', 'updraftplus'),
|
||||
'updraftcentral_key_created' => __('UpdraftCentral key created successfully', 'updraftplus'),
|
||||
'need_to_copy_key' => __('You now need to copy the key below and enter it at your %s.', 'updraftplus'),
|
||||
'press_add_site_button' => __('At your UpdraftCentral dashboard you should press the "Add Site" button then paste the key in the input box.', 'updraftplus'),
|
||||
'detailed_instructions' => __('Detailed instructions for this can be found at %s', 'updraftplus'),
|
||||
'control_this_site' => __('You can now control this site via your UpdraftCentral dashboard at %s.', 'updraftplus'),
|
||||
'attempt_to_register_failed' => __('A key was created, but the attempt to register it with %1$s was unsuccessful.', 'updraftplus').' '.__('You can try again, or try using the alternative connection method if the problem persists.', 'updraftplus').' '.__('For more information visit %2$s', 'updraftplus'),
|
||||
'key_created_successfully' => __('Key created successfully.', 'updraftplus'),
|
||||
'copy_paste_key' => __('You must copy and paste this key now - it cannot be shown again.', 'updraftplus'),
|
||||
'no_updraftcentral_dashboards' => __('There are no UpdraftCentral dashboards that can currently control this site.', 'updraftplus'),
|
||||
'unknown' => __('Unknown', 'updraftplus'),
|
||||
'access_as_user' => __('Access this site as user:', 'updraftplus'),
|
||||
'public_key_sent' => __('Public key was sent to:', 'updraftplus'),
|
||||
'created' => __('Created:', 'updraftplus'),
|
||||
'key_size' => __('Key size: %d bits', 'updraftplus'),
|
||||
'delete' => __('Delete...', 'updraftplus'),
|
||||
'manage_keys' => __('Manage existing keys (%d)...', 'updraftplus'),
|
||||
'key_description' => __('Key description', 'updraftplus'),
|
||||
'details' => __('Details', 'updraftplus'),
|
||||
'connect_to_updraftcentral_dashboard' => __('Connect this site to an UpdraftCentral dashboard found at...', 'updraftplus'),
|
||||
'in_example' => __('i.e. if you have %s there', 'updraftplus'),
|
||||
'an_account' => __('an account', 'updraftplus'),
|
||||
'self_hosted_dashboard' => __('Self-hosted dashboard', 'updraftplus'),
|
||||
'website_installed' => __('A website where you have installed %s', 'updraftplus'),
|
||||
'enter_url' => __('Enter the URL where your self-hosted install of UpdraftCentral is located:', 'updraftplus'),
|
||||
'updraftcentral_dashboard_url' => __('URL for the site of your UpdraftCentral dashboard', 'updraftplus'),
|
||||
'next' => __('Next', 'updraftplus'),
|
||||
'updraftcentral_connection_details' => __('UpdraftCentral dashboard connection details', 'updraftplus'),
|
||||
'description' => __('Description', 'updraftplus'),
|
||||
'enter_description' => __('Enter any description', 'updraftplus'),
|
||||
'encryption_key_size' => __('Encryption key size:', 'updraftplus'),
|
||||
'bits' => __('%s bits', 'updraftplus'),
|
||||
'bytes' => __('%s bytes', 'updraftplus'),
|
||||
'easy_to_break' => __('easy to break, fastest', 'updraftplus'),
|
||||
'faster' => __('faster (possibility for slow PHP installs)', 'updraftplus'),
|
||||
'recommended' => __('recommended', 'updraftplus'),
|
||||
'slower' => __('slower, strongest', 'updraftplus'),
|
||||
'use_alternative_method' => __('Use the alternative method for making a connection with the dashboard.', 'updraftplus'),
|
||||
'more_information' => __('More information...', 'updraftplus'),
|
||||
'this_is_useful' => __('This is useful if the dashboard webserver cannot be contacted with incoming traffic by this website (for example, this is the case if this website is hosted on the public Internet, but the UpdraftCentral dashboard is on localhost, or on an Intranet, or if this website has an outgoing firewall), or if the dashboard website does not have a SSL certificate.', 'updraftplus'),
|
||||
'create' => __('Create', 'updraftplus'),
|
||||
'back' => __('Back...', 'updraftplus'),
|
||||
'view_log_events' => __('View recent UpdraftCentral log events', 'updraftplus'),
|
||||
'updraftcentral_remote_control' => __('UpdraftCentral (Remote Control)', 'updraftplus'),
|
||||
'updraftcentral_description' => __('UpdraftCentral enables control of your WordPress sites %s from a central dashboard.', 'updraftplus'),
|
||||
'including_description' => array(
|
||||
'wp_optimize_desc' => __('(including management of WP-Optimize)', 'updraftplus'),
|
||||
'updraftplus_desc' => __('(including management of backups and updates)', 'updraftplus'),
|
||||
),
|
||||
'read_more' => __('Read more about it here.', 'updraftplus'),
|
||||
'create_another_key' => __('Create another key', 'updraftplus'),
|
||||
'unable_to_connect' => __('Unable to connect to the filesystem', 'updraftplus'),
|
||||
'unable_to_activate' => __('Unable to activate %s successfully.', 'updraftplus').' '.__('Make sure that this %s is compatible with your remote WordPress version.', 'updraftplus').' '.__('WordPress version currently installed in your remote website is %s.', 'updraftplus'),
|
||||
'unable_to_install' => __('Unable to install %s.', 'updraftplus').' '.__('Make sure you upload the correct file and that the zip file is a valid %s file (not corrupted) and try uploading the file again.', 'updraftplus'),
|
||||
'failed_to_attach_media' => __('Failed to attach media.', 'updraftplus'),
|
||||
'media_attached' => __('Media has been attached to post.', 'updraftplus'),
|
||||
'failed_to_detach_media' => __('Failed to detach media.', 'updraftplus'),
|
||||
'media_detached' => __('Media has been detached from post.', 'updraftplus'),
|
||||
'failed_to_delete_media' => __('Failed to delete selected media.', 'updraftplus'),
|
||||
'selected_media_deleted' => __('Selected media has been deleted successfully.', 'updraftplus'),
|
||||
'unattached' => __('Unattached', 'updraftplus'),
|
||||
'default_template' => __('Default template', 'updraftplus'),
|
||||
'parameters_missing' => __('Expected parameter(s) missing.', 'updraftplus'),
|
||||
'fetching' => __('Fetching...', 'updraftplus'),
|
||||
'deleting' => __('Deleting...', 'updraftplus'),
|
||||
'enter_mothership_url' => __('Please enter a valid URL', 'updraftplus'),
|
||||
'creating_please_allow' => __('Creating...', 'updraftplus').(function_exists('openssl_encrypt') ? '' : ' ('.__('your PHP install lacks the openssl module; as a result, this can take minutes; if nothing has happened by then, then you should either try a smaller key size, or ask your web hosting company how to enable this PHP module on your setup.', 'updraftplus').')'),
|
||||
'unexpectedresponse' => __('Unexpected response:', 'updraftplus'),
|
||||
'updraftcentral_wizard_empty_url' => __('Please enter the URL where your UpdraftCentral dashboard is hosted.', 'updraftplus'),
|
||||
'updraftcentral_wizard_invalid_url' => __('Please enter a valid URL e.g http://example.com', 'updraftplus'),
|
||||
'insufficient_privilege' => __('Sorry, you do not have enough privilege to execute the requested action.', 'updraftplus'),
|
||||
'copy_to_clipboard' => __('Copy to clipboard', 'updraftplus'),
|
||||
'key_copied' => __('The key was copied to the clipboard.', 'updraftplus'),
|
||||
'unable_to_copy' => __('The attempt to copy to the clipboard failed.', 'updraftplus'),
|
||||
'wpo_not_active' => __('WP_Optimize is not installed or active.', 'updraftplus'),
|
||||
'log_file_not_exist' => __('Log file does not exist or could not be read.', 'updraftplus'),
|
||||
'security_check_failed' => __('Security check failed; try refreshing the page.', 'updraftplus').' '.__('If refreshing the page does not help then perhaps you do not have sufficient privilege to manage WP-Optimize.', 'updraftplus'),
|
||||
'no_such_command' => __('No such command found.', 'updraftplus'),
|
||||
'command_not_allowed' => __('You are not allowed to run this command.', 'updraftplus'),
|
||||
'command_not_found' => __('The command is either not found or not allowed.', 'updraftplus'),
|
||||
'network_admin_only' => __('The command can only be executed by a network admin.', 'updraftplus'),
|
||||
);
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
if (class_exists('UpdraftPlus_Host')) return;
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) define('UPDRAFTCENTRAL_CLIENT_DIR', dirname(__FILE__));
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_URL')) define('UPDRAFTCENTRAL_CLIENT_URL', plugins_url('', __FILE__));
|
||||
if (!class_exists('UpdraftCentral_Host')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/host.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is the basic bridge between UpdraftCentral and UpdraftPlus.
|
||||
*/
|
||||
class UpdraftPlus_Host extends UpdraftCentral_Host {
|
||||
|
||||
public $plugin_name = 'updraftplus';
|
||||
|
||||
public $translations = array();
|
||||
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this class. Singleton Pattern
|
||||
*
|
||||
* @return object Instance of this class
|
||||
*/
|
||||
public static function instance() {
|
||||
if (empty(self::$_instance)) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action('updraftplus_debugtools_dashboard', array($this, 'debugtools_dashboard'), 20);
|
||||
add_action('updraftplus_load_translations_for_udcentral', array($this, 'load_updraftplus_translations'));
|
||||
|
||||
$this->maybe_initialize_required_objects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the UpdraftCentral_Main instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_updraftcentral() {
|
||||
$central_path = $this->is_host_dir_set() ? trailingslashit(UPDRAFTPLUS_DIR) : '';
|
||||
|
||||
if (file_exists($central_path.'central/bootstrap.php')) {
|
||||
include_once($central_path.'central/bootstrap.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can perform key control AJAX actions
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function current_user_can_ajax() {
|
||||
return UpdraftPlus_Options::user_can_manage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Below are interface methods' implementations that are required by UpdraftCentral to function properly. Please
|
||||
* see the "interface.php" to check all the required interface methods.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks whether the plugin's DIR constant is currently define or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_host_dir_set() {
|
||||
return defined('UPDRAFTPLUS_DIR') ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host plugin's dir path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_host_dir() {
|
||||
return defined('UPDRAFTPLUS_DIR') ? UPDRAFTPLUS_DIR : dirname(dirname(__FILE__));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the filter used by UpdraftPlus to log errors or certain events
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_logline_filter() {
|
||||
return 'updraftplus_logline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether debug mod is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_debug_mode() {
|
||||
if (class_exists('UpdraftPlus_Options')) {
|
||||
return UpdraftPlus_Options::get_updraft_option('updraft_debug_mode');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as a central location (to avoid repetition) to register or de-register hooks into the WP HTTP API
|
||||
*
|
||||
* @param bool $register True to register, false to de-register
|
||||
* @return void
|
||||
*/
|
||||
public function register_wp_http_option_hooks($register = true) {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
$updraftplus->register_wp_http_option_hooks($register);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the class name of the host plugin
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_class_name() {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
return get_class($updraftplus);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the host plugin
|
||||
*
|
||||
* @return object|bool
|
||||
*/
|
||||
public function get_instance() {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
return $updraftplus;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the admin instance of the host plugin
|
||||
*
|
||||
* @return object|bool
|
||||
*/
|
||||
public function get_admin_instance() {
|
||||
global $updraftplus_admin;
|
||||
|
||||
if ($updraftplus_admin) {
|
||||
return $updraftplus_admin;
|
||||
} else {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/admin.php')) {
|
||||
updraft_try_include_file('admin.php', 'include_once');
|
||||
$updraftplus_admin = new UpdraftPlus_Admin();
|
||||
return $updraftplus_admin;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given line
|
||||
*
|
||||
* @param string $line The log line
|
||||
* @param string $level The log level: notice, warning, error, etc.
|
||||
* @param boolean|string $uniq_id Each of these will only be logged once
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log($line, $level = 'notice', $uniq_id = false) {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
if (is_callable(array($updraftplus, 'log'))) {
|
||||
call_user_func(array($updraftplus, 'log'), $line, $level, $uniq_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of the host plugin
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_version() {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
return $updraftplus->version;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filesystem class of the host's plugin
|
||||
*
|
||||
* @return class|bool
|
||||
*/
|
||||
public function get_filesystem_functions() {
|
||||
if ($this->has_filesystem_functions()) {
|
||||
return UpdraftPlus_Filesystem_Functions;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the filesystem class of the host plugin exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_filesystem_functions() {
|
||||
return class_exists('UpdraftPlus_Filesystem_Functions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether force debugging is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_force_debug() {
|
||||
return (defined('UPDRAFTPLUS_UDRPC_FORCE_DEBUG') && UPDRAFTPLUS_UDRPC_FORCE_DEBUG) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes required objects (if not yet initialized) for UpdraftCentral usage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_initialize_required_objects() {
|
||||
global $updraftplus;
|
||||
|
||||
if (!class_exists('UpdraftPlus')) {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/class-updraftplus.php')) {
|
||||
updraft_try_include_file('class-updraftplus.php', 'include_once');
|
||||
if (empty($updraftplus) || !is_a($updraftplus, 'UpdraftPlus')) {
|
||||
$updraftplus = new UpdraftPlus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists('UpdraftPlus_Options')) {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/options.php')) {
|
||||
updraft_try_include_file('options.php', 'require_once');
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists('UpdraftPlus_Filesystem_Functions')) {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/includes/class-filesystem-functions.php')) {
|
||||
updraft_try_include_file('includes/class-filesystem-functions.php', 'require_once');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations which are based on UpdraftPlus domain text
|
||||
*/
|
||||
public function load_updraftplus_translations() {
|
||||
// Load updraftplus translations
|
||||
if (defined('UPDRAFTCENTRAL_CLIENT_DIR') && file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php')) {
|
||||
$this->translations = include(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
if (class_exists('WP_Optimize_Host')) return;
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) define('UPDRAFTCENTRAL_CLIENT_DIR', dirname(__FILE__));
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_URL')) define('UPDRAFTCENTRAL_CLIENT_URL', plugins_url('', __FILE__));
|
||||
if (!class_exists('UpdraftCentral_Host')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/host.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is the basic bridge between UpdraftCentral and WP_Optimize.
|
||||
*/
|
||||
class WP_Optimize_Host extends UpdraftCentral_Host {
|
||||
|
||||
public $plugin_name = 'wp-optimize';
|
||||
|
||||
public $translations = array();
|
||||
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this class. Singleton Pattern
|
||||
*
|
||||
* @return object Instance of this class
|
||||
*/
|
||||
public static function instance() {
|
||||
if (empty(self::$_instance)) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
add_action('updraftplus_load_translations_for_udcentral', array($this, 'load_updraftplus_translations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can perform key control AJAX actions
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function current_user_can_ajax() {
|
||||
return current_user_can(WP_Optimize()->capability_required());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the UpdraftCentral_Main instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_updraftcentral() {
|
||||
$central_path = $this->is_host_dir_set() ? trailingslashit(WPO_PLUGIN_MAIN_PATH) : '';
|
||||
|
||||
if (!empty($central_path) && file_exists($central_path.'central/bootstrap.php')) {
|
||||
include_once($central_path.'central/bootstrap.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the plugin's DIR constant is currently define or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_host_dir_set() {
|
||||
return defined('WPO_PLUGIN_MAIN_PATH') ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host plugin's dir path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_host_dir() {
|
||||
return defined('WPO_PLUGIN_MAIN_PATH') ? WPO_PLUGIN_MAIN_PATH : dirname(dirname(__FILE__));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of the host plugin
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_version() {
|
||||
return defined('WPO_VERSION') ? WPO_VERSION : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the host plugin
|
||||
*
|
||||
* @return object|bool
|
||||
*/
|
||||
public function get_instance() {
|
||||
global $wp_optimize;
|
||||
|
||||
if ($wp_optimize) {
|
||||
return $wp_optimize;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether debug mod is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_debug_mode() {
|
||||
return (defined('WP_OPTIMIZE_DEBUG_OPTIMIZATIONS') && WP_OPTIMIZE_DEBUG_OPTIMIZATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given line
|
||||
*
|
||||
* @param string $line The log line
|
||||
* @param string $level The log level: notice, warning, error, etc.
|
||||
* @param boolean|string $uniq_id Each of these will only be logged once
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log($line, $level = 'notice', $uniq_id = false) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the the abstract UpdraftCentral_Host class uses 3 arguments.
|
||||
global $wp_optimize;
|
||||
|
||||
if ($wp_optimize) {
|
||||
if (is_callable(array($wp_optimize, 'log'))) {
|
||||
call_user_func(array($wp_optimize, 'log'), $line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations which are based on UpdraftPlus domain text
|
||||
*/
|
||||
public function load_updraftplus_translations() {
|
||||
// Load wp-optimize translations
|
||||
if (defined('UPDRAFTCENTRAL_CLIENT_DIR') && file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php')) {
|
||||
$this->translations = include(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Developer Note:
|
||||
*
|
||||
* You can add your class methods below if ever you want to extend or modify
|
||||
* the module handlers of UpdraftCentral located at central/modules. Just be
|
||||
* sure to use this class to abstract any functionality that would link to the
|
||||
* wp-optimize plugin.
|
||||
*
|
||||
* N.B. All custom methods added here will then be available from the global
|
||||
* variable $updraftcentral_host_plugin (e.g. $updraftcentral_host_plugin->YOUR_METHOD)
|
||||
*/
|
||||
}
|
||||
Reference in New Issue
Block a user