logger = TigerStyleSEO_Backup_Logger::instance(); $this->settings = get_option('tigerstyle_backup_settings', array()); $this->setup_hooks(); } /** * Setup WordPress hooks */ private function setup_hooks() { // Scheduled backup hook add_action('tigerstyle_backup_scheduled', array($this, 'run_scheduled_backup')); // Cleanup hook add_action('tigerstyle_backup_cleanup', array($this, 'cleanup_old_backups')); // Admin hooks add_action('admin_init', array($this, 'maybe_setup_schedules')); // Plugin deactivation cleanup register_deactivation_hook(TIGERSTYLE_HEAT_PLUGIN_FILE, array($this, 'clear_schedules')); } /** * Setup schedules if needed */ public function maybe_setup_schedules() { // Setup cleanup schedule if not exists if (!wp_next_scheduled('tigerstyle_backup_cleanup')) { wp_schedule_event(time() + 3600, 'daily', 'tigerstyle_backup_cleanup'); } // Setup backup schedule based on settings $this->update_backup_schedule(); } /** * Update backup schedule based on settings */ public function update_backup_schedule() { // Clear existing schedule wp_clear_scheduled_hook('tigerstyle_backup_scheduled'); // Setup new schedule if enabled if (!empty($this->settings['schedule_enabled'])) { $frequency = $this->settings['schedule_frequency'] ?? 'daily'; $start_time = $this->calculate_next_backup_time($frequency); wp_schedule_event($start_time, $frequency, 'tigerstyle_backup_scheduled'); $this->logger->info('Backup schedule updated', array( 'frequency' => $frequency, 'next_run' => date('Y-m-d H:i:s', $start_time) )); } } /** * Calculate next backup time */ private function calculate_next_backup_time($frequency) { $current_time = time(); $preferred_hour = $this->settings['schedule_time'] ?? '02:00'; // Parse preferred time list($hour, $minute) = explode(':', $preferred_hour); $hour = intval($hour); $minute = intval($minute); // Calculate next run time switch ($frequency) { case 'hourly': return $current_time + HOUR_IN_SECONDS; case 'daily': $next_time = mktime($hour, $minute, 0); if ($next_time <= $current_time) { $next_time += DAY_IN_SECONDS; } return $next_time; case 'weekly': $preferred_day = $this->settings['schedule_day'] ?? 'sunday'; $day_number = $this->get_day_number($preferred_day); $next_time = strtotime("next {$preferred_day} {$hour}:{$minute}:00"); return $next_time; case 'monthly': $preferred_date = $this->settings['schedule_date'] ?? 1; $next_time = mktime($hour, $minute, 0, date('n'), $preferred_date); if ($next_time <= $current_time) { $next_time = mktime($hour, $minute, 0, date('n') + 1, $preferred_date); } return $next_time; default: return $current_time + DAY_IN_SECONDS; } } /** * Run scheduled backup */ public function run_scheduled_backup() { if (!$this->should_run_backup()) { $this->logger->info('Scheduled backup skipped', array( 'reason' => 'Conditions not met' )); return; } try { $this->logger->info('Starting scheduled backup'); $backup_engine = new TigerStyleSEO_Backup_Engine(); $backup_options = array( 'type' => 'scheduled', 'compression' => $this->settings['compression'] ?? 'zip', 'storage_location' => $this->settings['storage_location'] ?? 'local', 'include_files' => $this->settings['include_files'] ?? true, 'include_database' => $this->settings['include_database'] ?? true, 'description' => $this->generate_scheduled_backup_description() ); $backup_id = $backup_engine->create_backup($backup_options); $this->logger->info('Scheduled backup completed successfully', array( 'backup_id' => $backup_id )); // Send notification if enabled if (!empty($this->settings['email_notifications'])) { $this->send_backup_notification($backup_id, true); } // Update last backup time update_option('tigerstyle_last_scheduled_backup', time()); } catch (Exception $e) { $this->logger->error('Scheduled backup failed: ' . $e->getMessage()); // Send failure notification if (!empty($this->settings['email_notifications'])) { $this->send_backup_notification(null, false, $e->getMessage()); } // Record failure $this->record_backup_failure($e->getMessage()); } } /** * Check if backup should run */ private function should_run_backup() { // Check if backups are enabled if (empty($this->settings['schedule_enabled'])) { return false; } // Check system load (don't backup during high load) if ($this->is_system_under_high_load()) { $this->logger->warning('Backup skipped due to high system load'); return false; } // Check disk space if (!$this->has_sufficient_disk_space()) { $this->logger->warning('Backup skipped due to insufficient disk space'); return false; } // Check if another backup is running if ($this->is_backup_running()) { $this->logger->warning('Backup skipped because another backup is running'); return false; } return true; } /** * Check if system is under high load */ private function is_system_under_high_load() { if (!function_exists('sys_getloadavg')) { return false; } $load = sys_getloadavg(); $max_load = $this->settings['max_load_average'] ?? 2.0; return $load && $load[0] > $max_load; } /** * Check if there's sufficient disk space */ private function has_sufficient_disk_space() { $required_space_mb = $this->settings['min_disk_space'] ?? 1024; // 1GB default $required_space = $required_space_mb * 1024 * 1024; $available_space = disk_free_space(ABSPATH); return $available_space === false || $available_space > $required_space; } /** * Check if backup is currently running */ private function is_backup_running() { global $wpdb; // Check for active backup processes $active_backups = get_transient('tigerstyle_active_backup_processes'); if ($active_backups && count($active_backups) > 0) { // Clean up stale processes (older than 2 hours) $current_time = time(); foreach ($active_backups as $key => $timestamp) { if ($current_time - $timestamp > 7200) { unset($active_backups[$key]); } } set_transient('tigerstyle_active_backup_processes', $active_backups, 3600); return count($active_backups) > 0; } return false; } /** * Generate scheduled backup description */ private function generate_scheduled_backup_description() { $frequency = $this->settings['schedule_frequency'] ?? 'daily'; $timestamp = current_time('mysql'); return sprintf( __('Scheduled %s backup - %s', 'tigerstyle-heat'), $frequency, $timestamp ); } /** * Send backup notification email */ private function send_backup_notification($backup_id, $success, $error_message = '') { if (empty($this->settings['notification_email'])) { return; } $site_name = get_bloginfo('name'); $site_url = home_url(); if ($success) { $subject = sprintf(__('[%s] Scheduled Backup Completed Successfully', 'tigerstyle-heat'), $site_name); $message = sprintf( __("Your scheduled backup has completed successfully.\n\nBackup ID: %s\nSite: %s\nCompleted: %s\n\nYou can manage your backups from the WordPress admin panel.", 'tigerstyle-heat'), $backup_id, $site_url, current_time('Y-m-d H:i:s') ); } else { $subject = sprintf(__('[%s] Scheduled Backup Failed', 'tigerstyle-heat'), $site_name); $message = sprintf( __("Your scheduled backup has failed.\n\nSite: %s\nFailed: %s\nError: %s\n\nPlease check your backup settings and try again.", 'tigerstyle-heat'), $site_url, current_time('Y-m-d H:i:s'), $error_message ); } wp_mail($this->settings['notification_email'], $subject, $message); } /** * Record backup failure */ private function record_backup_failure($error_message) { $failures = get_option('tigerstyle_scheduled_backup_failures', array()); $failures[] = array( 'timestamp' => time(), 'error' => $error_message ); // Keep only last 10 failures $failures = array_slice($failures, -10); update_option('tigerstyle_scheduled_backup_failures', $failures); } /** * Cleanup old backups */ public function cleanup_old_backups() { $retention_days = $this->settings['retention_days'] ?? 30; if ($retention_days <= 0) { return; // Unlimited retention } try { $storage_manager = new TigerStyleSEO_Storage_Manager(); $deleted_count = $storage_manager->cleanup_old_backups($retention_days); $this->logger->info('Old backups cleanup completed', array( 'retention_days' => $retention_days, 'deleted_count' => $deleted_count )); } catch (Exception $e) { $this->logger->error('Backup cleanup failed: ' . $e->getMessage()); } } /** * Get next scheduled backup time */ public function get_next_backup_time() { $timestamp = wp_next_scheduled('tigerstyle_backup_scheduled'); if (!$timestamp) { return null; } return array( 'timestamp' => $timestamp, 'formatted' => date('Y-m-d H:i:s', $timestamp), 'human' => human_time_diff($timestamp, current_time('timestamp')) ); } /** * Get backup schedule status */ public function get_schedule_status() { $status = array( 'enabled' => !empty($this->settings['schedule_enabled']), 'frequency' => $this->settings['schedule_frequency'] ?? 'daily', 'next_run' => $this->get_next_backup_time(), 'last_run' => null, 'last_success' => null, 'failure_count' => 0 ); // Get last backup time $last_backup_time = get_option('tigerstyle_last_scheduled_backup'); if ($last_backup_time) { $status['last_run'] = array( 'timestamp' => $last_backup_time, 'formatted' => date('Y-m-d H:i:s', $last_backup_time), 'human' => human_time_diff($last_backup_time, current_time('timestamp')) . __(' ago', 'tigerstyle-heat') ); } // Get failure information $failures = get_option('tigerstyle_scheduled_backup_failures', array()); $status['failure_count'] = count($failures); if (!empty($failures)) { $last_failure = end($failures); $status['last_failure'] = array( 'timestamp' => $last_failure['timestamp'], 'formatted' => date('Y-m-d H:i:s', $last_failure['timestamp']), 'error' => $last_failure['error'] ); } return $status; } /** * Enable scheduled backups */ public function enable_schedule($frequency = 'daily', $time = '02:00') { $this->settings['schedule_enabled'] = true; $this->settings['schedule_frequency'] = $frequency; $this->settings['schedule_time'] = $time; update_option('tigerstyle_backup_settings', $this->settings); $this->update_backup_schedule(); $this->logger->info('Backup schedule enabled', array( 'frequency' => $frequency, 'time' => $time )); } /** * Disable scheduled backups */ public function disable_schedule() { $this->settings['schedule_enabled'] = false; update_option('tigerstyle_backup_settings', $this->settings); wp_clear_scheduled_hook('tigerstyle_backup_scheduled'); $this->logger->info('Backup schedule disabled'); } /** * Run backup immediately */ public function run_backup_now() { // Mark as manual backup $backup_engine = new TigerStyleSEO_Backup_Engine(); $backup_options = array( 'type' => 'manual', 'compression' => $this->settings['compression'] ?? 'zip', 'storage_location' => $this->settings['storage_location'] ?? 'local', 'include_files' => $this->settings['include_files'] ?? true, 'include_database' => $this->settings['include_database'] ?? true, 'description' => __('Manual backup - ', 'tigerstyle-heat') . current_time('mysql') ); return $backup_engine->create_backup($backup_options); } /** * Get day number for date calculations */ private function get_day_number($day_name) { $days = array( 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6 ); return $days[strtolower($day_name)] ?? 0; } /** * Clear all schedules (for plugin deactivation) */ public function clear_schedules() { wp_clear_scheduled_hook('tigerstyle_backup_scheduled'); wp_clear_scheduled_hook('tigerstyle_backup_cleanup'); $this->logger->info('All backup schedules cleared'); } /** * Get backup statistics */ public function get_backup_statistics($days = 30) { global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_metadata'; $since_date = date('Y-m-d H:i:s', strtotime("-{$days} days")); $stats = $wpdb->get_row( $wpdb->prepare( "SELECT COUNT(*) as total_backups, SUM(CASE WHEN backup_id LIKE 'backup_%scheduled%' THEN 1 ELSE 0 END) as scheduled_backups, SUM(CASE WHEN backup_id LIKE 'backup_%manual%' THEN 1 ELSE 0 END) as manual_backups, AVG(file_size) as average_size, SUM(file_size) as total_size FROM {$table_name} WHERE created_at >= %s", $since_date ), ARRAY_A ); if ($stats) { $stats['average_size_formatted'] = size_format($stats['average_size']); $stats['total_size_formatted'] = size_format($stats['total_size']); $stats['success_rate'] = $this->calculate_success_rate($days); } return $stats ?: array(); } /** * Calculate backup success rate */ private function calculate_success_rate($days) { $failures = get_option('tigerstyle_scheduled_backup_failures', array()); $recent_failures = array_filter($failures, function($failure) use ($days) { return $failure['timestamp'] > strtotime("-{$days} days"); }); global $wpdb; $table_name = $wpdb->prefix . 'tigerstyle_backup_metadata'; $since_date = date('Y-m-d H:i:s', strtotime("-{$days} days")); $total_attempts = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE created_at >= %s AND backup_id LIKE '%scheduled%'", $since_date ) ); $total_attempts += count($recent_failures); if ($total_attempts === 0) { return 100; } $success_rate = (($total_attempts - count($recent_failures)) / $total_attempts) * 100; return round($success_rate, 2); } }