if (!defined('UPDRAFTPLUS_DIR')) die('No direct access allowed');
// Admin-area code lives here. This gets called in admin_menu, earlier than admin_init
global $updraftplus_admin;
if (!is_a($updraftplus_admin, 'UpdraftPlus_Admin')) $updraftplus_admin = new UpdraftPlus_Admin();
class UpdraftPlus_Admin {
public $logged = array();
private $template_directories;
private $backups_instance_ids;
private $auth_instance_ids = array('dropbox' => array(), 'onedrive' => array(), 'googledrive' => array(), 'googlecloud' => array());
private $php_versions = array('5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0');
private $storage_service_without_settings;
private $storage_service_with_partial_settings;
public function __construct() {
* Get the path to the UI templates directory
* @return String - a filesystem directory path
public function get_templates_dir() {
return apply_filters('updraftplus_templates_dir', UpdraftPlus_Manipulation_Functions::wp_normalize_path(UPDRAFTPLUS_DIR.'/templates'));
private function register_template_directories() {
$template_directories = array();
$templates_dir = $this->get_templates_dir();
if ($dh = opendir($templates_dir)) {
while (($file = readdir($dh)) !== false) {
if ('.' == $file || '..' == $file) continue;
if (is_dir($templates_dir.'/'.$file)) {
$template_directories[$file] = $templates_dir.'/'.$file;
// This is the optimal hook for most extensions to hook into
$this->template_directories = apply_filters('updraftplus_template_directories', $template_directories);
* Output, or return, the results of running a template (from the 'templates' directory, unless a filter over-rides it). Templates are run with $updraftplus, $updraftplus_admin and $wpdb set.
* @param String $path - path to the template
* @param Boolean $return_instead_of_echo - by default, the template is echo-ed; set this to instead return it
* @param Array $extract_these - variables to inject into the template's run context
public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
if ($return_instead_of_echo) ob_start();
if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
if (isset($this->template_directories[$prefix])) {
$template_file = $this->template_directories[$prefix].'/'.$suffix;
if (!isset($template_file)) $template_file = UPDRAFTPLUS_DIR.'/templates/'.$path;
$template_file = apply_filters('updraftplus_template', $template_file, $path);
do_action('updraftplus_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
if (!file_exists($template_file)) {
error_log("UpdraftPlus: template not found: $template_file");
echo __('Error:', 'updraftplus').' '.__('template not found', 'updraftplus')." ($path)";
global $updraftplus, $wpdb;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$updraftplus_admin = $this;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
do_action('updraftplus_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);
if ($return_instead_of_echo) return ob_get_clean();
* Add actions for any needed dashboard notices for remote storage services
* @param String|Array $services - a list of services, or single service
private function setup_all_admin_notices_global($services) {
if ('googledrive' === $services || (is_array($services) && in_array('googledrive', $services))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('googledrive');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "Google Drive (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $instance_id => $storage_options) {
if ((defined('UPDRAFTPLUS_CUSTOM_GOOGLEDRIVE_APP') && UPDRAFTPLUS_CUSTOM_GOOGLEDRIVE_APP) || !empty($storage_options['clientid'])) {
if (!empty($storage_options['clientid'])) {
$clientid = $storage_options['clientid'];
$token = empty($storage_options['token']) ? '' : $storage_options['token'];
if (!empty($clientid) && '' == $token) {
if (!in_array($instance_id, $this->auth_instance_ids['googledrive'])) $this->auth_instance_ids['googledrive'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googledrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googledrive'));
if (empty($storage_options['user_id'])) {
if (!in_array($instance_id, $this->auth_instance_ids['googledrive'])) $this->auth_instance_ids['googledrive'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googledrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googledrive'));
if ('googlecloud' === $services || (is_array($services) && in_array('googlecloud', $services))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('googlecloud');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "Google Cloud (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $instance_id => $storage_options) {
if ((defined('UPDRAFTPLUS_CUSTOM_GOOGLECLOUD_APP') && UPDRAFTPLUS_CUSTOM_GOOGLECLOUD_APP) || !empty($storage_options['clientid'])) {
$clientid = $storage_options['clientid'];
$token = (empty($storage_options['token'])) ? '' : $storage_options['token'];
if (!empty($clientid) && empty($token)) {
if (!in_array($instance_id, $this->auth_instance_ids['googlecloud'])) $this->auth_instance_ids['googlecloud'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googlecloud'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googlecloud'));
if (empty($storage_options['user_id'])) {
if (!in_array($instance_id, $this->auth_instance_ids['googlecloud'])) $this->auth_instance_ids['googlecloud'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googlecloud'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googlecloud'));
if ('dropbox' === $services || (is_array($services) && in_array('dropbox', $services))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('dropbox');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "Dropbox (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $instance_id => $storage_options) {
if (empty($storage_options['tk_access_token'])) {
if (!in_array($instance_id, $this->auth_instance_ids['dropbox'])) $this->auth_instance_ids['dropbox'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_dropbox'))) add_action('all_admin_notices', array($this, 'show_admin_warning_dropbox'));
if ('onedrive' === $services || (is_array($services) && in_array('onedrive', $services))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('onedrive');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "OneDrive (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $instance_id => $storage_options) {
if ((defined('UPDRAFTPLUS_CUSTOM_ONEDRIVE_APP') && UPDRAFTPLUS_CUSTOM_ONEDRIVE_APP)) {
if (!empty($storage_options['clientid']) && !empty($storage_options['secret']) && empty($storage_options['refresh_token'])) {
if (!in_array($instance_id, $this->auth_instance_ids['onedrive'])) $this->auth_instance_ids['onedrive'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'));
} elseif (empty($storage_options['refresh_token'])) {
if (!in_array($instance_id, $this->auth_instance_ids['onedrive'])) $this->auth_instance_ids['onedrive'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'));
if (empty($storage_options['refresh_token'])) {
if (!in_array($instance_id, $this->auth_instance_ids['onedrive'])) $this->auth_instance_ids['onedrive'][] = $instance_id;
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'));
if (isset($storage_options['endpoint_tld']) && 'de' === $storage_options['endpoint_tld']) {
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive_germany'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive_germany'));
if ('azure' === $services || (is_array($services) && in_array('azure', $services))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('azure');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "Azure (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $instance_id => $storage_options) {
if (isset($storage_options['endpoint']) && 'blob.core.cloudapi.de' === $storage_options['endpoint']) {
if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_azure_germany'))) add_action('all_admin_notices', array($this, 'show_admin_warning_azure_germany'));
if ('updraftvault' === $services || (is_array($services) && in_array('updraftvault', $services))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('updraftvault');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "UpdraftVault (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $instance_id => $storage_options) {
if (empty($storage_options['token']) && empty($storage_options['email'])) {
add_action('all_admin_notices', array($this, 'show_admin_warning_updraftvault'));
if ($this->disk_space_check(1048576*35) === false) add_action('all_admin_notices', array($this, 'show_admin_warning_diskspace'));
$all_services = UpdraftPlus_Storage_Methods_Interface::get_enabled_storage_objects_and_ids($updraftplus->get_canonical_service_list());
$this->storage_service_without_settings = array();
$this->storage_service_with_partial_settings = array();
foreach ($all_services as $method => $sinfo) {
if (empty($sinfo['object']) || empty($sinfo['instance_settings']) || !is_callable(array($sinfo['object'], 'options_exist'))) continue;
foreach ($sinfo['instance_settings'] as $opt) {
if (!$sinfo['object']->options_exist($opt)) {
if (isset($opt['auth_in_progress'])) {
$this->storage_service_with_partial_settings[$method] = $updraftplus->backup_methods[$method];
$this->storage_service_without_settings[] = $updraftplus->backup_methods[$method];
if (!empty($this->storage_service_with_partial_settings)) {
add_action('all_admin_notices', array($this, 'show_admin_warning_if_remote_storage_with_partial_setttings'));
if (!empty($this->storage_service_without_settings)) {
add_action('all_admin_notices', array($this, 'show_admin_warning_if_remote_storage_settting_are_empty'));
if ($updraftplus->is_restricted_hosting('only_one_backup_per_month')) {
add_action('all_admin_notices', array($this, 'show_admin_warning_one_backup_per_month'));
private function setup_all_admin_notices_udonly($service, $override = false) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Filter use
if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
@ini_set('display_errors', 1);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
if (defined('E_DEPRECATED')) {
@error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, PHPCompatibility.Constants.NewConstants.e_deprecatedFound -- Ok to ignore
@error_reporting(E_ALL & ~E_NOTICE);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
add_action('all_admin_notices', array($this, 'show_admin_debug_warning'));
if (null === UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
add_action('all_admin_notices', array($this, 'show_admin_nosettings_warning'));
$this->no_settings_warning = true;
// Avoid false positives, by attempting to raise the limit (as happens when we actually do a backup)
if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
$max_execution_time = (int) @ini_get('max_execution_time');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
if ($max_execution_time>0 && $max_execution_time<20) {
add_action('all_admin_notices', array($this, 'show_admin_warning_execution_time'));
// LiteSpeed has a generic problem with terminating cron jobs
if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) {
if (!is_file(ABSPATH.'.htaccess') || !preg_match('/noabort/i', file_get_contents(ABSPATH.'.htaccess'))) {
add_action('all_admin_notices', array($this, 'show_admin_warning_litespeed'));
if (version_compare($updraftplus->get_wordpress_version(), '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion'));
// DreamObjects west cluster shutdown warning
if ('dreamobjects' === $service || (is_array($service) && in_array('dreamobjects', $service))) {
$settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('dreamobjects');
if (is_wp_error($settings)) {
if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = '';
$this->storage_module_option_errors .= "DreamObjects (".$settings->get_error_code()."): ".$settings->get_error_message();
add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options'));
$updraftplus->log_wp_error($settings, true, true);
} elseif (!empty($settings['settings'])) {
foreach ($settings['settings'] as $storage_options) {
if ('objects-us-west-1.dream.io' == $storage_options['endpoint']) {
add_action('all_admin_notices', array($this, 'show_admin_warning_dreamobjects'));
// If the plugin was not able to connect to a UDC account due to lack of licences
if (isset($_GET['udc_connect']) && 0 == $_GET['udc_connect']) {
add_action('all_admin_notices', array($this, 'show_admin_warning_udc_couldnt_connect'));
* Used to output the information for the next scheduled backup.
* moved to function for the ajax saves
public function next_scheduled_backups_output() {
$next_scheduled_backup = wp_next_scheduled('updraft_backup');
if ($next_scheduled_backup) {
$next_scheduled_backup_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup);
// Convert to blog time zone
$next_scheduled_backup = get_date_from_gmt($next_scheduled_backup_gmt, 'D, F j, Y H:i');
// $next_scheduled_backup = date_i18n('D, F j, Y H:i', $next_scheduled_backup);
$next_scheduled_backup = __('Nothing currently scheduled', 'updraftplus');
$files_not_scheduled = true;
$next_scheduled_backup_database = wp_next_scheduled('updraft_backup_database');
if (UpdraftPlus_Options::get_updraft_option('updraft_interval_database', UpdraftPlus_Options::get_updraft_option('updraft_interval')) == UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
if (isset($files_not_scheduled)) {
$next_scheduled_backup_database = $next_scheduled_backup;
$database_not_scheduled = true;
$next_scheduled_backup_database = __("At the same time as the files backup", 'updraftplus');
$next_scheduled_backup_database_same_time = true;
if ($next_scheduled_backup_database) {
$next_scheduled_backup_database_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup_database);
// Convert to blog time zone
$next_scheduled_backup_database = get_date_from_gmt($next_scheduled_backup_database_gmt, 'D, F j, Y H:i');
// $next_scheduled_backup_database = date_i18n('D, F j, Y H:i', $next_scheduled_backup_database);
$next_scheduled_backup_database = __('Nothing currently scheduled', 'updraftplus');
$database_not_scheduled = true;
if (isset($files_not_scheduled) && isset($database_not_scheduled)) {
<span class="not-scheduled"><?php _e('Nothing currently scheduled', 'updraftplus'); ?></span>
echo empty($next_scheduled_backup_database_same_time) ? __('Files', 'updraftplus') : __('Files and database', 'updraftplus');
<span class="updraft_all-files">
echo $next_scheduled_backup;
if (empty($next_scheduled_backup_database_same_time)) {
_e('Database', 'updraftplus');
<span class="updraft_all-files">
echo $next_scheduled_backup_database;
* Used to output the information for the next scheduled file backup.
* moved to function for the ajax saves
* @param Boolean $return_instead_of_echo Whether to return or echo the results. N.B. More than just the results to echo will be returned
* @return Void|String If $return_instead_of_echo parameter is true, It returns html string
public function next_scheduled_files_backups_output($return_instead_of_echo = false) {
if ($return_instead_of_echo) ob_start();
$next_scheduled_backup = wp_next_scheduled('updraft_backup');
if ($next_scheduled_backup) {
// Convert to blog time zone. wp_date() (WP 5.3+) also performs locale translation.
$next_scheduled_backup = function_exists('wp_date') ? wp_date('D, F j, Y H:i', $next_scheduled_backup) : get_date_from_gmt(gmdate('Y-m-d H:i:s', $next_scheduled_backup), 'D, F j, Y H:i');
$files_not_scheduled = false;
$next_scheduled_backup = __('Nothing currently scheduled', 'updraftplus');
$files_not_scheduled = true;
if ($files_not_scheduled) {
echo '<span>'.$next_scheduled_backup.'</span>';
echo '<span class="updraft_next_scheduled_date_time">'.$next_scheduled_backup.'</span>';
if ($return_instead_of_echo) return ob_get_clean();
* Used to output the information for the next scheduled database backup.
* moved to function for the ajax saves
* @param Boolean $return_instead_of_echo Whether to return or echo the results. N.B. More than just the results to echo will be returned
* @return Void|String If $return_instead_of_echo parameter is true, It returns html string
public function next_scheduled_database_backups_output($return_instead_of_echo = false) {
if ($return_instead_of_echo) ob_start();
$next_scheduled_backup_database = wp_next_scheduled('updraft_backup_database');
if ($next_scheduled_backup_database) {
$next_scheduled_backup_database_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup_database);
// Convert to blog time zone. wp_date() (WP 5.3+) also performs locale translation.
$next_scheduled_backup_database = function_exists('wp_date') ? wp_date('D, F j, Y H:i', $next_scheduled_backup_database) : get_date_from_gmt($next_scheduled_backup_database_gmt, 'D, F j, Y H:i');
$database_not_scheduled = false;
$next_scheduled_backup_database = __('Nothing currently scheduled', 'updraftplus');
$database_not_scheduled = true;
if ($database_not_scheduled) {
echo '<span>'.$next_scheduled_backup_database.'</span>';
echo '<span class="updraft_next_scheduled_date_time">'.$next_scheduled_backup_database.'</span>';
if ($return_instead_of_echo) return ob_get_clean();
* Run upon the WP admin_init action
private function admin_init() {
add_action('admin_init', array($this, 'maybe_download_backup_from_email'));
add_action('core_upgrade_preamble', array($this, 'core_upgrade_preamble'));
add_action('admin_action_upgrade-plugin', array($this, 'admin_action_upgrade_pluginortheme'));
add_action('admin_action_upgrade-theme', array($this, 'admin_action_upgrade_pluginortheme'));
add_action('admin_head', array($this, 'admin_head'));
add_filter((is_multisite() ? 'network_admin_' : '').'plugin_action_links', array($this, 'plugin_action_links'), 10, 2);
add_action('wp_ajax_updraft_download_backup', array($this, 'updraft_download_backup'));
add_action('wp_ajax_updraft_ajax', array($this, 'updraft_ajax_handler'));
add_action('wp_ajax_updraft_ajaxrestore', array($this, 'updraft_ajaxrestore'));
add_action('wp_ajax_nopriv_updraft_ajaxrestore', array($this, 'updraft_ajaxrestore'));
add_action('wp_ajax_updraft_ajaxrestore_continue', array($this, 'updraft_ajaxrestore'));
add_action('wp_ajax_nopriv_updraft_ajaxrestore_continue', array($this, 'updraft_ajaxrestore'));
add_action('wp_ajax_plupload_action', array($this, 'plupload_action'));
add_action('wp_ajax_plupload_action2', array($this, 'plupload_action2'));
add_action('wp_before_admin_bar_render', array($this, 'wp_before_admin_bar_render'));
// Add a new Ajax action for saving settings