MagicWP Docs

Hourly Backup Addon

Premium hourly backup solution with advanced features and real-time protection

Hourly Backup Addon

Experience premium backup protection with our Hourly Backup Addon. Get real-time backup capabilities, advanced monitoring, and enterprise-grade features for maximum data protection.

Premium Features Overview

Real-Time Backup

  • Instant Protection: Backup changes as they happen
  • Continuous Monitoring: Never lose recent work
  • Version Control: Multiple versions per hour
  • Granular Recovery: Restore to specific moments

Advanced Scheduling

  • Custom Intervals: Set backup frequency from minutes to hours
  • Smart Scheduling: Avoid peak traffic periods automatically
  • Priority Queuing: Manage backup job priorities
  • Resource Optimization: Balance backup frequency with server resources

Setup and Configuration

Enable Hourly Backup

// Enable hourly backup addon
define('HOURLY_BACKUP_ENABLED', true);
define('HOURLY_BACKUP_INTERVAL', 60); // Minutes between backups
define('HOURLY_BACKUP_RETENTION', 24); // Hours to keep hourly backups
define('HOURLY_BACKUP_MAX_VERSIONS', 50); // Maximum versions to keep

Resource Configuration

// Resource limits for hourly backups
define('HOURLY_BACKUP_MAX_CPU', 30); // Maximum CPU usage percentage
define('HOURLY_BACKUP_MAX_MEMORY', 128); // Maximum memory usage in MB
define('HOURLY_BACKUP_NETWORK_LIMIT', 10); // Network bandwidth limit in MB/s
define('HOURLY_BACKUP_DISK_IO_LIMIT', 50); // Disk I/O limit in MB/s

Real-Time Backup Engine

Change Detection System

class HourlyBackupChangeDetector {
    private $last_backup_hash = array();
    private $change_threshold = 1024; // 1KB minimum change

    public function detect_changes() {
        $current_state = $this->get_current_site_state();

        $changes = array();
        foreach ($current_state as $component => $hash) {
            if (!isset($this->last_backup_hash[$component]) ||
                $hash !== $this->last_backup_hash[$component]) {
                $changes[$component] = array(
                    'old_hash' => $this->last_backup_hash[$component] ?? null,
                    'new_hash' => $hash,
                    'component' => $component
                );
            }
        }

        $this->last_backup_hash = $current_state;
        return $changes;
    }

    private function get_current_site_state() {
        return array(
            'database' => $this->get_database_hash(),
            'themes' => $this->get_directory_hash(get_theme_root()),
            'plugins' => $this->get_directory_hash(WP_PLUGIN_DIR),
            'uploads' => $this->get_directory_hash(wp_upload_dir()['basedir']),
            'config' => $this->get_file_hash(ABSPATH . 'wp-config.php')
        );
    }

    private function get_database_hash() {
        global $wpdb;

        $tables_hash = '';
        $tables = $wpdb->get_col('SHOW TABLES');

        foreach ($tables as $table) {
            $count = $wpdb->get_var("SELECT COUNT(*) FROM `$table`");
            $last_modified = $wpdb->get_var("SELECT MAX(updated_at) FROM `$table` WHERE updated_at IS NOT NULL");

            $tables_hash .= $table . $count . ($last_modified ?: 'never') . '|';
        }

        return md5($tables_hash);
    }

    private function get_directory_hash($directory) {
        if (!is_dir($directory)) return '';

        $files_hash = '';
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));

        foreach ($iterator as $file) {
            if ($file->isFile()) {
                $files_hash .= $file->getPathname() . $file->getMTime() . $file->getSize() . '|';
            }
        }

        return md5($files_hash);
    }

    private function get_file_hash($file_path) {
        if (!file_exists($file_path)) return '';

        return md5_file($file_path);
    }
}

Incremental Backup System

class HourlyIncrementalBackup {
    private $backup_root;
    private $current_backup_chain = array();

    public function __construct() {
        $this->backup_root = WP_CONTENT_DIR . '/hourly-backups/';
        wp_mkdir_p($this->backup_root);
    }

