tigerstyle-life9/includes/class-admin.php
Ryan Malloy e92b7f8700 Initial commit: TigerStyle Life9 v1.0.0
Because cats have 9 lives, but servers don't - so they need
backup-restore! Complete backup solution with S3/MinIO support.

- Full WordPress backup (files + database)
- S3 / MinIO / S3-compatible storage backends
- Scheduled automatic backups
- Disaster recovery / one-click restore
- Backup integrity validation
- Cat-themed admin interface

Includes build.sh and .distignore for WordPress-installable release ZIPs.
2026-05-27 14:32:00 -06:00

663 lines
24 KiB
PHP

<?php
/**
* Admin Interface Manager
*
* Handles WordPress admin integration for TigerStyle Life9 backup plugin
* Registers admin pages and loads Astro-generated assets
*
* @package TigerStyleLife9
* @since 1.0.0
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
/**
* Admin interface management class
*
* @since 1.0.0
*/
class TigerStyle_Life9_Admin {
/**
* Plugin instance
*
* @var TigerStyle_Life9
*/
private $plugin;
/**
* Security instance
*
* @var TigerStyle_Life9_Security
*/
private $security;
/**
* Asset manifest
*
* @var array
*/
private $asset_manifest = [];
/**
* Constructor
*
* @param TigerStyle_Life9 $plugin Plugin instance
*/
public function __construct($plugin) {
$this->plugin = $plugin;
$this->security = $plugin->get_security();
$this->load_asset_manifest();
$this->init_hooks();
}
/**
* Initialize WordPress hooks
*/
private function init_hooks() {
add_action('admin_menu', [$this, 'register_admin_pages']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
add_action('admin_init', [$this, 'handle_admin_actions']);
add_action('wp_ajax_tigerstyle_life9_render_page', [$this, 'render_astro_page']);
// Add admin notices
add_action('admin_notices', [$this, 'display_admin_notices']);
// Add plugin action links
add_filter('plugin_action_links_' . TIGERSTYLE_LIFE9_BASENAME, [$this, 'add_plugin_action_links']);
}
/**
* Load Astro asset manifest
*/
private function load_asset_manifest() {
$manifest_path = TIGERSTYLE_LIFE9_PATH . 'admin/assets/dist/manifest.json';
if (file_exists($manifest_path)) {
$manifest_content = file_get_contents($manifest_path);
$this->asset_manifest = json_decode($manifest_content, true) ?: [];
}
}
/**
* Register admin menu pages
*/
public function register_admin_pages() {
// Check user capability
if (!current_user_can('manage_options')) {
return;
}
// Main menu page
add_menu_page(
'🐾 Life Tracker Dashboard', // Page title
'TigerStyle Life9', // Menu title
'manage_options', // Capability
'tigerstyle-life9', // Menu slug
[$this, 'render_dashboard_page'], // Callback
'dashicons-backup', // Icon (more appropriate for backups)
30 // Position
);
// Life Saving page
add_submenu_page(
'tigerstyle-life9', // Parent slug
'💾 Save a Life', // Page title
'💾 Save a Life', // Menu title
'manage_options', // Capability
'tigerstyle-life9-backup', // Menu slug
[$this, 'render_backup_page'] // Callback
);
// Life Revival page
add_submenu_page(
'tigerstyle-life9', // Parent slug
'🔄 Revive a Life', // Page title
'🔄 Revive a Life', // Menu title
'manage_options', // Capability
'tigerstyle-life9-restore', // Menu slug
[$this, 'render_restore_page'] // Callback
);
// Life Chronicles page
add_submenu_page(
'tigerstyle-life9', // Parent slug
'📚 Life Chronicles', // Page title
'📚 Life Chronicles', // Menu title
'manage_options', // Capability
'tigerstyle-life9-backups', // Menu slug
[$this, 'render_backups_page'] // Callback
);
// Territory Settings page
add_submenu_page(
'tigerstyle-life9', // Parent slug
'🏠 Territory Settings', // Page title
'🏠 Territory Settings', // Menu title
'manage_options', // Capability
'tigerstyle-life9-settings', // Menu slug
[$this, 'render_settings_page'] // Callback
);
// Rename first submenu to cat-themed name
global $submenu;
if (isset($submenu['tigerstyle-life9'])) {
$submenu['tigerstyle-life9'][0][0] = '🐾 Life Tracker';
}
}
/**
* Enqueue admin assets
*
* @param string $hook_suffix Current admin page hook suffix
*/
public function enqueue_admin_assets($hook_suffix) {
// Only load on our admin pages
if (!$this->is_tigerstyle_admin_page($hook_suffix)) {
return;
}
// Enqueue WordPress core dependencies
wp_enqueue_script('jquery');
wp_enqueue_media();
// Enqueue Alpine.js
wp_enqueue_script(
'alpine-js',
'https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js',
[],
'3.13.3',
true
);
// Defer Alpine.js execution
add_filter('script_loader_tag', function($tag, $handle) {
if ($handle === 'alpine-js') {
return str_replace(' src', ' defer src', $tag);
}
return $tag;
}, 10, 2);
// Enqueue Astro-generated assets
$this->enqueue_astro_assets();
// Enqueue admin styles
wp_enqueue_style(
'tigerstyle-life9-admin',
TIGERSTYLE_LIFE9_URL . 'admin/assets/css/admin.css',
[],
TIGERSTYLE_LIFE9_VERSION
);
// Localize script for AJAX with cat-themed messages
wp_localize_script('jquery', 'tigerStyleLife9', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('tigerstyle_life9_ajax'),
'pluginUrl' => TIGERSTYLE_LIFE9_URL,
'currentPage' => $this->get_current_page_slug($hook_suffix),
'capabilities' => [
'backup' => current_user_can('manage_options'),
'restore' => current_user_can('manage_options'),
'settings' => current_user_can('manage_options')
],
'strings' => [
'confirmDelete' => __('😿 Are you sure you want to permanently lose this life? This cannot be undone!', 'tigerstyle-life9'),
'confirmRestore' => __('🔄 This will revive your site to this saved life. Current state will be overwritten. Ready to pounce?', 'tigerstyle-life9'),
'processing' => __('🐾 Stalking through the process...', 'tigerstyle-life9'),
'error' => __('😿 Oops! Cat got stuck. Please try again.', 'tigerstyle-life9'),
'scanning' => __('🔍 Stalking through your files...', 'tigerstyle-life9'),
'compressing' => __('📦 Packing your territory efficiently...', 'tigerstyle-life9'),
'uploading' => __('☁️ Moving to your backup lair...', 'tigerstyle-life9'),
'completed' => __('😻 Mission accomplished! Life saved successfully.', 'tigerstyle-life9'),
'warning' => __('⚠️ Something smells fishy in your files...', 'tigerstyle-life9'),
'ninthLife' => __('🛡️ Nine lives protection activated!', 'tigerstyle-life9'),
'territoryScan' => __('🏠 Territory backup complete - domain secured!', 'tigerstyle-life9'),
'memoryPreservation' => __('🧠 Preserving digital memories...', 'tigerstyle-life9'),
'catReflexes' => __('⚡ Pouncing on database changes...', 'tigerstyle-life9')
]
]);
// Add Alpine.js WordPress integration helper
$this->add_alpine_wordpress_helper();
}
/**
* Enqueue Astro-generated assets
*/
private function enqueue_astro_assets() {
if (empty($this->asset_manifest)) {
return;
}
// Enqueue CSS files
foreach ($this->asset_manifest as $file => $data) {
if (isset($data['isEntry']) && $data['isEntry'] && isset($data['css'])) {
foreach ($data['css'] as $css_file) {
wp_enqueue_style(
'tigerstyle-astro-' . basename($css_file, '.css'),
TIGERSTYLE_LIFE9_URL . 'admin/assets/dist/' . $css_file,
[],
TIGERSTYLE_LIFE9_VERSION
);
}
}
}
// Enqueue JS files
foreach ($this->asset_manifest as $file => $data) {
if (isset($data['isEntry']) && $data['isEntry']) {
wp_enqueue_script(
'tigerstyle-astro-' . basename($file, '.js'),
TIGERSTYLE_LIFE9_URL . 'admin/assets/dist/' . $file,
['jquery', 'alpine-js'],
TIGERSTYLE_LIFE9_VERSION,
true
);
}
}
}
/**
* Add Alpine.js WordPress helper
*/
private function add_alpine_wordpress_helper() {
?>
<script>
// Alpine.js WordPress integration helper
document.addEventListener('alpine:init', () => {
Alpine.magic('wp', () => ({
ajax: async (action, data = {}) => {
const formData = new FormData();
formData.append('action', 'tigerstyle_life9_' + action);
formData.append('_wpnonce', tigerStyleLife9.nonce);
// Append data
Object.keys(data).forEach(key => {
if (data[key] instanceof File) {
formData.append(key, data[key]);
} else if (typeof data[key] === 'object') {
formData.append(key, JSON.stringify(data[key]));
} else {
formData.append(key, data[key]);
}
});
const response = await fetch(tigerStyleLife9.ajaxUrl, {
method: 'POST',
body: formData,
credentials: 'same-origin'
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.data || 'Request failed');
}
return result;
},
nonce: tigerStyleLife9.nonce,
adminUrl: tigerStyleLife9.ajaxUrl,
pluginUrl: tigerStyleLife9.pluginUrl,
currentPage: tigerStyleLife9.currentPage,
capabilities: tigerStyleLife9.capabilities,
strings: tigerStyleLife9.strings
}));
});
</script>
<?php
}
/**
* Check if current page is a TigerStyle admin page
*
* @param string $hook_suffix Current hook suffix
* @return bool
*/
private function is_tigerstyle_admin_page($hook_suffix) {
$tigerstyle_pages = [
'toplevel_page_tigerstyle-life9',
'tigerstyle-life9_page_tigerstyle-life9-backup',
'tigerstyle-life9_page_tigerstyle-life9-restore',
'tigerstyle-life9_page_tigerstyle-life9-backups',
'tigerstyle-life9_page_tigerstyle-life9-settings'
];
return in_array($hook_suffix, $tigerstyle_pages);
}
/**
* Get current page slug from hook suffix
*
* @param string $hook_suffix Hook suffix
* @return string Page slug
*/
private function get_current_page_slug($hook_suffix) {
$page_map = [
'toplevel_page_tigerstyle-life9' => 'dashboard',
'tigerstyle-life9_page_tigerstyle-life9-backup' => 'backup',
'tigerstyle-life9_page_tigerstyle-life9-restore' => 'restore',
'tigerstyle-life9_page_tigerstyle-life9-backups' => 'backups',
'tigerstyle-life9_page_tigerstyle-life9-settings' => 'settings'
];
return $page_map[$hook_suffix] ?? 'dashboard';
}
/**
* Render dashboard page
*/
public function render_dashboard_page() {
$this->render_page('admin-dashboard');
}
/**
* Render backup page
*/
public function render_backup_page() {
$this->render_page('backup');
}
/**
* Render restore page
*/
public function render_restore_page() {
$this->render_page('restore');
}
/**
* Render backups management page
*/
public function render_backups_page() {
$this->render_page('backups');
}
/**
* Render settings page
*/
public function render_settings_page() {
$this->render_page('settings');
}
/**
* Render Astro page
*
* @param string $page_name Page name
*/
private function render_page($page_name) {
// Security check
if (!current_user_can('manage_options')) {
wp_die(__('You do not have sufficient permissions to access this page.', 'tigerstyle-life9'));
}
// Verify nonce for AJAX requests
if (wp_doing_ajax()) {
check_ajax_referer('tigerstyle_life9_ajax', '_wpnonce');
}
// For now, render the Astro pages as PHP templates
// In a production version, you would use a proper Astro SSR setup
$astro_file = TIGERSTYLE_LIFE9_PATH . "src/astro/pages/{$page_name}.astro";
if (file_exists($astro_file)) {
// Convert Astro to WordPress-compatible output
$this->render_astro_as_php($astro_file, $page_name);
} else {
// Fallback if Astro file doesn't exist
$this->render_fallback_page($page_name);
}
}
/**
* Render Astro file as PHP (simplified conversion)
*
* @param string $astro_file Path to Astro file
* @param string $page_name Page name for context
*/
private function render_astro_as_php($astro_file, $page_name) {
// Read the Astro file content
$astro_content = file_get_contents($astro_file);
// Extract the HTML content (everything after the ---)
$parts = preg_split('/^---$/m', $astro_content);
$html_content = isset($parts[2]) ? $parts[2] : (isset($parts[1]) ? $parts[1] : $astro_content);
// Process template variables
$html_content = str_replace('{{PLUGIN_URL}}', TIGERSTYLE_LIFE9_URL, $html_content);
$html_content = str_replace('{{ADMIN_URL}}', admin_url(), $html_content);
$html_content = str_replace('{{AJAX_URL}}', admin_url('admin-ajax.php'), $html_content);
// Add WordPress admin wrapper
echo '<div class="wrap tigerstyle-life9-admin">';
echo $html_content;
echo '</div>';
}
/**
* Process Astro-generated content
*
* @param string $content HTML content
* @return string Processed content
*/
private function process_astro_content($content) {
// Extract scripts and styles for proper WordPress handling
$content = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $content);
$content = preg_replace('/<link[^>]*rel=["\']stylesheet["\'][^>]*>/i', '', $content);
// Add WordPress admin wrapper if not present
if (strpos($content, 'class="wrap"') === false) {
$content = '<div class="wrap tigerstyle-life9-admin">' . $content . '</div>';
}
return $content;
}
/**
* Render fallback page when Astro build is not available
*
* @param string $page_name Page name
*/
private function render_fallback_page($page_name) {
?>
<div class="wrap tigerstyle-life9-admin">
<div class="tigerstyle-header">
<h1 class="wp-heading-inline">
<span class="tigerstyle-icon">🛡️</span>
TigerStyle Life9 - <?php echo esc_html(ucfirst($page_name)); ?>
</h1>
</div>
<div class="notice notice-warning">
<h3>⚠️ Development Mode</h3>
<p>The Astro frontend is not built yet. Please run the build process:</p>
<ol>
<li>Navigate to the plugin directory: <code><?php echo esc_html(TIGERSTYLE_LIFE9_PATH); ?></code></li>
<li>Install dependencies: <code>npm install</code></li>
<li>Build the frontend: <code>npm run build</code></li>
</ol>
</div>
<div class="tigerstyle-card">
<h3><?php echo esc_html(ucfirst($page_name)); ?> Page</h3>
<p>This page will display the <?php echo esc_html($page_name); ?> interface once the frontend is built.</p>
<?php if ($page_name === 'backup'): ?>
<p>The backup interface will allow you to:</p>
<ul>
<li>Select what to backup (files, database, media)</li>
<li>Configure encryption settings</li>
<li>Choose storage destination</li>
<li>Monitor backup progress in real-time</li>
</ul>
<?php elseif ($page_name === 'restore'): ?>
<p>The restore interface will allow you to:</p>
<ul>
<li>Select backup source (existing, upload, or URL)</li>
<li>Decrypt and validate backups</li>
<li>Choose what to restore</li>
<li>Monitor restore progress with safety checks</li>
</ul>
<?php elseif ($page_name === 'settings'): ?>
<p>The settings interface will allow you to:</p>
<ul>
<li>Configure security and encryption settings</li>
<li>Set up storage backends (local, S3, Google Drive)</li>
<li>Schedule automatic backups</li>
<li>Manage notifications and advanced options</li>
</ul>
<?php endif; ?>
</div>
</div>
<?php
}
/**
* Handle admin actions
*/
public function handle_admin_actions() {
// Handle any admin-specific actions here
if (isset($_GET['tigerstyle_action'])) {
$action = sanitize_text_field($_GET['tigerstyle_action']);
// Verify nonce
if (!wp_verify_nonce($_GET['_wpnonce'] ?? '', 'tigerstyle_action_' . $action)) {
wp_die(__('Security check failed', 'tigerstyle-life9'));
}
switch ($action) {
case 'clear_cache':
$this->clear_plugin_cache();
break;
case 'rebuild_assets':
$this->rebuild_astro_assets();
break;
}
}
}
/**
* AJAX handler for rendering Astro pages
*/
public function render_astro_page() {
check_ajax_referer('tigerstyle_life9_ajax', '_wpnonce');
if (!current_user_can('manage_options')) {
wp_die(__('Insufficient permissions', 'tigerstyle-life9'), 403);
}
$page = sanitize_text_field($_POST['page'] ?? '');
if (empty($page)) {
wp_send_json_error('Invalid page');
}
// Capture page output
ob_start();
$this->render_page($page);
$content = ob_get_clean();
wp_send_json_success(['content' => $content]);
}
/**
* Display admin notices
*/
public function display_admin_notices() {
// Only show on our admin pages
$screen = get_current_screen();
if (!$screen || strpos($screen->id, 'tigerstyle-life9') === false) {
return;
}
// Check if Astro build exists
$build_exists = file_exists(TIGERSTYLE_LIFE9_PATH . 'admin/assets/dist/manifest.json');
if (!$build_exists && current_user_can('manage_options')) {
?>
<div class="notice notice-info">
<h3>🚀 Welcome to TigerStyle Life9!</h3>
<p>To get started, please build the admin interface:</p>
<ol>
<li>Open terminal in plugin directory: <code><?php echo esc_html(TIGERSTYLE_LIFE9_PATH); ?></code></li>
<li>Install dependencies: <code>npm install</code></li>
<li>Build interface: <code>npm run build</code></li>
</ol>
<p>After building, refresh this page to see the full interface.</p>
</div>
<?php
}
}
/**
* Add plugin action links
*
* @param array $links Existing links
* @return array Modified links
*/
public function add_plugin_action_links($links) {
$tigerstyle_links = [
'<a href="' . admin_url('admin.php?page=tigerstyle-life9-backup') . '">' . __('Create Backup', 'tigerstyle-life9') . '</a>',
'<a href="' . admin_url('admin.php?page=tigerstyle-life9-settings') . '">' . __('Settings', 'tigerstyle-life9') . '</a>'
];
return array_merge($tigerstyle_links, $links);
}
/**
* Clear plugin cache
*/
private function clear_plugin_cache() {
// Clear any cached data
delete_transient('tigerstyle_life9_system_info');
delete_transient('tigerstyle_life9_backup_list');
// Reload asset manifest
$this->load_asset_manifest();
// Add success notice
add_action('admin_notices', function() {
echo '<div class="notice notice-success is-dismissible">';
echo '<p>' . __('Cache cleared successfully!', 'tigerstyle-life9') . '</p>';
echo '</div>';
});
}
/**
* Rebuild Astro assets
*/
private function rebuild_astro_assets() {
// This could trigger a rebuild process
// For now, just clear the manifest to force reload
$this->asset_manifest = [];
add_action('admin_notices', function() {
echo '<div class="notice notice-info">';
echo '<p>' . __('Asset rebuild triggered. Please run npm run build to update the interface.', 'tigerstyle-life9') . '</p>';
echo '</div>';
});
}
/**
* Get plugin capabilities for current user
*
* @return array Capabilities array
*/
public function get_user_capabilities() {
return [
'backup' => current_user_can('manage_options'),
'restore' => current_user_can('manage_options'),
'settings' => current_user_can('manage_options'),
'view_backups' => current_user_can('manage_options'),
'delete_backups' => current_user_can('manage_options')
];
}
}