Recovery plugin: folder-agnostic detection + one-click install from Gitea
Detection (recovery-bootstrap.php): - Match on plugin Name + Author instead of hard-coded folder slug, so the recovery plugin is found regardless of whether it was unpacked as site-recovery/, wp-site-recovery/, or anything else. One-click install (recovery-installer.php — new): - Pulls site-recovery from a private Gitea repo via the standard archive endpoint with token auth. - Ref resolution order: latest release → latest tag → main branch HEAD. Lets us tag pinned releases in Gitea later without changing code. - upgrader_source_selection filter forces the unpacked folder name to 'site-recovery' regardless of the gitea wrapper-folder suffix. - Config from constants in wp-config.php (WPH_GITEA_HOST/OWNER/REPO/TOKEN) beats DB option storage. Constants are visually locked in the settings UI so admins can see they're inherited. Settings page (hidden submenu, reachable at Tools → Site Healthcheck → 'Configure gitea source'): - Host / Owner / Repo / Token fields - Inline 'Install now' button when configured + plugin not installed Bootstrap status panel: - Shows the recovery plugin's actual file path when active - 'Install from gitea (latest)' button when configured + missing - 'Configure gitea source' button when not configured + missing Install handler shows a success message via transient on the main healthcheck page after a successful install + activate.
This commit is contained in:
@@ -11,6 +11,8 @@ add_action('admin_post_wph_refresh_checks', 'wph_handle_refresh_checks');
|
||||
add_action('admin_post_wph_download_html', 'wph_handle_download_html');
|
||||
add_action('admin_post_wph_email_report', 'wph_handle_email_report');
|
||||
add_action('admin_post_wph_step_action', 'wph_handle_step_action');
|
||||
add_action('admin_post_wph_recovery_install', 'wph_handle_recovery_install');
|
||||
add_action('admin_post_wph_save_settings', 'wph_handle_save_settings');
|
||||
add_action('admin_enqueue_scripts', 'wph_enqueue_assets');
|
||||
|
||||
function wph_register_menu(): void {
|
||||
@@ -21,6 +23,14 @@ function wph_register_menu(): void {
|
||||
'site-healthcheck',
|
||||
'wph_render_admin_page'
|
||||
);
|
||||
add_submenu_page(
|
||||
null, // hidden — reachable via direct URL
|
||||
'Site Healthcheck Settings',
|
||||
'Site Healthcheck Settings',
|
||||
'manage_options',
|
||||
'site-healthcheck-settings',
|
||||
'wph_render_settings_page'
|
||||
);
|
||||
}
|
||||
|
||||
function wph_enqueue_assets($hook): void {
|
||||
@@ -100,6 +110,11 @@ function wph_render_admin_page(): void {
|
||||
echo '<div class="wrap">';
|
||||
echo '<h1>Site Healthcheck</h1>';
|
||||
|
||||
if ($msg = get_transient('wph_install_message')) {
|
||||
delete_transient('wph_install_message');
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html($msg) . '</p></div>';
|
||||
}
|
||||
|
||||
if (!$session) {
|
||||
wph_render_start_panel();
|
||||
echo '</div>';
|
||||
@@ -429,6 +444,103 @@ function wph_render_autocheck(WPH_Session $session, WPH_Step $step): void {
|
||||
<?php
|
||||
}
|
||||
|
||||
function wph_render_settings_page(): void {
|
||||
if (!current_user_can('manage_options')) wp_die('Forbidden');
|
||||
$c = WPH_Recovery_Installer::config();
|
||||
$o = WPH_Recovery_Installer::config_origin();
|
||||
$saved = isset($_GET['wph_saved']);
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>Site Healthcheck — Settings</h1>
|
||||
<p><a href="<?php echo esc_url(admin_url('tools.php?page=site-healthcheck')); ?>">← Back to healthcheck</a></p>
|
||||
|
||||
<?php if ($saved): ?><div class="notice notice-success is-dismissible"><p>Saved.</p></div><?php endif; ?>
|
||||
|
||||
<div class="wph-card">
|
||||
<h2>Recovery plugin source (Gitea)</h2>
|
||||
<p>One-click install pulls <code>site-recovery</code> from a private Gitea repo. The token needs read access to the repo only — a deploy / read-only PAT is safer than a personal token.</p>
|
||||
<p>Each field can be set via a constant in <code>wp-config.php</code> (then it takes precedence and the field below is locked).</p>
|
||||
|
||||
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
|
||||
<?php wp_nonce_field('wph_save_settings'); ?>
|
||||
<input type="hidden" name="action" value="wph_save_settings">
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><label for="wph-host">Gitea host</label></th>
|
||||
<td>
|
||||
<input id="wph-host" type="url" name="host" value="<?php echo esc_attr($c['host']); ?>" class="regular-text" placeholder="https://git.example.com" <?php disabled($o['host']); ?>>
|
||||
<?php if ($o['host']): ?><p class="description">Set via <code>WPH_GITEA_HOST</code> constant.</p><?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="wph-owner">Owner</label></th>
|
||||
<td>
|
||||
<input id="wph-owner" type="text" name="owner" value="<?php echo esc_attr($c['owner']); ?>" class="regular-text" placeholder="steve" <?php disabled($o['owner']); ?>>
|
||||
<?php if ($o['owner']): ?><p class="description">Set via <code>WPH_GITEA_OWNER</code> constant.</p><?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="wph-repo">Repo</label></th>
|
||||
<td>
|
||||
<input id="wph-repo" type="text" name="repo" value="<?php echo esc_attr($c['repo']); ?>" class="regular-text" placeholder="site-recovery" <?php disabled($o['repo']); ?>>
|
||||
<?php if ($o['repo']): ?><p class="description">Set via <code>WPH_GITEA_REPO</code> constant.</p><?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="wph-token">Token</label></th>
|
||||
<td>
|
||||
<input id="wph-token" type="password" name="token" value="<?php echo esc_attr($c['token']); ?>" class="regular-text" autocomplete="new-password" <?php disabled($o['token']); ?>>
|
||||
<?php if ($o['token']): ?><p class="description">Set via <code>WPH_GITEA_TOKEN</code> constant.</p>
|
||||
<?php else: ?><p class="description">Stored in WP options. Use a read-only deploy token scoped to this repo if possible.</p><?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><button class="button button-primary">Save settings</button></p>
|
||||
</form>
|
||||
|
||||
<?php if (WPH_Recovery_Installer::is_configured() && !WPH_Recovery_Bootstrap::is_installed()): ?>
|
||||
<hr>
|
||||
<h3>Install now</h3>
|
||||
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" onsubmit="return confirm('Download and install Site Recovery now?');">
|
||||
<?php wp_nonce_field('wph_recovery_install'); ?>
|
||||
<input type="hidden" name="action" value="wph_recovery_install">
|
||||
<button class="button button-primary">Install from gitea (latest)</button>
|
||||
</form>
|
||||
<?php elseif (WPH_Recovery_Bootstrap::is_installed()): ?>
|
||||
<hr>
|
||||
<p class="wph-ok">✓ Site Recovery is already installed at <code><?php echo esc_html((string) WPH_Recovery_Bootstrap::plugin_file()); ?></code>.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
function wph_handle_save_settings(): void {
|
||||
if (!current_user_can('manage_options')) wp_die('Forbidden');
|
||||
check_admin_referer('wph_save_settings');
|
||||
WPH_Recovery_Installer::save_options([
|
||||
'host' => (string) wp_unslash($_POST['host'] ?? ''),
|
||||
'owner' => (string) wp_unslash($_POST['owner'] ?? ''),
|
||||
'repo' => (string) wp_unslash($_POST['repo'] ?? ''),
|
||||
'token' => (string) wp_unslash($_POST['token'] ?? ''),
|
||||
]);
|
||||
wp_safe_redirect(admin_url('tools.php?page=site-healthcheck-settings&wph_saved=1'));
|
||||
exit;
|
||||
}
|
||||
|
||||
function wph_handle_recovery_install(): void {
|
||||
if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) wp_die('Forbidden');
|
||||
check_admin_referer('wph_recovery_install');
|
||||
@set_time_limit(120);
|
||||
$result = WPH_Recovery_Installer::install_and_activate();
|
||||
if (is_wp_error($result)) {
|
||||
wp_die('Install failed: ' . esc_html($result->get_error_message()) . ' <p><a href="' . esc_url(admin_url('tools.php?page=site-healthcheck-settings')) . '">Back to settings</a></p>');
|
||||
}
|
||||
set_transient('wph_install_message', sprintf('Site Recovery installed from %s "%s" and activated.', $result['ref']['type'], $result['ref']['ref']), 60);
|
||||
wp_safe_redirect(admin_url('tools.php?page=site-healthcheck'));
|
||||
exit;
|
||||
}
|
||||
|
||||
function wph_handle_step_action(): void {
|
||||
if (!current_user_can('manage_options')) wp_die('Forbidden');
|
||||
$step_id = isset($_POST['step']) ? sanitize_key((string) $_POST['step']) : '';
|
||||
|
||||
Reference in New Issue
Block a user