    public function create_incremental_backup($changes) {
        $timestamp = time();
        $backup_id = 'hourly_' . date('Y-m-d_H-i-s', $timestamp);

        $backup_path = $this->backup_root . $backup_id . '/';
        wp_mkdir_p($backup_path);

        // Create incremental backup for each changed component
        foreach ($changes as $component => $change_info) {
            $this->backup_component_incremental($component, $backup_path);
        }

        // Update backup chain
        $this->current_backup_chain[] = array(
            'id' => $backup_id,
            'timestamp' => $timestamp,
            'path' => $backup_path,
            'changes' => $changes
        );

        // Maintain backup chain limit
        $this->maintain_backup_chain_limit();

        return array(
            'backup_id' => $backup_id,
            'path' => $backup_path,
            'changes' => $changes
        );
    }

    private function backup_component_incremental($component, $backup_path) {
        switch ($component) {
            case 'database':
                $this->backup_database_incremental($backup_path);
                break;
            case 'themes':
                $this->backup_directory_incremental(get_theme_root(), $backup_path . 'themes/');
                break;
            case 'plugins':
                $this->backup_directory_incremental(WP_PLUGIN_DIR, $backup_path . 'plugins/');
                break;
            case 'uploads':
                $this->backup_directory_incremental(wp_upload_dir()['basedir'], $backup_path . 'uploads/');
                break;
            case 'config':
                copy(ABSPATH . 'wp-config.php', $backup_path . 'wp-config.php');
                break;
        }
    }

    private function backup_database_incremental($backup_path) {
        global $wpdb;

        // Get changes since last backup
        $last_backup_time = $this->get_last_backup_time();
        $changed_tables = $this->get_changed_tables($last_backup_time);

        foreach ($changed_tables as $table) {
            $sql_file = $backup_path . $table . '.sql';
            $this->export_table_to_file($table, $sql_file, $last_backup_time);
        }
    }

    private function backup_directory_incremental($source_dir, $backup_dir) {
        wp_mkdir_p($backup_dir);

        // Use rsync for efficient incremental backup
        $command = sprintf(
            'rsync -av --delete --link-dest="%s" "%s" "%s"',
            $this->get_last_backup_path(),
            $source_dir,
            $backup_dir
        );

        exec($command);
    }

    private function maintain_backup_chain_limit() {
        $max_backups = get_option('hourly_backup_max_chain_length', 24);

        if (count($this->current_backup_chain) > $max_backups) {
            // Remove oldest backups
            $backups_to_remove = array_slice($this->current_backup_chain, 0, - $max_backups);

            foreach ($backups_to_remove as $backup) {
                $this->remove_backup_directory($backup['path']);
            }

            $this->current_backup_chain = array_slice($this->current_backup_chain, - $max_backups);
        }
    }
}

Point-in-Time Recovery

Version Selection Interface

function render_point_in_time_recovery_interface() {
    $backup_chains = get_option('hourly_backup_chains', array());

    echo '<div class="pit-recovery-interface">';
    echo '<h3>Point-in-Time Recovery</h3>';

    foreach ($backup_chains as $chain) {
        echo '<div class="backup-chain">';
        echo '<h4>Backup Chain: ' . esc_html($chain['name']) . '</h4>';

        if (!empty($chain['versions'])) {
            echo '<ul class="backup-versions">';
            foreach ($chain['versions'] as $version) {
                $timestamp = date('M j, Y H:i:s', $version['timestamp']);
                $size = size_format($version['size']);
                $changes = count($version['changes']);

                echo '<li class="backup-version">';
                echo '<input type="radio" name="restore_version" value="' . esc_attr($version['id']) . '" id="' . esc_attr($version['id']) . '">';
                echo '<label for="' . esc_attr($version['id']) . '">';
                echo '<strong>' . esc_html($timestamp) . '</strong><br>';
                echo '<small>Size: ' . esc_html($size) . ' | Changes: ' . esc_html($changes) . '</small>';
                echo '</label>';
                echo '</li>';
            }
            echo '</ul>';
        }

        echo '</div>';
    }

    echo '<div class="recovery-actions">';
    echo '<button type="button" class="button button-primary" id="preview-recovery">Preview Recovery</button>';
    echo '<button type="button" class="button" id="execute-recovery">Execute Recovery</button>';
    echo '</div>';

    echo '</div>';
}

Granular Recovery Options

