first commit
This commit is contained in:
440
wp-content/plugins/updraftplus/central/modules/analytics.php
Normal file
440
wp-content/plugins/updraftplus/central/modules/analytics.php
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
391
wp-content/plugins/updraftplus/central/modules/backups.php
Normal file
391
wp-content/plugins/updraftplus/central/modules/backups.php
Normal file
@@ -0,0 +1,391 @@
|
||||
<?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']);
|
||||
$response['last_backup']['backup_time'] = $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);
|
||||
|
||||
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_central_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'];
|
||||
$response['progress']['backup_time'] = $last_backup['backup_time'];
|
||||
$response['progress']['completed_time'] = gmdate('g:ia', $last_backup['backup_time']);
|
||||
$response['progress']['completed_date'] = gmdate('M d, Y', $last_backup['backup_time']);
|
||||
|
||||
$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 (if applicable).
|
||||
$last_progress = UpdraftPlus_Options::get_updraft_option('updraft_central_last_backup_progress');
|
||||
|
||||
$response['status'] = 'in-progress';
|
||||
if (!empty($last_progress) && isset($last_progress['nonce'])) {
|
||||
$response['progress'] = $last_progress;
|
||||
|
||||
if ($nonce == $last_progress['nonce']) {
|
||||
UpdraftPlus_Options::delete_updraft_option('updraft_central_last_backup_progress');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
}
|
||||
842
wp-content/plugins/updraftplus/central/modules/comments.php
Normal file
842
wp-content/plugins/updraftplus/central/modules/comments.php
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
653
wp-content/plugins/updraftplus/central/modules/core.php
Normal file
653
wp-content/plugins/updraftplus/central/modules/core.php
Normal file
@@ -0,0 +1,653 @@
|
||||
<?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');
|
||||
}
|
||||
|
||||
if (!class_exists('UpdraftCentral_Media_Commands') && defined('UPDRAFTCENTRAL_CLIENT_DIR')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/modules/media.php');
|
||||
}
|
||||
|
||||
$media = new UpdraftCentral_Media_Commands($this);
|
||||
$icon_details = array();
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$site_icon_id = (int) get_option('site_icon');
|
||||
if ($site_icon_id) $icon_details = $media->get_media_item(array('id' => $site_icon_id), null, true);
|
||||
}
|
||||
|
||||
// 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, 'icon_details' => $icon_details));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles site icon upload
|
||||
*
|
||||
* @param Array $query An array containing the image data.
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function handle_site_icon_upload($query) {
|
||||
if (!current_user_can('upload_files')) {
|
||||
return $this->_generic_error_response('insufficient_permission', array('error_message' => __('You do not have the necessary permissions to upload files.', 'updraftcentral')));
|
||||
}
|
||||
|
||||
$data_uri = sanitize_text_field($query['data_uri']);
|
||||
$filename = sanitize_text_field(basename($query['filename']));
|
||||
$file_ext = pathinfo($filename, PATHINFO_EXTENSION);
|
||||
$history = sanitize_text_field($query['history']);
|
||||
$preview = sanitize_text_field($query['preview']);
|
||||
$pattern = '/^data:(image\/[^;]+);base64,([A-Za-z0-9+\/=]+)$/i';
|
||||
|
||||
if (!empty($data_uri) && preg_match($pattern, $data_uri, $matches)) {
|
||||
list(, $data) = explode(';', $data_uri);
|
||||
list(, $data) = explode(',', $data);
|
||||
|
||||
$decoded_data = base64_decode($data);
|
||||
if (!class_exists('wp_tempnam')) include_once(ABSPATH.'/wp-admin/includes/file.php');
|
||||
$temp_img_file = wp_tempnam();
|
||||
@file_put_contents($temp_img_file, $decoded_data); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the call.
|
||||
$mime_type = wp_get_image_mime($temp_img_file);
|
||||
@unlink($temp_img_file); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist.
|
||||
$allowed_ext = array('jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif', 'webp', 'avif', 'heic');
|
||||
if (false !== $mime_type && !empty($matches[1]) && strtolower($mime_type) === strtolower($matches[1]) && !empty($file_ext) && in_array(strtolower($file_ext), $allowed_ext)) {
|
||||
$upload = wp_upload_bits($filename, null, $decoded_data);
|
||||
} else {
|
||||
$upload = array('error' => __("Couldn't verify the actual MIME type of the given site icon image data.", 'updraftcentral'));
|
||||
}
|
||||
|
||||
if (!$upload['error']) {
|
||||
$attachment = array(
|
||||
'guid' => $upload['url'],
|
||||
'post_mime_type' => $upload['type'],
|
||||
'post_title' => sanitize_file_name($filename),
|
||||
'post_content' => '',
|
||||
'post_status' => 'inherit',
|
||||
);
|
||||
|
||||
$attach_id = wp_insert_attachment($attachment, $upload['file']);
|
||||
|
||||
if (!function_exists('wp_generate_attachment_metadata')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
// Generate metadata and thumbnails
|
||||
$attach_data = wp_generate_attachment_metadata($attach_id, $upload['file']);
|
||||
wp_update_attachment_metadata($attach_id, $attach_data);
|
||||
|
||||
if (update_option('site_icon', $attach_id)) {
|
||||
if (1 == intval($preview)) {
|
||||
if (!class_exists('UpdraftCentral_Media_Commands') && defined('UPDRAFTCENTRAL_CLIENT_DIR')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/modules/media.php');
|
||||
}
|
||||
|
||||
$media = new UpdraftCentral_Media_Commands($this);
|
||||
$icon_details = $media->get_media_item(array('id' => $attach_id), null, true);
|
||||
|
||||
$params = array(
|
||||
'_ajax_nonce' => $icon_details->nonce,
|
||||
'postid' => $attach_id,
|
||||
'history' => $history,
|
||||
'rand' => $icon_details->misc['rand'],
|
||||
);
|
||||
|
||||
$result = $media->image_preview($params);
|
||||
$result['data']['icon_details'] = $icon_details;
|
||||
|
||||
return $result;
|
||||
} else {
|
||||
return $this->get_site_icon();
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('upload_error', array('error_message' => __('Unable to set uploaded file as site icon.', 'updraftcentral')));
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('upload_error', array('error_message' => $upload['error']));
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('data_uri_field_empty_or_invalid', array('error_message' => __('Required data URI is either missing or invalid.', 'updraftcentral')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function get_blog_sites() {
|
||||
|
||||
if (!is_multisite()) {
|
||||
return $this->_generic_error_response('not_multisite');
|
||||
}
|
||||
|
||||
$sites = array();
|
||||
$network_sites = array();
|
||||
|
||||
// Use `get_sites` for WP version >= 4.6 else use old `wp_get_sites`.
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($network_sites)) {
|
||||
foreach ($network_sites as $site) {
|
||||
|
||||
// Check if the site type is an array,
|
||||
// because `wp_get_sites` returns site data as associative array while,
|
||||
// `get_sites` returns the data as WP_Site object.
|
||||
$blog_id = is_array($site) ? $site['blog_id'] : $site->blog_id;
|
||||
|
||||
$sites[] = array(
|
||||
'site_id' => $blog_id,
|
||||
'name' => get_blog_details($blog_id)->blogname,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response(array(
|
||||
'sites' => $sites,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) || is_a($instance, 'UpdraftCentral_UpdraftPlus_Commands') || is_a($instance, 'UpdraftCentral_WP_Optimize_Commands')) {
|
||||
$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;
|
||||
}
|
||||
}
|
||||
601
wp-content/plugins/updraftplus/central/modules/media.php
Normal file
601
wp-content/plugins/updraftplus/central/modules/media.php
Normal file
@@ -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)));
|
||||
}
|
||||
}
|
||||
15
wp-content/plugins/updraftplus/central/modules/pages.php
Normal file
15
wp-content/plugins/updraftplus/central/modules/pages.php
Normal file
@@ -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';
|
||||
}
|
||||
700
wp-content/plugins/updraftplus/central/modules/plugin.php
Normal file
700
wp-content/plugins/updraftplus/central/modules/plugin.php
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
2038
wp-content/plugins/updraftplus/central/modules/posts.php
Normal file
2038
wp-content/plugins/updraftplus/central/modules/posts.php
Normal file
File diff suppressed because it is too large
Load Diff
391
wp-content/plugins/updraftplus/central/modules/reporting.php
Normal file
391
wp-content/plugins/updraftplus/central/modules/reporting.php
Normal file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* - A container for RPC commands (white label reporting 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_Reporting_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $valid_statuses = array(
|
||||
'recurring',
|
||||
'manual',
|
||||
);
|
||||
|
||||
private $max_number_of_recipients = 100;
|
||||
|
||||
/**
|
||||
* Update existing reports.
|
||||
*
|
||||
* @param array $reports Reports data which will be saved.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _update_existing_reports($reports) {
|
||||
update_option('updraftcentral_reporting_reports', $reports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize email address - lowercase and sanitize.
|
||||
*
|
||||
* @param string $email Email address to normalize.
|
||||
*
|
||||
* @return string Normalized email.
|
||||
*/
|
||||
private function _normalize_email($email) {
|
||||
return strtolower(sanitize_email($email));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing reports.
|
||||
*
|
||||
* @return array List of all reports.
|
||||
*/
|
||||
private function _get_existing_reports() {
|
||||
return (array) get_option('updraftcentral_reporting_reports', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update existing sent reports.
|
||||
*
|
||||
* @param array $sent_reports Sent reports data which will be saved.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function _update_existing_sent_reports($sent_reports) {
|
||||
update_option('updraftcentral_reporting_sent_reports', $sent_reports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing sent reports.
|
||||
*
|
||||
* @return array List of all sent reports.
|
||||
*/
|
||||
private function _get_existing_sent_reports() {
|
||||
return (array) get_option('updraftcentral_reporting_sent_reports', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the reports (scheduled or not scheduled).
|
||||
*
|
||||
* @param array $data Data array containing report IDs to fetch.
|
||||
*
|
||||
* @return array An array of reports.
|
||||
*/
|
||||
public function get_reports($data) {
|
||||
$all_reports = $this->_get_existing_reports();
|
||||
|
||||
$sent_reports = array_reverse($this->_get_existing_sent_reports());
|
||||
|
||||
foreach ($sent_reports as $key => $sent_report) {
|
||||
$sent_report['download_url'] = '';
|
||||
|
||||
if (!empty($sent_report['pdf_attachment_id'])) {
|
||||
$sent_report['download_url'] = wp_get_attachment_url(absint($sent_report['pdf_attachment_id']));
|
||||
}
|
||||
|
||||
$sent_reports[$key] = $sent_report;
|
||||
}
|
||||
|
||||
if (empty($data['report_ids']) || !is_array($data['report_ids'])) {
|
||||
return $this->_response(array(
|
||||
'reports' => $all_reports,
|
||||
'sent_reports' => $sent_reports,
|
||||
));
|
||||
}
|
||||
|
||||
$report_ids = array();
|
||||
|
||||
foreach ($data['report_ids'] as $report_id) {
|
||||
$report_ids[] = sanitize_key(strval($report_id));
|
||||
}
|
||||
|
||||
return $this->_response((array(
|
||||
'reports' => array_intersect_key($all_reports, array_flip($report_ids)),
|
||||
'sent_reports' => $sent_reports,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a report.
|
||||
*
|
||||
* @param array $data Data array containing report ID to delete.
|
||||
*
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function delete_report($data) {
|
||||
// Permission check.
|
||||
if (!current_user_can('manage_options')) {
|
||||
$result = array("error" => true, "message" => "not_allowed");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Return early if valid data structure is not present.
|
||||
if (!is_array($data)) {
|
||||
$result = array("error" => true, "message" => "invalid_data");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$report_id = empty($data['id']) ? '' : sanitize_key(strval($data['id']));
|
||||
|
||||
// Return early if ID not supplied.
|
||||
if (empty($report_id)) {
|
||||
$result = array('error' => true, 'message' => 'missing_id');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Get the reports from options table.
|
||||
$reports = $this->_get_existing_reports();
|
||||
|
||||
// Check if the ID to delete is present.
|
||||
if (!isset($reports[$report_id])) {
|
||||
$result = array('error' => true, 'message' => 'invalid_id');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
unset($reports[$report_id]);
|
||||
|
||||
$this->_update_existing_reports($reports);
|
||||
|
||||
$result = array("error" => false, "message" => "reports_updated");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new report.
|
||||
*
|
||||
* @param array $data Report information to add
|
||||
*
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function add_report($data) {
|
||||
// Permission check.
|
||||
if (!current_user_can('manage_options')) {
|
||||
$result = array("error" => true, "message" => "not_allowed");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Return early if valid report structure is not present.
|
||||
if (!is_array($data)) {
|
||||
$result = array("error" => true, "message" => "invalid_report_data");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$report_name = isset($data['name']) ? sanitize_text_field(strval($data['name'])) : '';
|
||||
|
||||
if ('' === $report_name) {
|
||||
$result = array("error" => true, "message" => "empty_name");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$report_status = empty($data['status']) ? '' : sanitize_text_field(strval($data['status']));
|
||||
|
||||
if (!in_array($report_status, $this->valid_statuses)) {
|
||||
$result = array("error" => true, "message" => "status_invalid");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$template_id = empty($data['template_id']) ? '' : sanitize_key($data['template_id']);
|
||||
|
||||
if (empty($template_id)) {
|
||||
$result = array("error" => true, "message" => "template_id_invalid");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$recipients = (isset($data['recipients']) && is_array($data['recipients'])) ? $data['recipients'] : array();
|
||||
|
||||
if (count($recipients) > $this->max_number_of_recipients) {
|
||||
$result = array("error" => true, "message" => "max_number_of_recipients_exceeded");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$recipients = array_unique(array_map(array($this, '_normalize_email'), $recipients));
|
||||
|
||||
// Sanity check for invalid email.
|
||||
foreach ($recipients as $email) {
|
||||
if (!is_email($email)) {
|
||||
$result = array(
|
||||
"error" => true,
|
||||
"message" => "recipients_invalid",
|
||||
"values" => array(
|
||||
'invalid_email' => $email,
|
||||
)
|
||||
);
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($recipients)) {
|
||||
$result = array("error" => true, "message" => "no_recipients_provided");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Get existing reports from options table.
|
||||
$existing_reports = $this->_get_existing_reports();
|
||||
|
||||
// Report.
|
||||
$report = array();
|
||||
|
||||
$report_id = empty($data['id']) ? '' : sanitize_key(strval($data['id']));
|
||||
|
||||
if (empty($report_id)) {
|
||||
// First report timestamp and formatted date.
|
||||
$next_report_timestamp = strtotime("+1 month", time());
|
||||
$next_report_formatted_date = date("j M, g:i a", $next_report_timestamp);
|
||||
|
||||
$report_id = UpdraftPlus_Manipulation_Functions::generate_random_string(10);
|
||||
|
||||
$report_id_generation_loops = 0;
|
||||
|
||||
// Sanity check to check if the report ID exists.
|
||||
while (isset($existing_reports[$report_id])) {
|
||||
$report_id = UpdraftPlus_Manipulation_Functions::generate_random_string(10);
|
||||
++$report_id_generation_loops;
|
||||
|
||||
// If we somehow exceed the max generation loops then return error - which will not happen in almost any case.
|
||||
if ($report_id_generation_loops > 10) {
|
||||
$result = array("error" => true, "message" => "report_id_generation_failed");
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
|
||||
$report = array(
|
||||
'id' => $report_id,
|
||||
'name' => $report_name,
|
||||
'status' => $report_status,
|
||||
'template_id' => $template_id,
|
||||
'recipients' => $recipients,
|
||||
'last_report_timestamp' => 0,
|
||||
'last_report_formatted_date' => __('N/A', 'updraftplus'),
|
||||
'next_report_timestamp' => $next_report_timestamp,
|
||||
'next_report_formatted_date' => $next_report_formatted_date,
|
||||
);
|
||||
} elseif (!empty($existing_reports[$report_id])) {
|
||||
$report = $existing_reports[$report_id];
|
||||
|
||||
$report['name'] = $report_name;
|
||||
$report['status'] = $report_status;
|
||||
$report['template_id'] = $template_id;
|
||||
$report['recipients'] = $recipients;
|
||||
} else {
|
||||
$result = array("error" => true, "message" => "report_does_not_exist");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Add the new report.
|
||||
$existing_reports[$report_id] = $report;
|
||||
|
||||
// Update the reports.
|
||||
$this->_update_existing_reports($existing_reports);
|
||||
|
||||
$result = array(
|
||||
"error" => false,
|
||||
"message" => "reports_updated",
|
||||
"values" => array(
|
||||
'report' => $report,
|
||||
)
|
||||
);
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sent report.
|
||||
*
|
||||
* @param array $data Report information to add
|
||||
*
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function add_sent_reports($data) {
|
||||
// Permission check.
|
||||
if (!current_user_can('manage_options')) {
|
||||
$result = array("error" => true, "message" => "not_allowed");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Return early if valid report structure is not present.
|
||||
if (!is_array($data) || empty($data['sent_reports_data'])) {
|
||||
$result = array("error" => true, "message" => "invalid_sent_report_data");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$reports = $this->_get_existing_reports();
|
||||
$sent_reports = $this->_get_existing_sent_reports();
|
||||
|
||||
$return_data = array();
|
||||
|
||||
// Loop through all the sent reports.
|
||||
foreach ($data['sent_reports_data'] as $report_data) {
|
||||
$report_id = sanitize_key(strval($report_data['report_id']));
|
||||
|
||||
// Skip if no report of this ID exists.
|
||||
if (empty($reports[$report_id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$report_sent_at_timestamp = time();
|
||||
$report_sent_at_formatted_date = date("j M, g:i a", $report_sent_at_timestamp);
|
||||
|
||||
// Change the last report time of the report.
|
||||
$reports[$report_id]['last_report_timestamp'] = $report_sent_at_timestamp;
|
||||
$reports[$report_id]['last_report_formatted_date'] = $report_sent_at_formatted_date;
|
||||
|
||||
// Save the PDF as attachment.
|
||||
$pdf_attachment_id = 0;
|
||||
$uploads_dir = wp_upload_dir();
|
||||
$custom_upload_directory = trailingslashit($uploads_dir['basedir']) . 'updraftcentral-white-label-reporting-pdfs/';
|
||||
$custom_upload_url = trailingslashit($uploads_dir['baseurl']) . 'updraftcentral-white-label-reporting-pdfs/';
|
||||
$filename = sanitize_text_field($reports[$report_id]['name']) . '-' . $report_sent_at_timestamp . '-' . UpdraftPlus_Manipulation_Functions::generate_random_string(5) . '.pdf';
|
||||
$full_path = $custom_upload_directory . basename($filename);
|
||||
|
||||
// Sanity check to test directory exists.
|
||||
wp_mkdir_p(dirname($full_path));
|
||||
|
||||
file_put_contents($full_path, base64_decode($report_data['pdf_content']));
|
||||
|
||||
$wp_filetype = wp_check_filetype($filename, null);
|
||||
$attachment = array(
|
||||
'guid' => $custom_upload_url . basename($filename),
|
||||
'post_mime_type' => $wp_filetype['type'],
|
||||
'post_title' => sanitize_file_name(pathinfo($filename, PATHINFO_FILENAME)),
|
||||
'post_content' => '',
|
||||
'post_status' => 'inherit',
|
||||
);
|
||||
|
||||
$pdf_attachment_id = wp_insert_attachment($attachment, $full_path);
|
||||
|
||||
require_once(ABSPATH . 'wp-admin/includes/image.php');
|
||||
|
||||
$attach_data = wp_generate_attachment_metadata($pdf_attachment_id, $full_path);
|
||||
wp_update_attachment_metadata($pdf_attachment_id, $attach_data);
|
||||
|
||||
$new_sent_report = array(
|
||||
'report' => $reports[$report_id]['name'],
|
||||
'sent' => (bool) $report_data['sent'],
|
||||
'template_id_used' => sanitize_key($report_data['template_id']),
|
||||
'template_name_used' => sanitize_text_field($report_data['template_name']),
|
||||
'services' => array_map('sanitize_text_field', $report_data['services']),
|
||||
'sent_at' => $report_sent_at_formatted_date,
|
||||
'number_of_recipients' => absint($report_data['number_of_recipients']),
|
||||
'pdf_attachment_id' => $pdf_attachment_id,
|
||||
);
|
||||
|
||||
$sent_reports[] = $new_sent_report;
|
||||
$return_data[] = $new_sent_report;
|
||||
}
|
||||
|
||||
$this->_update_existing_reports($reports);
|
||||
$this->_update_existing_sent_reports($sent_reports);
|
||||
|
||||
$result = array(
|
||||
"error" => false,
|
||||
"message" => "sent_reports_updated",
|
||||
"data" => $return_data,
|
||||
);
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
92
wp-content/plugins/updraftplus/central/modules/rest.php
Normal file
92
wp-content/plugins/updraftplus/central/modules/rest.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles commands to access the REST API.
|
||||
*
|
||||
* This action is used to relay any REST API request through UDC command.
|
||||
* From UDC we don't have direct authentication to child site's REST APIs, therefore this middleware.
|
||||
*
|
||||
* UDC authentication logic automatically authenticates the user with which you have added the site to UDC dashboard.
|
||||
* And then the request is just relayed to the WordPress rest api handler, which takes care of permission callback and everything as usual.
|
||||
*/
|
||||
class UpdraftCentral_REST_API_Access_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
protected $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* Link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function _pre_action($command, $data) {
|
||||
$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
|
||||
*
|
||||
* Link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action() {
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Relays the REST API request.
|
||||
*
|
||||
* @param array $params The parameters for the request.
|
||||
*
|
||||
* @return array The response from the REST API, wrapped in udrpc response structure.
|
||||
*/
|
||||
public function handle_request($params) {
|
||||
$route = untrailingslashit(!empty($params['route']) ? $params['route'] : '');
|
||||
$method = !empty($params['method']) ? $params['method'] : 'GET';
|
||||
$body = !empty($params['body']) ? $params['body'] : null;
|
||||
|
||||
// Return early if the route is empty.
|
||||
if (empty($route)) {
|
||||
return $this->_generic_error_response('route_empty', array(
|
||||
'prefix' => 'updraftcentral',
|
||||
'command' => 'handle_request',
|
||||
'class' => 'UpdraftCentral_REST_API_Access_Commands'
|
||||
));
|
||||
}
|
||||
|
||||
if (!class_exists('WP_REST_Request')) {
|
||||
return $this->_generic_error_response('rest_api_not_available_on_this_wordpress_version', array(
|
||||
'prefix' => 'updraftcentral',
|
||||
'command' => 'handle_request',
|
||||
'class' => 'UpdraftCentral_REST_API_Access_Commands'
|
||||
));
|
||||
}
|
||||
|
||||
$request = new WP_REST_Request($method, '/' . $route);
|
||||
|
||||
if (!empty($body)) {
|
||||
$request->set_body(json_encode($body));
|
||||
$request->set_header('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
// Do the request.
|
||||
$response = rest_do_request($request);
|
||||
|
||||
// Return if error.
|
||||
if (true === $response->is_error()) {
|
||||
return $this->_generic_error_response('rest_request_failed', $response->as_error());
|
||||
}
|
||||
|
||||
// `get_data` should always return JSON-serializable data.
|
||||
return $this->_response(array('rest_data' => $response->get_data(), 'headers' => $response->headers));
|
||||
}
|
||||
}
|
||||
964
wp-content/plugins/updraftplus/central/modules/theme.php
Normal file
964
wp-content/plugins/updraftplus/central/modules/theme.php
Normal file
@@ -0,0 +1,964 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
// Get pagination parameters early
|
||||
$updates_only = isset($query['updates_only']) ? filter_var($query['updates_only'], FILTER_VALIDATE_BOOLEAN) : false;
|
||||
$include_updates_pagination = isset($query['include_updates_pagination']) && $query['include_updates_pagination'];
|
||||
$per_page = isset($query['per_page']) ? (int) $query['per_page'] : 10;
|
||||
$page = isset($query['page']) ? (int) $query['page'] : 1;
|
||||
$offset = ($page - 1) * $per_page;
|
||||
|
||||
// A call is considered legacy if neither updates_only nor include_updates_pagination flags are set
|
||||
$is_legacy_call = !isset($query['updates_only']) && !isset($query['include_updates_pagination']) && !isset($query['per_page']);
|
||||
$sort_direction = isset($query['sort_direction']) ? strtolower($query['sort_direction']) : 'asc';
|
||||
|
||||
// Initialize arrays
|
||||
$themes_with_updates = array();
|
||||
$themes_without_updates = array();
|
||||
$installed_slugs = array();
|
||||
$snoozed_themes_info = array();
|
||||
|
||||
// Get current theme info once
|
||||
$current_theme_slug = basename(get_stylesheet_directory());
|
||||
$website = get_bloginfo('name');
|
||||
|
||||
// Load updates
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$updates = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
$theme_updates = (array) $updates->get_item_updates('themes');
|
||||
|
||||
// Get all themes
|
||||
$themes = wp_get_themes($args);
|
||||
|
||||
// Sort themes by name
|
||||
if (!empty($themes)) {
|
||||
uasort($themes, array($this, '_sort_themes_by_name'));
|
||||
}
|
||||
|
||||
// Get list of snoozed theme slugs if provided
|
||||
$snoozed_slugs = isset($query['snoozed_themes']) ? $query['snoozed_themes'] : array();
|
||||
|
||||
// Prepare config object for theme data
|
||||
$config = array(
|
||||
'website' => $website,
|
||||
'current_theme_slug' => $current_theme_slug,
|
||||
'is_legacy_call' => $is_legacy_call,
|
||||
'snoozed_slugs' => $snoozed_slugs
|
||||
);
|
||||
|
||||
// Process themes efficiently
|
||||
foreach ($themes as $slug => $value) {
|
||||
// Skip processing if we're only looking for updates and this theme has none
|
||||
if ($updates_only && empty($theme_updates[$slug])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$config['slug'] = $slug;
|
||||
$theme = $this->_prepare_theme_data($value, $config);
|
||||
|
||||
// Track installed slugs if needed
|
||||
if (!empty($query['get_installed_slugs'])) {
|
||||
$installed_slugs[] = $slug;
|
||||
}
|
||||
|
||||
// Check for updates and categorize
|
||||
if (!empty($theme_updates[$slug]) && version_compare($theme->version, $theme_updates[$slug]->update['new_version'], '<')) {
|
||||
$theme = $this->_add_update_info($theme, $theme_updates[$slug], $is_legacy_call);
|
||||
|
||||
// Add to themes_with_updates regardless of snooze status
|
||||
if ($slug === $current_theme_slug) {
|
||||
$themes_with_updates = array($theme->slug => $theme) + $themes_with_updates;
|
||||
} else {
|
||||
$themes_with_updates[$theme->slug] = $theme;
|
||||
}
|
||||
|
||||
// Track snoozed status separately
|
||||
if (in_array($slug, $snoozed_slugs)) {
|
||||
$snoozed_themes_info[$slug] = $theme;
|
||||
}
|
||||
} else {
|
||||
if ($slug === $current_theme_slug) {
|
||||
$themes_without_updates = array($theme->slug => $theme) + $themes_without_updates;
|
||||
} else {
|
||||
$themes_without_updates[$theme->slug] = $theme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle response based on call type
|
||||
if ($is_legacy_call) {
|
||||
$result = $this->_prepare_legacy_response($themes_with_updates, $themes_without_updates, $theme_updates);
|
||||
} else {
|
||||
$result = $this->_prepare_paginated_response(
|
||||
$themes_with_updates,
|
||||
$themes_without_updates,
|
||||
$updates_only,
|
||||
$include_updates_pagination,
|
||||
$per_page,
|
||||
$page,
|
||||
$offset,
|
||||
$current_theme_slug,
|
||||
$sort_direction
|
||||
);
|
||||
}
|
||||
|
||||
// Add installed slugs if requested
|
||||
if (!empty($query['get_installed_slugs'])) {
|
||||
$result['installed_slugs'] = $installed_slugs;
|
||||
}
|
||||
|
||||
// Add snoozed themes info if any were requested
|
||||
if (!empty($snoozed_themes_info)) {
|
||||
$result['snoozed_themes_info'] = $snoozed_themes_info;
|
||||
}
|
||||
|
||||
return $this->_response(array_merge($result, $this->_get_backup_credentials_settings(get_theme_root())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare basic theme data
|
||||
*
|
||||
* @param WP_Theme $value Theme object
|
||||
* @param array $config Configuration array containing:
|
||||
* - slug: Theme slug
|
||||
* - website: Website name
|
||||
* - current_theme_slug: Current active theme slug
|
||||
* - is_legacy_call: Whether this is a legacy call
|
||||
* - snoozed_slugs: Array of snoozed theme slugs
|
||||
* @return stdClass Theme data object
|
||||
*/
|
||||
private function _prepare_theme_data($value, $config) {
|
||||
$theme = new stdClass();
|
||||
$theme->name = $value->get('Name') ? $value->get('Name') : $config['slug'];
|
||||
$theme->description = $value->get('Description');
|
||||
$theme->slug = $config['slug'];
|
||||
$theme->version = $value->get('Version');
|
||||
$theme->author = $value->get('Author');
|
||||
$theme->status = ($config['slug'] === $config['current_theme_slug']) ? 'active' : 'inactive';
|
||||
|
||||
// Set is_snoozed property for all themes
|
||||
$theme->is_snoozed = !empty($config['snoozed_slugs']) && in_array($config['slug'], $config['snoozed_slugs']);
|
||||
|
||||
if (!$config['is_legacy_call']) {
|
||||
$screenshot = $value->get_screenshot();
|
||||
$theme->screenshot = $screenshot ? $screenshot : null;
|
||||
$theme->has_update = false;
|
||||
}
|
||||
|
||||
$template = $value->get('Template');
|
||||
$theme->child_theme = !empty($template);
|
||||
$theme->website = $config['website'];
|
||||
$theme->multisite = is_multisite();
|
||||
$theme->site_url = trailingslashit(get_bloginfo('url'));
|
||||
|
||||
if ($theme->child_theme) {
|
||||
$parent_theme = wp_get_theme($template);
|
||||
$theme->parent = $parent_theme->get('Name') ? $parent_theme->get('Name') : $parent_theme->get_stylesheet();
|
||||
}
|
||||
|
||||
if (empty($theme->short_description) && !empty($theme->description)) {
|
||||
$temp = explode('.', $theme->description);
|
||||
$theme->short_description = $temp[0] . (isset($temp[1]) ? '.' . $temp[1] : '') . '.';
|
||||
}
|
||||
|
||||
return $theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add update information to theme object
|
||||
*
|
||||
* @param stdClass $theme Theme object
|
||||
* @param object $update_info Update information
|
||||
* @param bool $is_legacy_call Whether this is a legacy call
|
||||
* @return stdClass Updated theme object
|
||||
*/
|
||||
private function _add_update_info($theme, $update_info, $is_legacy_call) {
|
||||
$theme->latest_version = $update_info->update['new_version'];
|
||||
$theme->download_link = $update_info->update['package'];
|
||||
|
||||
if (!$is_legacy_call) {
|
||||
$theme->update_url = $update_info->update['url'];
|
||||
$theme->requires = $update_info->update['requires'];
|
||||
$theme->requires_php = $update_info->update['requires_php'];
|
||||
$theme->has_update = true;
|
||||
}
|
||||
|
||||
return $theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare legacy response format
|
||||
*
|
||||
* @param array $themes_with_updates Themes with updates
|
||||
* @param array $themes_without_updates Themes without updates
|
||||
* @param array $theme_updates Theme updates data
|
||||
* @return array Legacy format response
|
||||
*/
|
||||
private function _prepare_legacy_response($themes_with_updates, $themes_without_updates, $theme_updates) {
|
||||
return array(
|
||||
'themes' => array_merge(array_values($themes_with_updates), array_values($themes_without_updates)),
|
||||
'theme_updates' => $theme_updates,
|
||||
'is_super_admin' => is_super_admin(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare paginated response format
|
||||
*
|
||||
* @param array $themes_with_updates Themes with updates
|
||||
* @param array $themes_without_updates Themes without updates
|
||||
* @param bool $updates_only Whether only updates are requested
|
||||
* @param bool $include_updates_pagination Whether to include updates pagination
|
||||
* @param int $per_page Number of items per page
|
||||
* @param int $page Current page number
|
||||
* @param int $offset Offset for pagination
|
||||
* @param string $current_theme_slug Current active theme slug
|
||||
* @param string $sort_direction Sort direction
|
||||
* @return array Paginated response
|
||||
*/
|
||||
private function _prepare_paginated_response($themes_with_updates, $themes_without_updates, $updates_only, $include_updates_pagination, $per_page, $page, $offset, $current_theme_slug, $sort_direction) {
|
||||
|
||||
// If only requesting updates, filter out snoozed themes here
|
||||
if ($updates_only) {
|
||||
$filtered_updates = array_filter($themes_with_updates, array($this, '_filter_non_snoozed'));
|
||||
$results = array_slice($filtered_updates, $offset, $per_page);
|
||||
return array(
|
||||
'theme_updates' => $results,
|
||||
'pagination' => array(
|
||||
'total' => count($filtered_updates),
|
||||
'per_page' => $per_page,
|
||||
'current_page' => $page,
|
||||
'total_pages' => ceil(count($filtered_updates) / $per_page)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// For all themes view, merge and sort
|
||||
$all_themes = array_merge($themes_with_updates, $themes_without_updates);
|
||||
|
||||
// Sort themes
|
||||
global $current_theme_slug, $sort_direction;
|
||||
$current_theme_slug = $current_theme_slug;
|
||||
$sort_direction = $sort_direction;
|
||||
uasort($all_themes, array($this, '_sort_themes_with_active'));
|
||||
|
||||
// Get paginated results for all themes
|
||||
$results = array_slice($all_themes, $offset, $per_page);
|
||||
|
||||
// Filter out snoozed themes from updates list
|
||||
$filtered_updates = array_filter($themes_with_updates, array($this, '_filter_non_snoozed'));
|
||||
|
||||
// For theme_updates, use the filtered list
|
||||
$paginated_updates = $include_updates_pagination ? array_slice($filtered_updates, 0, $per_page) : $filtered_updates;
|
||||
|
||||
// Return with all the original data
|
||||
$total_themes = count($all_themes);
|
||||
$result = array(
|
||||
'themes' => $results, // Contains ALL themes including snoozed ones
|
||||
'theme_updates' => $paginated_updates, // Contains only non-snoozed themes with updates
|
||||
'is_super_admin' => is_super_admin(),
|
||||
'pagination' => array(
|
||||
'total' => $total_themes,
|
||||
'per_page' => $per_page,
|
||||
'current_page' => $page,
|
||||
'total_pages' => ceil($total_themes / $per_page)
|
||||
),
|
||||
'updates_count' => count($filtered_updates)
|
||||
);
|
||||
|
||||
if ($include_updates_pagination) {
|
||||
$result['updates_pagination'] = array(
|
||||
'total' => count($filtered_updates),
|
||||
'per_page' => $per_page,
|
||||
'current_page' => 1,
|
||||
'total_pages' => ceil(count($filtered_updates) / $per_page)
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort themes by name
|
||||
*
|
||||
* @param object $a Theme object
|
||||
* @param object $b Theme object
|
||||
* @return int Comparison result
|
||||
*/
|
||||
private function _sort_themes_by_name($a, $b) {
|
||||
global $sort_direction;
|
||||
$result = strcasecmp($a->name, $b->name);
|
||||
return 'desc' === $sort_direction ? -$result : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort all themes while keeping active theme first
|
||||
*
|
||||
* @param object $a Theme object
|
||||
* @param object $b Theme object
|
||||
* @return int Comparison result
|
||||
*/
|
||||
private function _sort_themes_with_active($a, $b) {
|
||||
global $current_theme_slug, $sort_direction;
|
||||
// Active theme always first
|
||||
if ($a->slug === $current_theme_slug) return -1;
|
||||
if ($b->slug === $current_theme_slug) return 1;
|
||||
|
||||
// Sort by name respecting direction
|
||||
$result = strcasecmp($a->name, $b->name);
|
||||
return 'desc' === $sort_direction ? -$result : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out snoozed themes
|
||||
*
|
||||
* @param object $theme Theme object
|
||||
* @return bool Whether the theme is not snoozed
|
||||
*/
|
||||
private function _filter_non_snoozed($theme) {
|
||||
return !$theme->is_snoozed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()));
|
||||
}
|
||||
}
|
||||
1028
wp-content/plugins/updraftplus/central/modules/updates.php
Normal file
1028
wp-content/plugins/updraftplus/central/modules/updates.php
Normal file
File diff suppressed because it is too large
Load Diff
632
wp-content/plugins/updraftplus/central/modules/users.php
Normal file
632
wp-content/plugins/updraftplus/central/modules/users.php
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user