tigerstyle-heat/admin/pages/backup-restore.php
Ryan Malloy 0028738e33 Initial commit: TigerStyle Heat v2.0.0
Make your WordPress site irresistible. Natural SEO attraction with:
- robots.txt management
- sitemap.xml generation
- LLMs.txt support
- Google integration (Analytics, Search Console, Tag Manager)
- Schema.org structured data
- Open Graph / Twitter Card meta tags
- AMP support
- Visual elements gallery
- Built-in backup/restore module

Includes build.sh and .distignore for WordPress-installable release ZIPs.
2026-05-27 13:41:35 -06:00

1442 lines
58 KiB
PHP

<?php
/**
* Backup & Restore Admin Page
*
* Enterprise-grade backup and restore interface with progress tracking,
* advanced options, and comprehensive management features.
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Get backup module instance
$backup_module = tigerstyle_heat()->get_module('backup_restore');
$settings = $backup_module->get_backup_settings();
$backups = $backup_module->get_backup_list();
$compression_methods = $backup_module->get_available_compression_methods();
// Get storage stats
$storage_manager = TigerStyleSEO_Storage_Manager::instance();
$storage_stats = $storage_manager->get_storage_stats();
// Get scheduler status (check if class exists first)
$schedule_status = array();
if (class_exists('TigerStyleSEO_Backup_Scheduler')) {
$scheduler = new TigerStyleSEO_Backup_Scheduler();
$schedule_status = $scheduler->get_schedule_status();
}
?>
<div class="tigerstyle-backup-restore">
<h2><?php _e('Backup & Restore', 'tigerstyle-heat'); ?></h2>
<!-- Statistics Dashboard -->
<div class="backup-dashboard">
<div class="stats-cards">
<div class="stat-card">
<h3><?php _e('Total Backups', 'tigerstyle-heat'); ?></h3>
<div class="stat-value"><?php echo esc_html($storage_stats['total_backups'] ?? 0); ?></div>
</div>
<div class="stat-card">
<h3><?php _e('Storage Used', 'tigerstyle-heat'); ?></h3>
<div class="stat-value"><?php echo esc_html($storage_stats['total_size_formatted'] ?? '0 B'); ?></div>
</div>
<div class="stat-card">
<h3><?php _e('Last Backup', 'tigerstyle-heat'); ?></h3>
<div class="stat-value">
<?php if (isset($storage_stats['newest_backup'])): ?>
<?php echo esc_html(mysql2date(get_option('date_format'), $storage_stats['newest_backup'])); ?>
<?php else: ?>
<?php _e('Never', 'tigerstyle-heat'); ?>
<?php endif; ?>
</div>
</div>
<div class="stat-card">
<h3><?php _e('Next Scheduled', 'tigerstyle-heat'); ?></h3>
<div class="stat-value">
<?php if ($schedule_status['enabled'] && $schedule_status['next_run']): ?>
<?php echo esc_html($schedule_status['next_run']['human']); ?>
<?php else: ?>
<?php _e('Not scheduled', 'tigerstyle-heat'); ?>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- Tab Navigation -->
<div class="nav-tab-wrapper backup-tabs">
<a href="#create-backup" class="nav-tab nav-tab-active"><?php _e('Create Backup', 'tigerstyle-heat'); ?></a>
<a href="#manage-backups" class="nav-tab"><?php _e('Manage Backups', 'tigerstyle-heat'); ?></a>
<a href="#restore" class="nav-tab"><?php _e('Restore', 'tigerstyle-heat'); ?></a>
<a href="#settings" class="nav-tab"><?php _e('Settings', 'tigerstyle-heat'); ?></a>
<a href="#advanced" class="nav-tab"><?php _e('Advanced', 'tigerstyle-heat'); ?></a>
<a href="#logs" class="nav-tab"><?php _e('Logs', 'tigerstyle-heat'); ?></a>
</div>
<!-- Create Backup Tab -->
<div id="create-backup" class="tab-content active">
<div class="backup-section">
<h3><?php _e('Create New Backup', 'tigerstyle-heat'); ?></h3>
<form id="create-backup-form" class="backup-form">
<?php wp_nonce_field('tigerstyle_backup_action', 'tigerstyle_backup_nonce'); ?>
<div class="form-row">
<div class="form-group">
<label for="backup_type"><?php _e('Backup Type', 'tigerstyle-heat'); ?></label>
<select id="backup_type" name="backup_type">
<option value="full"><?php _e('Full Backup (Files + Database)', 'tigerstyle-heat'); ?></option>
<option value="files_only"><?php _e('Files Only', 'tigerstyle-heat'); ?></option>
<option value="database_only"><?php _e('Database Only', 'tigerstyle-heat'); ?></option>
</select>
</div>
<div class="form-group">
<label for="compression"><?php _e('Compression', 'tigerstyle-heat'); ?></label>
<select id="compression" name="compression">
<?php foreach ($compression_methods as $method => $name): ?>
<option value="<?php echo esc_attr($method); ?>" <?php selected($settings['compression'], $method); ?>>
<?php echo esc_html($name); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="storage_location"><?php _e('Storage Location', 'tigerstyle-heat'); ?></label>
<select id="storage_location" name="storage_location">
<option value="local" <?php selected($settings['storage_location'], 'local'); ?>><?php _e('Local Storage', 'tigerstyle-heat'); ?></option>
<?php if (!empty($settings['s3_bucket'])): ?>
<option value="s3" <?php selected($settings['storage_location'], 's3'); ?>><?php _e('S3 Compatible Storage', 'tigerstyle-heat'); ?></option>
<?php endif; ?>
</select>
</div>
<div class="form-group">
<label for="backup_description"><?php _e('Description (Optional)', 'tigerstyle-heat'); ?></label>
<input type="text" id="backup_description" name="description" placeholder="<?php esc_attr_e('Backup before site update', 'tigerstyle-heat'); ?>">
</div>
</div>
<div class="advanced-options" style="display: none;">
<h4><?php _e('Advanced Options', 'tigerstyle-heat'); ?></h4>
<label class="checkbox-label">
<input type="checkbox" name="include_uploads" checked>
<?php _e('Include wp-content/uploads directory', 'tigerstyle-heat'); ?>
</label>
<label class="checkbox-label">
<input type="checkbox" name="include_themes" checked>
<?php _e('Include themes', 'tigerstyle-heat'); ?>
</label>
<label class="checkbox-label">
<input type="checkbox" name="include_plugins" checked>
<?php _e('Include plugins', 'tigerstyle-heat'); ?>
</label>
<label class="checkbox-label">
<input type="checkbox" name="exclude_cache">
<?php _e('Exclude cache files', 'tigerstyle-heat'); ?>
</label>
</div>
<div class="form-actions">
<button type="button" class="button" id="toggle-advanced"><?php _e('Advanced Options', 'tigerstyle-heat'); ?></button>
<button type="submit" class="button-primary" id="create-backup-btn">
<span class="dashicons dashicons-backup"></span>
<?php _e('Create Backup', 'tigerstyle-heat'); ?>
</button>
</div>
</form>
<!-- Progress Display -->
<div id="backup-progress" style="display: none;">
<h4><?php _e('Backup Progress', 'tigerstyle-heat'); ?></h4>
<div class="progress-bar">
<div class="progress-fill"></div>
<div class="progress-text">0%</div>
</div>
<div class="progress-message"><?php _e('Initializing backup...', 'tigerstyle-heat'); ?></div>
<div class="progress-details">
<div class="detail-item">
<span class="label"><?php _e('Backup ID:', 'tigerstyle-heat'); ?></span>
<span class="value" id="backup-id-display">-</span>
</div>
<div class="detail-item">
<span class="label"><?php _e('Started:', 'tigerstyle-heat'); ?></span>
<span class="value" id="backup-start-time">-</span>
</div>
<div class="detail-item">
<span class="label"><?php _e('Estimated Time:', 'tigerstyle-heat'); ?></span>
<span class="value" id="backup-eta">-</span>
</div>
</div>
</div>
</div>
</div>
<!-- Manage Backups Tab -->
<div id="manage-backups" class="tab-content">
<div class="backup-section">
<h3><?php _e('Backup List', 'tigerstyle-heat'); ?></h3>
<div class="backup-filters">
<select id="backup-filter-storage">
<option value=""><?php _e('All Storage Locations', 'tigerstyle-heat'); ?></option>
<option value="local"><?php _e('Local Storage', 'tigerstyle-heat'); ?></option>
<option value="s3"><?php _e('S3 Compatible Storage', 'tigerstyle-heat'); ?></option>
</select>
<input type="text" id="backup-search" placeholder="<?php esc_attr_e('Search backups...', 'tigerstyle-heat'); ?>">
<button type="button" class="button" id="refresh-backups">
<span class="dashicons dashicons-update"></span>
<?php _e('Refresh', 'tigerstyle-heat'); ?>
</button>
</div>
<div class="backup-list">
<?php if (empty($backups)): ?>
<div class="no-backups">
<span class="dashicons dashicons-backup"></span>
<p><?php _e('No backups found. Create your first backup to get started.', 'tigerstyle-heat'); ?></p>
</div>
<?php else: ?>
<div class="backup-table">
<div class="backup-header">
<div class="col-backup-id"><?php _e('Backup ID', 'tigerstyle-heat'); ?></div>
<div class="col-date"><?php _e('Created', 'tigerstyle-heat'); ?></div>
<div class="col-size"><?php _e('Size', 'tigerstyle-heat'); ?></div>
<div class="col-type"><?php _e('Type', 'tigerstyle-heat'); ?></div>
<div class="col-storage"><?php _e('Storage', 'tigerstyle-heat'); ?></div>
<div class="col-actions"><?php _e('Actions', 'tigerstyle-heat'); ?></div>
</div>
<?php foreach ($backups as $backup): ?>
<div class="backup-row" data-backup-id="<?php echo esc_attr($backup['backup_id']); ?>">
<div class="col-backup-id">
<strong><?php echo esc_html(substr($backup['backup_id'], 0, 16)); ?>...</strong>
<?php if (!empty($backup['description'])): ?>
<div class="backup-description"><?php echo esc_html($backup['description']); ?></div>
<?php endif; ?>
</div>
<div class="col-date">
<?php echo esc_html($backup['created_at_formatted'] ?? ($backup['created_at'] ?? 'Unknown')); ?>
<div class="age"><?php echo esc_html($backup['age'] ?? ''); ?> <?php if (!empty($backup['age'])): ?><?php _e('ago', 'tigerstyle-heat'); ?><?php endif; ?></div>
</div>
<div class="col-size"><?php echo esc_html($backup['file_size_formatted'] ?? (isset($backup['file_size']) ? size_format($backup['file_size']) : 'Unknown')); ?></div>
<div class="col-type">
<span class="backup-type-badge"><?php echo esc_html($backup['type'] ?? 'full'); ?></span>
</div>
<div class="col-storage">
<span class="storage-badge <?php echo esc_attr($backup['storage_type'] ?? 'local'); ?>">
<?php echo esc_html(strtoupper($backup['storage_type'] ?? 'LOCAL')); ?>
</span>
</div>
<div class="col-actions">
<?php if (!empty($backup['backup_id'])): ?>
<button type="button" class="button button-small restore-backup"
data-backup-id="<?php echo esc_attr($backup['backup_id']); ?>">
<span class="dashicons dashicons-update"></span>
<?php _e('Restore', 'tigerstyle-heat'); ?>
</button>
<button type="button" class="button button-small download-backup"
data-backup-id="<?php echo esc_attr($backup['backup_id']); ?>">
<span class="dashicons dashicons-download"></span>
<?php _e('Download', 'tigerstyle-heat'); ?>
</button>
<button type="button" class="button button-small validate-backup"
data-backup-id="<?php echo esc_attr($backup['backup_id']); ?>">
<span class="dashicons dashicons-yes-alt"></span>
<?php _e('Validate', 'tigerstyle-heat'); ?>
</button>
<button type="button" class="button button-small button-link-delete delete-backup"
data-backup-id="<?php echo esc_attr($backup['backup_id']); ?>">
<span class="dashicons dashicons-trash"></span>
<?php _e('Delete', 'tigerstyle-heat'); ?>
<?php else: ?>
<span class="backup-error"><?php _e('Invalid backup data', 'tigerstyle-heat'); ?></span>
<?php endif; ?>
</button>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<!-- Restore Tab -->
<div id="restore" class="tab-content">
<div class="backup-section">
<h3><?php _e('Restore from Backup', 'tigerstyle-heat'); ?></h3>
<div class="restore-warning">
<span class="dashicons dashicons-warning"></span>
<p><?php _e('Restoring from backup will overwrite your current website. This action cannot be undone. Please create a backup before proceeding.', 'tigerstyle-heat'); ?></p>
</div>
<form id="restore-form" class="backup-form">
<?php wp_nonce_field('tigerstyle_backup_action', 'tigerstyle_restore_nonce'); ?>
<div class="form-group">
<label for="restore_backup_id"><?php _e('Select Backup to Restore', 'tigerstyle-heat'); ?></label>
<select id="restore_backup_id" name="backup_id" required>
<option value=""><?php _e('Choose a backup...', 'tigerstyle-heat'); ?></option>
<?php foreach ($backups as $backup): ?>
<option value="<?php echo esc_attr($backup['backup_id']); ?>">
<?php echo esc_html(substr($backup['backup_id'], 0, 16)); ?>... -
<?php echo esc_html(isset($backup['created_at_formatted']) ? $backup['created_at_formatted'] : $backup['created_at']); ?>
(<?php echo esc_html(isset($backup['file_size_formatted']) ? $backup['file_size_formatted'] : ($backup['file_size'] ? size_format($backup['file_size']) : 'Unknown')); ?>)
</option>
<?php endforeach; ?>
</select>
</div>
<div class="restore-options">
<h4><?php _e('Restore Options', 'tigerstyle-heat'); ?></h4>
<label class="checkbox-label">
<input type="checkbox" name="restore_files" checked>
<?php _e('Restore Files', 'tigerstyle-heat'); ?>
</label>
<label class="checkbox-label">
<input type="checkbox" name="restore_database" checked>
<?php _e('Restore Database', 'tigerstyle-heat'); ?>
</label>
<label class="checkbox-label">
<input type="checkbox" name="create_rollback" checked>
<?php _e('Create rollback backup before restore', 'tigerstyle-heat'); ?>
</label>
<label class="checkbox-label">
<input type="checkbox" name="validate_before_restore" checked>
<?php _e('Validate backup integrity before restore', 'tigerstyle-heat'); ?>
</label>
</div>
<div class="confirmation-section" style="display: none;">
<h4><?php _e('Confirmation Required', 'tigerstyle-heat'); ?></h4>
<p><?php _e('Type "CONFIRM RESTORE" to proceed with the restoration:', 'tigerstyle-heat'); ?></p>
<input type="text" id="restore_confirmation" placeholder="<?php esc_attr_e('Type confirmation here...', 'tigerstyle-heat'); ?>" required>
</div>
<div class="form-actions">
<button type="button" class="button" id="show-restore-confirmation">
<?php _e('Prepare Restore', 'tigerstyle-heat'); ?>
</button>
<button type="submit" class="button-primary" id="restore-backup-btn" style="display: none;">
<span class="dashicons dashicons-update"></span>
<?php _e('Restore Now', 'tigerstyle-heat'); ?>
</button>
</div>
</form>
<!-- Restore Progress -->
<div id="restore-progress" style="display: none;">
<h4><?php _e('Restore Progress', 'tigerstyle-heat'); ?></h4>
<div class="progress-bar">
<div class="progress-fill"></div>
<div class="progress-text">0%</div>
</div>
<div class="progress-message"><?php _e('Initializing restore...', 'tigerstyle-heat'); ?></div>
</div>
</div>
</div>
<!-- Settings Tab -->
<div id="settings" class="tab-content">
<div class="backup-section">
<h3><?php _e('Backup Settings', 'tigerstyle-heat'); ?></h3>
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>" class="backup-settings-form">
<?php wp_nonce_field('tigerstyle_backup_settings', 'tigerstyle_backup_nonce'); ?>
<input type="hidden" name="action" value="tigerstyle_backup_settings">
<!-- General Settings -->
<div class="settings-section">
<h4><?php _e('General Settings', 'tigerstyle-heat'); ?></h4>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Default Compression', 'tigerstyle-heat'); ?></th>
<td>
<select name="compression">
<?php foreach ($compression_methods as $method => $name): ?>
<option value="<?php echo esc_attr($method); ?>" <?php selected($settings['compression'], $method); ?>>
<?php echo esc_html($name); ?>
</option>
<?php endforeach; ?>
</select>
<p class="description"><?php _e('Default compression method for new backups.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Default Storage Location', 'tigerstyle-heat'); ?></th>
<td>
<select name="storage_location">
<option value="local" <?php selected($settings['storage_location'], 'local'); ?>><?php _e('Local Storage', 'tigerstyle-heat'); ?></option>
<option value="s3" <?php selected($settings['storage_location'], 's3'); ?>><?php _e('S3 Compatible Storage', 'tigerstyle-heat'); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Chunk Size (MB)', 'tigerstyle-heat'); ?></th>
<td>
<input type="number" name="chunk_size" value="<?php echo esc_attr($settings['chunk_size']); ?>" min="1" max="50">
<p class="description"><?php _e('Size of file chunks for processing large backups.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Backup Retention', 'tigerstyle-heat'); ?></th>
<td>
<input type="number" name="retention_days" value="<?php echo esc_attr($settings['retention_days']); ?>" min="0">
<span><?php _e('days (0 = unlimited)', 'tigerstyle-heat'); ?></span>
<p class="description"><?php _e('Automatically delete backups older than this many days.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
</table>
</div>
<!-- Scheduled Backups -->
<div class="settings-section">
<h4><?php _e('Scheduled Backups', 'tigerstyle-heat'); ?></h4>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Enable Scheduled Backups', 'tigerstyle-heat'); ?></th>
<td>
<label>
<input type="checkbox" name="schedule_enabled" value="1" <?php checked($settings['schedule_enabled']); ?>>
<?php _e('Automatically create backups on schedule', 'tigerstyle-heat'); ?>
</label>
</td>
</tr>
<tr class="schedule-option">
<th scope="row"><?php _e('Backup Frequency', 'tigerstyle-heat'); ?></th>
<td>
<select name="schedule_frequency">
<option value="hourly" <?php selected($settings['schedule_frequency'], 'hourly'); ?>><?php _e('Hourly', 'tigerstyle-heat'); ?></option>
<option value="daily" <?php selected($settings['schedule_frequency'], 'daily'); ?>><?php _e('Daily', 'tigerstyle-heat'); ?></option>
<option value="weekly" <?php selected($settings['schedule_frequency'], 'weekly'); ?>><?php _e('Weekly', 'tigerstyle-heat'); ?></option>
<option value="monthly" <?php selected($settings['schedule_frequency'], 'monthly'); ?>><?php _e('Monthly', 'tigerstyle-heat'); ?></option>
</select>
</td>
</tr>
<tr class="schedule-option">
<th scope="row"><?php _e('Backup What', 'tigerstyle-heat'); ?></th>
<td>
<label>
<input type="checkbox" name="include_files" value="1" <?php checked($settings['include_files']); ?>>
<?php _e('Include Files', 'tigerstyle-heat'); ?>
</label><br>
<label>
<input type="checkbox" name="include_database" value="1" <?php checked($settings['include_database']); ?>>
<?php _e('Include Database', 'tigerstyle-heat'); ?>
</label>
</td>
</tr>
</table>
</div>
<!-- S3 Storage Settings -->
<div class="settings-section">
<h4><?php _e('S3 Compatible Storage', 'tigerstyle-heat'); ?></h4>
<table class="form-table">
<tr>
<th scope="row"><?php _e('S3 Bucket', 'tigerstyle-heat'); ?></th>
<td>
<input type="text" name="s3_bucket" value="<?php echo esc_attr($settings['s3_bucket']); ?>" class="regular-text">
</td>
</tr>
<tr>
<th scope="row"><?php _e('Access Key ID', 'tigerstyle-heat'); ?></th>
<td>
<input type="text" name="s3_access_key" value="<?php echo esc_attr($settings['s3_access_key']); ?>" class="regular-text">
</td>
</tr>
<tr>
<th scope="row"><?php _e('Secret Access Key', 'tigerstyle-heat'); ?></th>
<td>
<input type="password" name="s3_secret_key" value="<?php echo esc_attr($settings['s3_secret_key']); ?>" class="regular-text">
</td>
</tr>
<tr>
<th scope="row"><?php _e('Region', 'tigerstyle-heat'); ?></th>
<td>
<input type="text" name="s3_region" value="<?php echo esc_attr($settings['s3_region']); ?>" class="regular-text" placeholder="us-east-1">
</td>
</tr>
<tr>
<th scope="row"><?php _e('Custom Endpoint', 'tigerstyle-heat'); ?></th>
<td>
<input type="url" name="s3_endpoint" value="<?php echo esc_attr($settings['s3_endpoint']); ?>" class="regular-text" placeholder="https://s3.example.com">
<p class="description"><?php _e('For S3-compatible services like MinIO, DigitalOcean Spaces, etc.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Test Connection', 'tigerstyle-heat'); ?></th>
<td>
<button type="button" class="button" id="test-s3-connection">
<?php _e('Test S3 Connection', 'tigerstyle-heat'); ?>
</button>
<div id="s3-test-result"></div>
</td>
</tr>
</table>
</div>
<!-- Notification Settings -->
<div class="settings-section">
<h4><?php _e('Email Notifications', 'tigerstyle-heat'); ?></h4>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Enable Notifications', 'tigerstyle-heat'); ?></th>
<td>
<label>
<input type="checkbox" name="email_notifications" value="1" <?php checked($settings['email_notifications']); ?>>
<?php _e('Send email notifications for backup events', 'tigerstyle-heat'); ?>
</label>
</td>
</tr>
<tr class="notification-option">
<th scope="row"><?php _e('Notification Email', 'tigerstyle-heat'); ?></th>
<td>
<input type="email" name="notification_email" value="<?php echo esc_attr($settings['notification_email']); ?>" class="regular-text">
</td>
</tr>
</table>
</div>
<?php submit_button(__('Save Settings', 'tigerstyle-heat')); ?>
</form>
</div>
</div>
<!-- Advanced Tab -->
<div id="advanced" class="tab-content">
<div class="backup-section">
<h3><?php _e('Advanced Operations', 'tigerstyle-heat'); ?></h3>
<!-- WordPress Reset -->
<div class="advanced-operation">
<h4><?php _e('WordPress Content Reset', 'tigerstyle-heat'); ?></h4>
<p><?php _e('Remove default WordPress posts, pages, and comments to prepare for a fresh restore.', 'tigerstyle-heat'); ?></p>
<div class="warning-box">
<span class="dashicons dashicons-warning"></span>
<p><?php _e('This will delete all posts, pages, and comments. A backup will be created automatically before reset.', 'tigerstyle-heat'); ?></p>
</div>
<form id="wordpress-reset-form">
<?php wp_nonce_field('tigerstyle_backup_action', 'tigerstyle_reset_nonce'); ?>
<p><?php _e('Type "RESET_WORDPRESS" to confirm:', 'tigerstyle-heat'); ?></p>
<input type="text" id="wordpress-reset-confirmation" placeholder="<?php esc_attr_e('Confirmation text...', 'tigerstyle-heat'); ?>" required>
<button type="submit" class="button button-delete" id="reset-wordpress-btn">
<?php _e('Reset WordPress Content', 'tigerstyle-heat'); ?>
</button>
</form>
</div>
<!-- Database Reset -->
<div class="advanced-operation">
<h4><?php _e('Complete Database Reset', 'tigerstyle-heat'); ?></h4>
<p><?php _e('Completely wipe the database. This is irreversible and should only be used for development.', 'tigerstyle-heat'); ?></p>
<div class="danger-box">
<span class="dashicons dashicons-dismiss"></span>
<p><?php _e('DANGER: This will completely delete all database tables. Your site will be completely broken until you restore from backup.', 'tigerstyle-heat'); ?></p>
</div>
<form id="database-reset-form">
<?php wp_nonce_field('tigerstyle_backup_action', 'tigerstyle_db_reset_nonce'); ?>
<div id="reset-code-section" style="display: none;">
<p><?php _e('Confirmation code:', 'tigerstyle-heat'); ?> <strong id="reset-code-display"></strong></p>
<p><?php _e('Enter the code shown above:', 'tigerstyle-heat'); ?></p>
<input type="text" id="database-reset-code" placeholder="<?php esc_attr_e('Enter confirmation code...', 'tigerstyle-heat'); ?>" required>
<p><?php _e('Type "YES_DELETE_EVERYTHING" to proceed:', 'tigerstyle-heat'); ?></p>
<input type="text" id="database-reset-final" placeholder="<?php esc_attr_e('Final confirmation...', 'tigerstyle-heat'); ?>" required>
<button type="submit" class="button button-delete" id="reset-database-btn">
<?php _e('DELETE DATABASE COMPLETELY', 'tigerstyle-heat'); ?>
</button>
</div>
<button type="button" class="button" id="generate-reset-code">
<?php _e('Generate Reset Code', 'tigerstyle-heat'); ?>
</button>
</form>
</div>
<!-- File Upload -->
<div class="advanced-operation">
<h4><?php _e('Upload Backup File', 'tigerstyle-heat'); ?></h4>
<p><?php _e('Upload a backup file from your computer to restore.', 'tigerstyle-heat'); ?></p>
<form id="upload-backup-form" enctype="multipart/form-data">
<?php wp_nonce_field('tigerstyle_backup_action', 'tigerstyle_upload_nonce'); ?>
<input type="file" id="backup-file-upload" name="backup_file" accept=".zip,.tar,.tar.gz,.tar.bz2" required>
<button type="submit" class="button">
<span class="dashicons dashicons-upload"></span>
<?php _e('Upload Backup', 'tigerstyle-heat'); ?>
</button>
</form>
<div id="upload-progress" style="display: none;">
<div class="progress-bar">
<div class="progress-fill"></div>
<div class="progress-text">0%</div>
</div>
</div>
</div>
</div>
</div>
<!-- Logs Tab -->
<div id="logs" class="tab-content">
<div class="backup-section">
<h3><?php _e('Backup Logs', 'tigerstyle-heat'); ?></h3>
<div class="log-filters">
<select id="log-level-filter">
<option value=""><?php _e('All Levels', 'tigerstyle-heat'); ?></option>
<option value="debug"><?php _e('Debug', 'tigerstyle-heat'); ?></option>
<option value="info"><?php _e('Info', 'tigerstyle-heat'); ?></option>
<option value="warning"><?php _e('Warning', 'tigerstyle-heat'); ?></option>
<option value="error"><?php _e('Error', 'tigerstyle-heat'); ?></option>
<option value="critical"><?php _e('Critical', 'tigerstyle-heat'); ?></option>
</select>
<button type="button" class="button" id="refresh-logs">
<span class="dashicons dashicons-update"></span>
<?php _e('Refresh', 'tigerstyle-heat'); ?>
</button>
<button type="button" class="button" id="export-logs">
<span class="dashicons dashicons-download"></span>
<?php _e('Export Logs', 'tigerstyle-heat'); ?>
</button>
<button type="button" class="button button-link-delete" id="clear-logs">
<span class="dashicons dashicons-trash"></span>
<?php _e('Clear Old Logs', 'tigerstyle-heat'); ?>
</button>
</div>
<div id="logs-container">
<div class="log-loading">
<span class="spinner is-active"></span>
<?php _e('Loading logs...', 'tigerstyle-heat'); ?>
</div>
</div>
</div>
</div>
</div>
<style>
/* Backup & Restore Styles */
.tigerstyle-backup-restore {
max-width: 1200px;
}
.backup-dashboard {
margin-bottom: 20px;
}
.stats-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
text-align: center;
}
.stat-card h3 {
margin: 0 0 10px 0;
font-size: 14px;
color: #666;
text-transform: uppercase;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #2271b1;
}
.backup-tabs {
margin-bottom: 0;
}
.tab-content {
display: none;
background: #fff;
border: 1px solid #ccd0d4;
border-top: none;
padding: 20px;
}
.tab-content.active {
display: block;
}
.backup-section {
margin-bottom: 30px;
}
.backup-form {
max-width: 600px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-group label {
margin-bottom: 5px;
font-weight: 600;
}
.form-group input,
.form-group select {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
}
.advanced-options {
margin: 20px 0;
padding: 15px;
background: #f9f9f9;
border-radius: 4px;
}
.checkbox-label {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.checkbox-label input {
margin-right: 8px;
}
.form-actions {
display: flex;
gap: 10px;
align-items: center;
}
.progress-bar {
position: relative;
width: 100%;
height: 30px;
background: #f0f0f0;
border-radius: 4px;
overflow: hidden;
margin: 10px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #2271b1, #72aee6);
transition: width 0.3s ease;
width: 0%;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
color: #333;
}
.progress-details {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 15px;
}
.detail-item {
display: flex;
justify-content: space-between;
}
.detail-item .label {
font-weight: 600;
}
.backup-filters {
display: flex;
gap: 10px;
margin-bottom: 15px;
align-items: center;
}
.backup-filters input,
.backup-filters select {
padding: 6px 10px;
}
.no-backups {
text-align: center;
padding: 40px;
color: #666;
}
.no-backups .dashicons {
font-size: 48px;
margin-bottom: 10px;
opacity: 0.5;
}
.backup-table {
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;
}
.backup-header,
.backup-row {
display: grid;
grid-template-columns: 2fr 1.5fr 1fr 1fr 1fr 2fr;
gap: 15px;
padding: 15px;
align-items: center;
}
.backup-header {
background: #f9f9f9;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.backup-row {
border-bottom: 1px solid #eee;
}
.backup-row:last-child {
border-bottom: none;
}
.backup-row:hover {
background: #f9f9f9;
}
.backup-description {
font-size: 12px;
color: #666;
font-style: italic;
}
.age {
font-size: 12px;
color: #666;
}
.backup-type-badge,
.storage-badge {
padding: 4px 8px;
border-radius: 3px;
font-size: 11px;
font-weight: bold;
text-transform: uppercase;
}
.backup-type-badge {
background: #e1f5fe;
color: #0277bd;
}
.storage-badge.local {
background: #e8f5e8;
color: #2e7d32;
}
.storage-badge.s3 {
background: #fff3e0;
color: #ef6c00;
}
.col-actions {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.restore-warning,
.warning-box {
background: #fff2cd;
border: 1px solid #f0ad4e;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
display: flex;
align-items: flex-start;
gap: 10px;
}
.danger-box {
background: #f8d7da;
border: 1px solid #dc3545;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
display: flex;
align-items: flex-start;
gap: 10px;
}
.restore-options,
.confirmation-section {
margin: 20px 0;
padding: 15px;
background: #f9f9f9;
border-radius: 4px;
}
.advanced-operation {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 4px;
}
.advanced-operation h4 {
margin-top: 0;
}
.settings-section {
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid #eee;
}
.settings-section:last-child {
border-bottom: none;
}
.log-filters {
display: flex;
gap: 10px;
margin-bottom: 15px;
align-items: center;
}
.log-loading {
text-align: center;
padding: 40px;
color: #666;
}
.log-entry {
padding: 10px;
border-bottom: 1px solid #eee;
font-family: monospace;
}
.log-entry.level-error,
.log-entry.level-critical {
background: #ffeaea;
border-left: 3px solid #dc3545;
}
.log-entry.level-warning {
background: #fff3cd;
border-left: 3px solid #ffc107;
}
.log-entry.level-info {
background: #d1ecf1;
border-left: 3px solid #17a2b8;
}
@media (max-width: 768px) {
.form-row {
grid-template-columns: 1fr;
}
.backup-header,
.backup-row {
grid-template-columns: 1fr;
gap: 10px;
}
.col-actions {
justify-content: flex-start;
}
}
</style>
<script>
jQuery(document).ready(function($) {
// Tab switching
$('.backup-tabs .nav-tab').on('click', function(e) {
e.preventDefault();
const target = $(this).attr('href');
$('.backup-tabs .nav-tab').removeClass('nav-tab-active');
$(this).addClass('nav-tab-active');
$('.tab-content').removeClass('active');
$(target).addClass('active');
});
// Toggle advanced options
$('#toggle-advanced').on('click', function() {
$('.advanced-options').toggle();
});
// Show/hide schedule options
$('input[name="schedule_enabled"]').on('change', function() {
$('.schedule-option').toggle(this.checked);
}).trigger('change');
// Show/hide notification options
$('input[name="email_notifications"]').on('change', function() {
$('.notification-option').toggle(this.checked);
}).trigger('change');
// Create backup form
$('#create-backup-form').on('submit', function(e) {
e.preventDefault();
createBackup();
});
// Restore preparation
$('#show-restore-confirmation').on('click', function() {
if ($('#restore_backup_id').val()) {
$('.confirmation-section').show();
$('#restore-backup-btn').show();
$(this).hide();
} else {
alert('<?php echo esc_js(__('Please select a backup to restore.', 'tigerstyle-heat')); ?>');
}
});
// Restore form
$('#restore-form').on('submit', function(e) {
e.preventDefault();
const confirmation = $('#restore_confirmation').val();
if (confirmation !== 'CONFIRM RESTORE') {
alert('<?php echo esc_js(__('Please type "CONFIRM RESTORE" to proceed.', 'tigerstyle-heat')); ?>');
return;
}
restoreBackup();
});
// WordPress reset
$('#wordpress-reset-form').on('submit', function(e) {
e.preventDefault();
const confirmation = $('#wordpress-reset-confirmation').val();
if (confirmation !== 'RESET_WORDPRESS') {
alert('<?php echo esc_js(__('Please type "RESET_WORDPRESS" to confirm.', 'tigerstyle-heat')); ?>');
return;
}
resetWordPress();
});
// Generate reset code
$('#generate-reset-code').on('click', function() {
generateResetCode();
});
// Database reset
$('#database-reset-form').on('submit', function(e) {
e.preventDefault();
resetDatabase();
});
// Test S3 connection
$('#test-s3-connection').on('click', function() {
testS3Connection();
});
// Backup actions
$(document).on('click', '.restore-backup', function() {
const backupId = $(this).data('backup-id');
$('#restore_backup_id').val(backupId);
$('.backup-tabs .nav-tab[href="#restore"]').click();
});
$(document).on('click', '.validate-backup', function() {
const backupId = $(this).data('backup-id');
validateBackup(backupId);
});
$(document).on('click', '.delete-backup', function() {
const backupId = $(this).data('backup-id');
if (confirm('<?php echo esc_js(__('Are you sure you want to delete this backup? This action cannot be undone.', 'tigerstyle-heat')); ?>')) {
deleteBackup(backupId);
}
});
// Load logs on tab switch
$('.backup-tabs .nav-tab[href="#logs"]').on('click', function() {
loadLogs();
});
// Refresh buttons
$('#refresh-backups').on('click', function() {
location.reload();
});
$('#refresh-logs').on('click', function() {
loadLogs();
});
// Functions
function createBackup() {
const formData = new FormData(document.getElementById('create-backup-form'));
$('#create-backup-btn').prop('disabled', true);
$('#backup-progress').show();
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_create_backup',
nonce: $('#tigerstyle_backup_nonce').val(),
backup_type: formData.get('backup_type'),
compression: formData.get('compression'),
storage_location: formData.get('storage_location'),
description: formData.get('description'),
include_files: $('input[name="backup_type"]').val() !== 'database_only',
include_database: $('input[name="backup_type"]').val() !== 'files_only'
},
success: function(response) {
if (response.success) {
$('#backup-id-display').text(response.data.backup_id);
$('#backup-start-time').text(new Date().toLocaleString());
// Start progress tracking
trackBackupProgress(response.data.backup_id);
} else {
alert('Backup failed: ' + response.data);
$('#backup-progress').hide();
$('#create-backup-btn').prop('disabled', false);
}
},
error: function() {
alert('<?php echo esc_js(__('Network error occurred.', 'tigerstyle-heat')); ?>');
$('#backup-progress').hide();
$('#create-backup-btn').prop('disabled', false);
}
});
}
function trackBackupProgress(backupId) {
const interval = setInterval(function() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_backup_progress',
nonce: $('#tigerstyle_backup_nonce').val(),
operation_id: backupId
},
success: function(response) {
if (response.success) {
const progress = response.data;
$('.progress-fill').css('width', progress.percentage + '%');
$('.progress-text').text(progress.percentage + '%');
$('.progress-message').text(progress.message);
if (progress.percentage >= 100) {
clearInterval(interval);
$('#create-backup-btn').prop('disabled', false);
setTimeout(function() {
location.reload();
}, 2000);
}
}
}
});
}, 2000);
}
function restoreBackup() {
const formData = new FormData(document.getElementById('restore-form'));
$('#restore-backup-btn').prop('disabled', true);
$('#restore-progress').show();
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_restore_backup',
nonce: $('#tigerstyle_restore_nonce').val(),
backup_id: formData.get('backup_id'),
restore_files: formData.get('restore_files') ? true : false,
restore_database: formData.get('restore_database') ? true : false
},
success: function(response) {
if (response.success) {
// Start progress tracking
trackRestoreProgress(response.data.restore_id);
} else {
alert('Restore failed: ' + response.data);
$('#restore-progress').hide();
$('#restore-backup-btn').prop('disabled', false);
}
}
});
}
function trackRestoreProgress(restoreId) {
const interval = setInterval(function() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_backup_progress',
nonce: $('#tigerstyle_backup_nonce').val(),
operation_id: restoreId
},
success: function(response) {
if (response.success) {
const progress = response.data;
$('#restore-progress .progress-fill').css('width', progress.percentage + '%');
$('#restore-progress .progress-text').text(progress.percentage + '%');
$('#restore-progress .progress-message').text(progress.message);
if (progress.percentage >= 100) {
clearInterval(interval);
alert('<?php echo esc_js(__('Restore completed successfully!', 'tigerstyle-heat')); ?>');
location.reload();
}
}
}
});
}, 2000);
}
function validateBackup(backupId) {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_validate_backup',
nonce: $('#tigerstyle_backup_nonce').val(),
backup_id: backupId
},
success: function(response) {
if (response.success) {
alert('<?php echo esc_js(__('Backup validation passed!', 'tigerstyle-heat')); ?>');
} else {
alert('Backup validation failed: ' + response.data);
}
}
});
}
function deleteBackup(backupId) {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_delete_backup',
nonce: $('#tigerstyle_backup_nonce').val(),
backup_id: backupId
},
success: function(response) {
if (response.success) {
$('[data-backup-id="' + backupId + '"]').remove();
} else {
alert('Delete failed: ' + response.data);
}
}
});
}
function resetWordPress() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_reset_wordpress',
nonce: $('#tigerstyle_reset_nonce').val(),
confirmation: $('#wordpress-reset-confirmation').val()
},
success: function(response) {
if (response.success) {
alert('<?php echo esc_js(__('WordPress content reset completed!', 'tigerstyle-heat')); ?>');
$('#wordpress-reset-confirmation').val('');
} else {
alert('Reset failed: ' + response.data);
}
}
});
}
function generateResetCode() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_generate_reset_code',
nonce: $('#tigerstyle_db_reset_nonce').val()
},
success: function(response) {
if (response.success) {
$('#reset-code-display').text(response.data.code);
$('#reset-code-section').show();
$('#generate-reset-code').hide();
}
}
});
}
function resetDatabase() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_reset_database',
nonce: $('#tigerstyle_db_reset_nonce').val(),
confirmation_code: $('#database-reset-code').val(),
final_confirmation: $('#database-reset-final').val()
},
success: function(response) {
if (response.success) {
alert('<?php echo esc_js(__('Database reset completed!', 'tigerstyle-heat')); ?>');
location.reload();
} else {
alert('Reset failed: ' + response.data);
}
}
});
}
function testS3Connection() {
$('#test-s3-connection').prop('disabled', true);
$('#s3-test-result').html('<span class="spinner is-active"></span>');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_test_s3_connection',
nonce: $('#tigerstyle_backup_nonce').val(),
s3_bucket: $('input[name="s3_bucket"]').val(),
s3_access_key: $('input[name="s3_access_key"]').val(),
s3_secret_key: $('input[name="s3_secret_key"]').val(),
s3_region: $('input[name="s3_region"]').val(),
s3_endpoint: $('input[name="s3_endpoint"]').val()
},
success: function(response) {
$('#test-s3-connection').prop('disabled', false);
if (response.success) {
$('#s3-test-result').html('<span style="color: green;">✓ Connection successful</span>');
} else {
$('#s3-test-result').html('<span style="color: red;">✗ ' + response.data + '</span>');
}
},
error: function() {
$('#test-s3-connection').prop('disabled', false);
$('#s3-test-result').html('<span style="color: red;">✗ Network error</span>');
}
});
}
function loadLogs() {
$('#logs-container').html('<div class="log-loading"><span class="spinner is-active"></span> <?php echo esc_js(__('Loading logs...', 'tigerstyle-heat')); ?></div>');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_get_backup_logs',
nonce: $('#tigerstyle_backup_nonce').val(),
level: $('#log-level-filter').val(),
limit: 100
},
success: function(response) {
if (response.success) {
displayLogs(response.data);
} else {
$('#logs-container').html('<p>Failed to load logs.</p>');
}
},
error: function() {
$('#logs-container').html('<p>Network error loading logs.</p>');
}
});
}
function displayLogs(logs) {
if (logs.length === 0) {
$('#logs-container').html('<p><?php echo esc_js(__('No logs found.', 'tigerstyle-heat')); ?></p>');
return;
}
let html = '<div class="logs-list">';
logs.forEach(function(log) {
html += '<div class="log-entry level-' + log.level + '">';
html += '<div class="log-meta">';
html += '<span class="log-time">' + log.created_at_formatted + '</span>';
html += '<span class="log-level level-' + log.level + '">' + log.level.toUpperCase() + '</span>';
html += '</div>';
html += '<div class="log-message">' + log.message + '</div>';
if (log.context && Object.keys(log.context).length > 0) {
html += '<div class="log-context"><pre>' + JSON.stringify(log.context, null, 2) + '</pre></div>';
}
html += '</div>';
});
html += '</div>';
$('#logs-container').html(html);
}
});
</script>