function execute_point_in_time_recovery($version_id, $recovery_options = array()) {
    $version_info = get_backup_version_info($version_id);

    if (!$version_info) {
        return new WP_Error('version_not_found', 'Backup version not found.');
    }

    $recovery_result = array(
        'version_id' => $version_id,
        'timestamp' => $version_info['timestamp'],
        'components_restored' => array(),
        'errors' => array()
    );

    // Determine what to restore based on options
    $components_to_restore = $recovery_options['components'] ?? array('database', 'files');

    foreach ($components_to_restore as $component) {
        try {
            $result = $this->restore_component_from_version($component, $version_info);

            if ($result['success']) {
                $recovery_result['components_restored'][] = $component;
            } else {
                $recovery_result['errors'][] = "Failed to restore {$component}: " . $result['error'];
            }
        } catch (Exception $e) {
            $recovery_result['errors'][] = "Exception restoring {$component}: " . $e->getMessage();
        }
    }

    // Log recovery operation
    log_recovery_operation($recovery_result);

    return $recovery_result;
}

private function restore_component_from_version($component, $version_info) {
    $backup_path = $version_info['path'];

    switch ($component) {
        case 'database':
            return $this->restore_database_from_version($backup_path);
        case 'themes':
            return $this->restore_directory_from_version($backup_path . 'themes/', get_theme_root());
        case 'plugins':
            return $this->restore_directory_from_version($backup_path . 'plugins/', WP_PLUGIN_DIR);
        case 'uploads':
            return $this->restore_directory_from_version($backup_path . 'uploads/', wp_upload_dir()['basedir']);
        case 'config':
            return $this->restore_file_from_version($backup_path . 'wp-config.php', ABSPATH . 'wp-config.php');
        default:
            return array('success' => false, 'error' => 'Unknown component: ' . $component);
    }
}

Advanced Monitoring

Real-Time Backup Status

class HourlyBackupMonitor {
    private $status_file;
    private $metrics_file;

    public function __construct() {
        $this->status_file = WP_CONTENT_DIR . '/hourly-backup-status.json';
        $this->metrics_file = WP_CONTENT_DIR . '/hourly-backup-metrics.json';
    }

    public function update_backup_status($status, $details = array()) {
        $status_data = array(
            'status' => $status,
            'timestamp' => time(),
            'details' => $details,
            'server_load' => sys_getloadavg(),
            'memory_usage' => memory_get_peak_usage(true),
            'disk_usage' => disk_free_space(ABSPATH)
        );

        file_put_contents($this->status_file, wp_json_encode($status_data, JSON_PRETTY_PRINT));
    }

    public function get_backup_status() {
        if (!file_exists($this->status_file)) {
            return array('status' => 'unknown', 'timestamp' => 0);
        }

        $status_data = json_decode(file_get_contents($this->status_file), true);

        // Add human-readable time
        $status_data['time_ago'] = human_time_diff($status_data['timestamp']);

        return $status_data;
    }

    public function record_backup_metrics($backup_id, $metrics) {
        $existing_metrics = array();

        if (file_exists($this->metrics_file)) {
            $existing_metrics = json_decode(file_get_contents($this->metrics_file), true);
        }

        $existing_metrics[$backup_id] = array_merge($metrics, array(
            'recorded_at' => time(),
            'backup_id' => $backup_id
        ));

        // Keep only last 100 entries
        if (count($existing_metrics) > 100) {
            $existing_metrics = array_slice($existing_metrics, -100, null, true);
        }

        file_put_contents($this->metrics_file, wp_json_encode($existing_metrics, JSON_PRETTY_PRINT));
    }

    public function get_backup_metrics($limit = 10) {
        if (!file_exists($this->metrics_file)) {
            return array();
        }

        $metrics = json_decode(file_get_contents($this->metrics_file), true);

        // Sort by recorded time, newest first
        uasort($metrics, function($a, $b) {
            return $b['recorded_at'] - $a['recorded_at'];
        });

        return array_slice($metrics, 0, $limit, true);
    }
}

Dashboard Integration

Real-Time Status Widget

function add_hourly_backup_dashboard_widget() {
    wp_add_dashboard_widget(
        'hourly_backup_status',
        'Hourly Backup Status',
        'render_hourly_backup_status_widget'
    );
}

