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.
572 lines
20 KiB
PHP
572 lines
20 KiB
PHP
<?php
|
|
/**
|
|
* Enterprise Backup & Restore Module for TigerStyle Heat
|
|
*
|
|
* Provides comprehensive backup and restore functionality including:
|
|
* - File system backups with chunked processing
|
|
* - Database backups with table-level control
|
|
* - S3 and S3-compatible storage integration
|
|
* - Advanced compression with multiple formats
|
|
* - Complete WordPress reset functionality
|
|
* - Enterprise-grade logging and validation
|
|
*
|
|
* @package TigerStyleSEO
|
|
* @subpackage BackupRestore
|
|
* @version 1.0.0
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class TigerStyleSEO_Backup_Restore {
|
|
|
|
/**
|
|
* Single instance
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Backup engine
|
|
*/
|
|
private $backup_engine;
|
|
|
|
/**
|
|
* Restore engine
|
|
*/
|
|
private $restore_engine;
|
|
|
|
/**
|
|
* Storage manager
|
|
*/
|
|
private $storage_manager;
|
|
|
|
/**
|
|
* Logger
|
|
*/
|
|
private $logger;
|
|
|
|
/**
|
|
* Validator
|
|
*/
|
|
private $validator;
|
|
|
|
/**
|
|
* Get instance
|
|
*/
|
|
public static function instance() {
|
|
if (is_null(self::$instance)) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
private function __construct() {
|
|
$this->init();
|
|
}
|
|
|
|
/**
|
|
* Initialize module
|
|
*/
|
|
private function init() {
|
|
// Load dependencies
|
|
$this->load_dependencies();
|
|
|
|
// Defer backup system initialization until needed to avoid database errors during startup
|
|
add_action('admin_init', array($this, 'init_backup_system'), 10);
|
|
|
|
// Setup hooks
|
|
$this->setup_hooks();
|
|
}
|
|
|
|
/**
|
|
* Initialize backup system components
|
|
*/
|
|
public function init_backup_system() {
|
|
// Only initialize if we're in admin and not already initialized
|
|
if (!is_admin() || $this->backup_engine) {
|
|
return;
|
|
}
|
|
|
|
// Initialize components
|
|
$this->backup_engine = TigerStyleSEO_Backup_Engine::instance();
|
|
$this->restore_engine = TigerStyleSEO_Restore_Engine::instance();
|
|
$this->storage_manager = TigerStyleSEO_Storage_Manager::instance();
|
|
$this->logger = TigerStyleSEO_Backup_Logger::instance();
|
|
$this->validator = TigerStyleSEO_Backup_Validator::instance();
|
|
}
|
|
|
|
/**
|
|
* Load dependencies
|
|
*/
|
|
private function load_dependencies() {
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-backup-engine.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-restore-engine.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-storage-manager.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-backup-logger.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-backup-validator.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-backup-scheduler.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/class-compression-manager.php';
|
|
require_once TIGERSTYLE_HEAT_PLUGIN_DIR . 'includes/backup/ajax-handlers.php';
|
|
}
|
|
|
|
/**
|
|
* Setup WordPress hooks
|
|
*/
|
|
private function setup_hooks() {
|
|
// AJAX handlers
|
|
add_action('wp_ajax_tigerstyle_create_backup', array($this, 'ajax_create_backup'));
|
|
add_action('wp_ajax_tigerstyle_restore_backup', array($this, 'ajax_restore_backup'));
|
|
add_action('wp_ajax_tigerstyle_delete_backup', array($this, 'ajax_delete_backup'));
|
|
add_action('wp_ajax_tigerstyle_download_backup', array($this, 'ajax_download_backup'));
|
|
add_action('wp_ajax_tigerstyle_upload_backup', array($this, 'ajax_upload_backup'));
|
|
add_action('wp_ajax_tigerstyle_reset_wordpress', array($this, 'ajax_reset_wordpress'));
|
|
add_action('wp_ajax_tigerstyle_reset_database', array($this, 'ajax_reset_database'));
|
|
add_action('wp_ajax_tigerstyle_backup_progress', array($this, 'ajax_backup_progress'));
|
|
add_action('wp_ajax_tigerstyle_validate_backup', array($this, 'ajax_validate_backup'));
|
|
|
|
// Scheduled backup hooks
|
|
add_action('tigerstyle_backup_scheduled', array($this, 'run_scheduled_backup'));
|
|
add_action('tigerstyle_backup_cleanup', array($this, 'cleanup_old_backups'));
|
|
|
|
// Admin hooks
|
|
add_action('admin_post_tigerstyle_backup_settings', array($this, 'save_backup_settings'));
|
|
add_action('admin_notices', array($this, 'display_backup_notices'));
|
|
|
|
// Cron hooks
|
|
if (!wp_next_scheduled('tigerstyle_backup_cleanup')) {
|
|
wp_schedule_event(time(), 'daily', 'tigerstyle_backup_cleanup');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Render admin page
|
|
*/
|
|
public function render_admin_page() {
|
|
if (!current_user_can('manage_options')) {
|
|
wp_die(__('You do not have sufficient permissions to access this page.', 'tigerstyle-heat'));
|
|
}
|
|
|
|
// Handle form submissions
|
|
$this->handle_form_submissions();
|
|
|
|
// Get backup list
|
|
$backups = $this->get_backup_list();
|
|
$storage_stats = $this->storage_manager->get_storage_stats();
|
|
$compression_methods = $this->get_available_compression_methods();
|
|
|
|
include TIGERSTYLE_HEAT_PLUGIN_DIR . 'admin/pages/backup-restore.php';
|
|
}
|
|
|
|
/**
|
|
* Handle form submissions
|
|
*/
|
|
private function handle_form_submissions() {
|
|
if (!isset($_POST['tigerstyle_backup_nonce']) ||
|
|
!wp_verify_nonce($_POST['tigerstyle_backup_nonce'], 'tigerstyle_backup_action')) {
|
|
return;
|
|
}
|
|
|
|
$action = sanitize_text_field($_POST['backup_action']);
|
|
|
|
switch ($action) {
|
|
case 'create_backup':
|
|
$this->handle_create_backup();
|
|
break;
|
|
case 'restore_backup':
|
|
$this->handle_restore_backup();
|
|
break;
|
|
case 'delete_backup':
|
|
$this->handle_delete_backup();
|
|
break;
|
|
case 'save_settings':
|
|
$this->handle_save_settings();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create backup via AJAX
|
|
*/
|
|
public function ajax_create_backup() {
|
|
check_ajax_referer('tigerstyle_backup_action', 'nonce');
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error('Insufficient permissions');
|
|
}
|
|
|
|
$backup_type = sanitize_text_field($_POST['backup_type']);
|
|
$compression = sanitize_text_field($_POST['compression']);
|
|
$storage_location = sanitize_text_field($_POST['storage_location']);
|
|
$include_files = isset($_POST['include_files']) ? (bool)$_POST['include_files'] : true;
|
|
$include_database = isset($_POST['include_database']) ? (bool)$_POST['include_database'] : true;
|
|
|
|
try {
|
|
$backup_id = $this->backup_engine->create_backup(array(
|
|
'type' => $backup_type,
|
|
'compression' => $compression,
|
|
'storage_location' => $storage_location,
|
|
'include_files' => $include_files,
|
|
'include_database' => $include_database,
|
|
'description' => sanitize_textarea_field($_POST['description'])
|
|
));
|
|
|
|
wp_send_json_success(array(
|
|
'backup_id' => $backup_id,
|
|
'message' => __('Backup started successfully', 'tigerstyle-heat')
|
|
));
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Backup creation failed: ' . $e->getMessage());
|
|
wp_send_json_error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Restore backup via AJAX
|
|
*/
|
|
public function ajax_restore_backup() {
|
|
check_ajax_referer('tigerstyle_backup_action', 'nonce');
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error('Insufficient permissions');
|
|
}
|
|
|
|
$backup_id = sanitize_text_field($_POST['backup_id']);
|
|
$restore_files = isset($_POST['restore_files']) ? (bool)$_POST['restore_files'] : true;
|
|
$restore_database = isset($_POST['restore_database']) ? (bool)$_POST['restore_database'] : true;
|
|
|
|
try {
|
|
// Validate backup first
|
|
if (!$this->validator->validate_backup($backup_id)) {
|
|
throw new Exception(__('Invalid or corrupted backup file', 'tigerstyle-heat'));
|
|
}
|
|
|
|
$restore_id = $this->restore_engine->restore_backup(array(
|
|
'backup_id' => $backup_id,
|
|
'restore_files' => $restore_files,
|
|
'restore_database' => $restore_database
|
|
));
|
|
|
|
wp_send_json_success(array(
|
|
'restore_id' => $restore_id,
|
|
'message' => __('Restore started successfully', 'tigerstyle-heat')
|
|
));
|
|
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Restore failed: ' . $e->getMessage());
|
|
wp_send_json_error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset WordPress (remove default pages/posts)
|
|
*/
|
|
public function ajax_reset_wordpress() {
|
|
check_ajax_referer('tigerstyle_backup_action', 'nonce');
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error('Insufficient permissions');
|
|
}
|
|
|
|
$confirmation = sanitize_text_field($_POST['confirmation']);
|
|
if ($confirmation !== 'RESET_WORDPRESS') {
|
|
wp_send_json_error(__('Invalid confirmation text', 'tigerstyle-heat'));
|
|
}
|
|
|
|
try {
|
|
$this->reset_wordpress_content();
|
|
wp_send_json_success(__('WordPress content reset successfully', 'tigerstyle-heat'));
|
|
} catch (Exception $e) {
|
|
wp_send_json_error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset database (complete database wipe)
|
|
*/
|
|
public function ajax_reset_database() {
|
|
check_ajax_referer('tigerstyle_backup_action', 'nonce');
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error('Insufficient permissions');
|
|
}
|
|
|
|
$confirmation_code = sanitize_text_field($_POST['confirmation_code']);
|
|
$expected_code = get_transient('tigerstyle_reset_code_' . get_current_user_id());
|
|
|
|
if (!$expected_code || $confirmation_code !== $expected_code) {
|
|
wp_send_json_error(__('Invalid confirmation code', 'tigerstyle-heat'));
|
|
}
|
|
|
|
$final_confirmation = sanitize_text_field($_POST['final_confirmation']);
|
|
if ($final_confirmation !== 'YES_DELETE_EVERYTHING') {
|
|
wp_send_json_error(__('Final confirmation required', 'tigerstyle-heat'));
|
|
}
|
|
|
|
try {
|
|
$this->reset_database_completely();
|
|
delete_transient('tigerstyle_reset_code_' . get_current_user_id());
|
|
wp_send_json_success(__('Database reset successfully', 'tigerstyle-heat'));
|
|
} catch (Exception $e) {
|
|
wp_send_json_error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get backup progress
|
|
*/
|
|
public function ajax_backup_progress() {
|
|
check_ajax_referer('tigerstyle_backup_action', 'nonce');
|
|
|
|
$operation_id = sanitize_text_field($_POST['operation_id']);
|
|
$progress = get_transient('tigerstyle_backup_progress_' . $operation_id);
|
|
|
|
if ($progress === false) {
|
|
wp_send_json_error(__('Operation not found', 'tigerstyle-heat'));
|
|
}
|
|
|
|
wp_send_json_success($progress);
|
|
}
|
|
|
|
/**
|
|
* Get list of available backups
|
|
*/
|
|
public function get_backup_list() {
|
|
return $this->storage_manager->list_backups();
|
|
}
|
|
|
|
/**
|
|
* Get available compression methods
|
|
*/
|
|
public function get_available_compression_methods() {
|
|
$methods = array();
|
|
|
|
if (class_exists('ZipArchive')) {
|
|
$methods['zip'] = __('ZIP Compression', 'tigerstyle-heat');
|
|
}
|
|
|
|
if (function_exists('gzopen')) {
|
|
$methods['tar.gz'] = __('TAR.GZ Compression', 'tigerstyle-heat');
|
|
}
|
|
|
|
if (function_exists('bzopen')) {
|
|
$methods['tar.bz2'] = __('TAR.BZ2 Compression', 'tigerstyle-heat');
|
|
}
|
|
|
|
if (empty($methods)) {
|
|
$methods['none'] = __('No Compression (Fallback)', 'tigerstyle-heat');
|
|
}
|
|
|
|
return $methods;
|
|
}
|
|
|
|
/**
|
|
* Reset WordPress content (default pages/posts)
|
|
*/
|
|
private function reset_wordpress_content() {
|
|
global $wpdb;
|
|
|
|
// Create backup before reset
|
|
$backup_id = $this->backup_engine->create_backup(array(
|
|
'type' => 'quick',
|
|
'description' => 'Auto-backup before WordPress reset',
|
|
'include_files' => false,
|
|
'include_database' => true
|
|
));
|
|
|
|
// Delete default posts
|
|
$default_posts = get_posts(array(
|
|
'post_type' => array('post', 'page'),
|
|
'posts_per_page' => -1,
|
|
'post_status' => 'any'
|
|
));
|
|
|
|
foreach ($default_posts as $post) {
|
|
wp_delete_post($post->ID, true);
|
|
}
|
|
|
|
// Delete default comments
|
|
$wpdb->query("DELETE FROM {$wpdb->comments}");
|
|
$wpdb->query("DELETE FROM {$wpdb->commentmeta}");
|
|
|
|
// Reset comment count
|
|
$wpdb->query("UPDATE {$wpdb->posts} SET comment_count = 0");
|
|
|
|
// Clear caches
|
|
wp_cache_flush();
|
|
|
|
$this->logger->info('WordPress content reset completed', array(
|
|
'backup_id' => $backup_id,
|
|
'posts_deleted' => count($default_posts)
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Reset database completely
|
|
*/
|
|
private function reset_database_completely() {
|
|
global $wpdb;
|
|
|
|
// Get all tables
|
|
$tables = $wpdb->get_col("SHOW TABLES");
|
|
|
|
// Disable foreign key checks
|
|
$wpdb->query("SET FOREIGN_KEY_CHECKS = 0");
|
|
|
|
try {
|
|
// Drop all tables
|
|
foreach ($tables as $table) {
|
|
$wpdb->query("DROP TABLE IF EXISTS `{$table}`");
|
|
}
|
|
|
|
$this->logger->critical('Complete database reset performed', array(
|
|
'tables_dropped' => count($tables),
|
|
'user_id' => get_current_user_id()
|
|
));
|
|
|
|
} finally {
|
|
// Re-enable foreign key checks
|
|
$wpdb->query("SET FOREIGN_KEY_CHECKS = 1");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate reset confirmation code
|
|
*/
|
|
public function generate_reset_code() {
|
|
$code = wp_generate_password(6, false, false);
|
|
$code = strtoupper($code);
|
|
set_transient('tigerstyle_reset_code_' . get_current_user_id(), $code, 300); // 5 minutes
|
|
return $code;
|
|
}
|
|
|
|
/**
|
|
* Display admin notices
|
|
*/
|
|
public function display_backup_notices() {
|
|
// Check for backup failures
|
|
$failed_backups = get_option('tigerstyle_failed_backups', array());
|
|
if (!empty($failed_backups)) {
|
|
echo '<div class="notice notice-error"><p>';
|
|
echo __('Some backup operations have failed. Please check the backup logs.', 'tigerstyle-heat');
|
|
echo '</p></div>';
|
|
}
|
|
|
|
// Check storage space
|
|
$storage_stats = $this->storage_manager->get_storage_stats();
|
|
if (isset($storage_stats['usage_percent']) && $storage_stats['usage_percent'] > 90) {
|
|
echo '<div class="notice notice-warning"><p>';
|
|
echo __('Backup storage is nearly full. Consider cleaning up old backups.', 'tigerstyle-heat');
|
|
echo '</p></div>';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run scheduled backup
|
|
*/
|
|
public function run_scheduled_backup() {
|
|
$settings = get_option('tigerstyle_backup_settings', array());
|
|
|
|
if (!isset($settings['schedule_enabled']) || !$settings['schedule_enabled']) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$this->backup_engine->create_backup(array(
|
|
'type' => 'scheduled',
|
|
'compression' => $settings['compression'] ?? 'zip',
|
|
'storage_location' => $settings['storage_location'] ?? 'local',
|
|
'include_files' => $settings['include_files'] ?? true,
|
|
'include_database' => $settings['include_database'] ?? true,
|
|
'description' => 'Scheduled backup - ' . current_time('mysql')
|
|
));
|
|
} catch (Exception $e) {
|
|
$this->logger->error('Scheduled backup failed: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cleanup old backups
|
|
*/
|
|
public function cleanup_old_backups() {
|
|
$settings = get_option('tigerstyle_backup_settings', array());
|
|
$retention_days = $settings['retention_days'] ?? 30;
|
|
|
|
$this->storage_manager->cleanup_old_backups($retention_days);
|
|
}
|
|
|
|
/**
|
|
* Get backup settings
|
|
*/
|
|
public function get_backup_settings() {
|
|
$defaults = array(
|
|
'compression' => 'zip',
|
|
'storage_location' => 'local',
|
|
'schedule_enabled' => false,
|
|
'schedule_frequency' => 'daily',
|
|
'retention_days' => 30,
|
|
'include_files' => true,
|
|
'include_database' => true,
|
|
'chunk_size' => 5, // MB
|
|
's3_bucket' => '',
|
|
's3_access_key' => '',
|
|
's3_secret_key' => '',
|
|
's3_region' => 'us-east-1',
|
|
's3_endpoint' => '', // For S3-compatible services
|
|
'email_notifications' => false,
|
|
'notification_email' => get_option('admin_email')
|
|
);
|
|
|
|
return wp_parse_args(get_option('tigerstyle_backup_settings', array()), $defaults);
|
|
}
|
|
|
|
/**
|
|
* Save backup settings
|
|
*/
|
|
public function save_backup_settings() {
|
|
if (!isset($_POST['tigerstyle_backup_nonce']) || !wp_verify_nonce($_POST['tigerstyle_backup_nonce'], 'tigerstyle_backup_settings')) {
|
|
wp_die(__('Security check failed', 'tigerstyle-heat'));
|
|
}
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_die(__('Insufficient permissions', 'tigerstyle-heat'));
|
|
}
|
|
|
|
$settings = array(
|
|
'compression' => sanitize_text_field($_POST['compression']),
|
|
'storage_location' => sanitize_text_field($_POST['storage_location']),
|
|
'schedule_enabled' => isset($_POST['schedule_enabled']),
|
|
'schedule_frequency' => sanitize_text_field($_POST['schedule_frequency']),
|
|
'retention_days' => absint($_POST['retention_days']),
|
|
'include_files' => isset($_POST['include_files']),
|
|
'include_database' => isset($_POST['include_database']),
|
|
'chunk_size' => absint($_POST['chunk_size']),
|
|
's3_bucket' => sanitize_text_field($_POST['s3_bucket']),
|
|
's3_access_key' => sanitize_text_field($_POST['s3_access_key']),
|
|
's3_secret_key' => sanitize_text_field($_POST['s3_secret_key']),
|
|
's3_region' => sanitize_text_field($_POST['s3_region']),
|
|
's3_endpoint' => sanitize_url($_POST['s3_endpoint']),
|
|
'email_notifications' => isset($_POST['email_notifications']),
|
|
'notification_email' => sanitize_email($_POST['notification_email'])
|
|
);
|
|
|
|
update_option('tigerstyle_backup_settings', $settings);
|
|
|
|
// Update scheduled backup if settings changed
|
|
if ($settings['schedule_enabled']) {
|
|
wp_clear_scheduled_hook('tigerstyle_backup_scheduled');
|
|
wp_schedule_event(time(), $settings['schedule_frequency'], 'tigerstyle_backup_scheduled');
|
|
} else {
|
|
wp_clear_scheduled_hook('tigerstyle_backup_scheduled');
|
|
}
|
|
|
|
wp_redirect(add_query_arg('message', 'backup_settings_saved', wp_get_referer()));
|
|
exit;
|
|
}
|
|
} |