function render_hourly_backup_status_widget() {
    $monitor = new HourlyBackupMonitor();
    $status = $monitor->get_backup_status();
    $metrics = $monitor->get_backup_metrics(5);

    echo '<div class="hourly-backup-status-widget">';

    // Current status
    $status_class = 'status-' . $status['status'];
    echo '<div class="backup-status ' . esc_attr($status_class) . '">';
    echo '<strong>Status:</strong> ' . esc_html(ucfirst($status['status']));
    if (isset($status['time_ago'])) {
        echo ' <small>(' . esc_html($status['time_ago']) . ' ago)</small>';
    }
    echo '</div>';

    // Server metrics
    if (isset($status['server_load'])) {
        echo '<div class="server-metrics">';
        echo '<strong>Server Load:</strong> ' . esc_html(implode(', ', array_map(function($load) {
            return number_format($load, 2);
        }, $status['server_load'])));
        echo '</div>';
    }

    // Recent backups
    if (!empty($metrics)) {
        echo '<div class="recent-backups">';
        echo '<h4>Recent Backups</h4>';
        echo '<ul>';

        foreach ($metrics as $backup_id => $metric) {
            $duration = isset($metric['duration']) ? number_format($metric['duration'], 1) . 's' : 'N/A';
            $size = isset($metric['size']) ? size_format($metric['size']) : 'N/A';

            echo '<li>';
            echo '<strong>' . esc_html(date('M j H:i', $metric['recorded_at'])) . '</strong>';
            echo '<small> - ' . esc_html($duration) . ', ' . esc_html($size) . '</small>';
            echo '</li>';
        }

        echo '</ul>';
        echo '</div>';
    }

    echo '</div>';
}
add_action('wp_dashboard_setup', 'add_hourly_backup_dashboard_widget');

Enterprise Features

Multi-Site Support

class HourlyBackupMultiSite {
    private $sites_backup_status = array();

    public function backup_all_sites() {
        if (!is_multisite()) {
            return new WP_Error('not_multisite', 'Multi-site support required.');
        }

        $sites = get_sites();
        $results = array();

        foreach ($sites as $site) {
            switch_to_blog($site->blog_id);

            $site_result = $this->backup_single_site($site);
            $results[$site->blog_id] = $site_result;

            restore_current_blog();
        }

        return $results;
    }

    private function backup_single_site($site) {
        // Implement single site backup logic
        $backup_result = create_hourly_backup_for_site($site->blog_id);

        $this->sites_backup_status[$site->blog_id] = array(
            'last_backup' => time(),
            'status' => $backup_result['success'] ? 'success' : 'failed',
            'site_id' => $site->blog_id,
            'site_url' => get_site_url($site->blog_id)
        );

        return $backup_result;
    }

    public function get_sites_backup_status() {
        return $this->sites_backup_status;
    }
}

Cloud Integration

class HourlyBackupCloudIntegration {
    private $cloud_providers = array();

    public function __construct() {
        $this->cloud_providers = array(
            'aws' => new HourlyBackupAWSProvider(),
            'gcp' => new HourlyBackupGCPProvider(),
            'azure' => new HourlyBackupAzureProvider()
        );
    }

    public function upload_to_cloud($backup_path, $provider = 'aws') {
        if (!isset($this->cloud_providers[$provider])) {
            return new WP_Error('invalid_provider', 'Invalid cloud provider specified.');
        }

        $provider_instance = $this->cloud_providers[$provider];

        try {
            $upload_result = $provider_instance->upload_backup($backup_path);

            // Log successful upload
            log_cloud_upload($provider, $backup_path, $upload_result);

            return $upload_result;
        } catch (Exception $e) {
            // Log upload failure
            log_cloud_upload_error($provider, $backup_path, $e->getMessage());

            return new WP_Error('upload_failed', $e->getMessage());
        }
    }

    public function download_from_cloud($backup_id, $provider = 'aws') {
        if (!isset($this->cloud_providers[$provider])) {
            return new WP_Error('invalid_provider', 'Invalid cloud provider specified.');
        }

        $provider_instance = $this->cloud_providers[$provider];

        try {
            $download_result = $provider_instance->download_backup($backup_id);

            return $download_result;
        } catch (Exception $e) {
            return new WP_Error('download_failed', $e->getMessage());
        }
    }
}

Performance Optimization

Resource Management

class HourlyBackupResourceManager {
    private $cpu_limit;
    private $memory_limit;
    private $io_limit;

    public function __construct() {
        $this->cpu_limit = get_option('hourly_backup_cpu_limit', 30);
        $this->memory_limit = get_option('hourly_backup_memory_limit', 128);
        $this->io_limit = get_option('hourly_backup_io_limit', 50);
    }

    public function can_run_backup() {
        // Check CPU usage
        $cpu_usage = $this->get_cpu_usage();
        if ($cpu_usage > $this->cpu_limit) {
            return false;
        }

        // Check memory usage
        $memory_usage = memory_get_peak_usage(true) / 1024 / 1024; // MB
        if ($memory_usage > $this->memory_limit) {
            return false;
        }

        // Check I/O usage
        $io_usage = $this->get_io_usage();
        if ($io_usage > $this->io_limit) {
            return false;
        }

        // Check concurrent backups
        $concurrent_backups = $this->get_concurrent_backup_count();
        $max_concurrent = get_option('hourly_backup_max_concurrent', 2);
        if ($concurrent_backups >= $max_concurrent) {
            return false;
        }

        return true;
    }

    private function get_cpu_usage() {
        if (function_exists('sys_getloadavg')) {
            $load = sys_getloadavg();
            return $load[0] * 100; // Convert to percentage
        }
        return 0;
    }

    private function get_io_usage() {
        // Implement I/O usage monitoring
        // This would require system-specific tools
        return 0; // Placeholder
    }

    private function get_concurrent_backup_count() {
        global $wpdb;
        $count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE 'backup_in_progress_%'");
        return intval($count);
    }
}

Security Features

Backup Encryption

class HourlyBackupEncryption {
    private $encryption_key;
    private $cipher = 'AES-256-CBC';

    public function __construct() {
        $this->encryption_key = get_option('hourly_backup_encryption_key');
        if (!$this->encryption_key) {
            $this->encryption_key = wp_generate_password(32, true, true);
            update_option('hourly_backup_encryption_key', $this->encryption_key);
        }
    }

    public function encrypt_backup($backup_path) {
        $backup_content = file_get_contents($backup_path);

        if (!$backup_content) {
            return new WP_Error('read_failed', 'Failed to read backup file.');
        }

        // Generate initialization vector
        $iv = openssl_random_pseudo_bytes(16);

        // Encrypt content
        $encrypted = openssl_encrypt(
            $backup_content,
            $this->cipher,
            $this->encryption_key,
            0,
            $iv
        );

        if ($encrypted === false) {
            return new WP_Error('encryption_failed', 'Failed to encrypt backup.');
        }

        // Combine IV and encrypted content
        $encrypted_with_iv = $iv . $encrypted;

        // Save encrypted backup
        $encrypted_path = $backup_path . '.encrypted';
        $result = file_put_contents($encrypted_path, $encrypted_with_iv);

        if ($result === false) {
            return new WP_Error('write_failed', 'Failed to write encrypted backup.');
        }

        // Remove original unencrypted file
        unlink($backup_path);

        return $encrypted_path;
    }

    public function decrypt_backup($encrypted_path) {
        $encrypted_content = file_get_contents($encrypted_path);

        if (!$encrypted_content) {
            return new WP_Error('read_failed', 'Failed to read encrypted backup.');
        }

        // Extract IV and encrypted content
        $iv = substr($encrypted_content, 0, 16);
        $encrypted = substr($encrypted_content, 16);

        // Decrypt content
        $decrypted = openssl_decrypt(
            $encrypted,
            $this->cipher,
            $this->encryption_key,
            0,
            $iv
        );

        if ($decrypted === false) {
            return new WP_Error('decryption_failed', 'Failed to decrypt backup.');
        }

        return $decrypted;
    }
}

Best Practices

Performance Best Practices

  1. Smart Scheduling: Schedule backups during low-traffic periods
  2. Resource Monitoring: Monitor system resources during backup operations
  3. Incremental Backups: Use incremental backups to reduce resource usage
  4. Compression: Compress backups to minimize storage requirements
  5. Cleanup: Regularly clean up old backup versions

Security Best Practices

  1. Encryption: Always encrypt sensitive backup data
  2. Access Control: Limit access to backup files and settings
  3. Secure Storage: Use secure storage locations for backups
  4. Regular Audits: Audit backup integrity and security
  5. Monitoring: Monitor backup operations for anomalies

Reliability Best Practices

  1. Redundancy: Store backups in multiple locations
  2. Testing: Regularly test backup restoration
  3. Monitoring: Monitor backup success and failures
  4. Documentation: Document backup procedures and policies
  5. Training: Train staff on backup procedures

Enterprise-grade hourly backup solution with real-time protection and advanced features.

On this page