Phase 3 v1: autocheck framework + six step automations
Infrastructure:
- WPH_Step::autocheck($session_state) returns an array of findings
shaped {id, level: ok/warn/bad/info, label, value, detail}.
- WPH_Session stores results keyed by step id (persisted in the option-
backed session).
- WPH_Step::has_autocheck() reflection check so the UI only renders the
panel for steps that implement automation.
- 'Run checks' / 'Refresh' button per step, admin-post handler runs
autocheck() and stashes the result on the session.
- Findings rendered as a coloured table on the step card; included
verbatim in the Markdown report with status icons.
Step automations implemented:
- Step 1 (Backup): detection of 11 known backup plugins by slug;
active/inactive state; UpdraftPlus last-backup timestamp.
- Step 2 (Environment): PHP version + EOL, WP version vs latest, disk
usage, wp-config flags, file perms on wp-config/wp-content/uploads,
error-log sizes.
- Step 4 (Plugins): WP.org API enrichment with 24h transient cache —
last_updated, active_installs, abandonment flag, removed-from-repo
flag, update-available count. Summary line at the top.
- Step 8 (Security): SSL cert expiry via stream_socket_client +
openssl_x509_parse, administrator audit, xmlrpc reachability, login
URL hardening detection.
- Step 9 (Database): spam comments, post revisions, autoload size (WP
6.6+ value handling), top 3 largest tables.
- Step 11 (Small fixes): deactivated-but-installed plugin list,
homepage alt-text scan.
Smoke-tested on testsite — all six steps return findings with
correctly-classified levels. Report regenerated with automated findings
section.
This commit is contained in:
@@ -7,6 +7,7 @@ add_action('admin_post_wph_save_step', 'wph_handle_save_step');
|
||||
add_action('admin_post_wph_finish', 'wph_handle_finish');
|
||||
add_action('admin_post_wph_discard', 'wph_handle_discard');
|
||||
add_action('admin_post_wph_download_report', 'wph_handle_download_report');
|
||||
add_action('admin_post_wph_refresh_checks', 'wph_handle_refresh_checks');
|
||||
add_action('admin_enqueue_scripts', 'wph_enqueue_assets');
|
||||
|
||||
function wph_register_menu(): void {
|
||||
@@ -52,6 +53,21 @@ function wph_inline_css(): string {
|
||||
.wph-bootstrap-panel { padding:.6rem 1rem; background:#f6f7f7; border:1px solid #dcdcde; border-radius:6px; margin-bottom:.75rem; }
|
||||
.wph-bootstrap-panel h3 { margin:0 0 .35rem; font-size:1rem; }
|
||||
.wph-actions { display:flex; gap:.5rem; align-items:center; margin-top:.4rem; }
|
||||
.wph-autocheck { background:#f6f7f7; border:1px solid #dcdcde; border-radius:6px; padding:.6rem 1rem; margin:.6rem 0; }
|
||||
.wph-autocheck header { display:flex; justify-content:space-between; align-items:center; margin:0 0 .4rem; }
|
||||
.wph-autocheck header h3 { margin:0; font-size:.95rem; }
|
||||
.wph-autocheck table { width:100%; border-collapse:collapse; }
|
||||
.wph-autocheck td { padding:.25rem .4rem; vertical-align:top; border-bottom:1px solid #f0f0f1; }
|
||||
.wph-autocheck tr:last-child td { border-bottom:0; }
|
||||
.wph-autocheck .lvl { width:1.4rem; text-align:center; font-weight:600; }
|
||||
.wph-autocheck .lvl-ok { color:#1a8917; }
|
||||
.wph-autocheck .lvl-warn { color:#b07a00; }
|
||||
.wph-autocheck .lvl-bad { color:#c0392b; }
|
||||
.wph-autocheck .lvl-info { color:#646970; }
|
||||
.wph-autocheck .label { font-weight:600; }
|
||||
.wph-autocheck .value { color:#1d1d1f; }
|
||||
.wph-autocheck .detail { color:#646970; font-size:.9em; }
|
||||
.wph-checked-at { color:#646970; font-size:.85em; }
|
||||
';
|
||||
}
|
||||
|
||||
@@ -164,6 +180,7 @@ function wph_render_step_card(WPH_Session $session, WPH_Step $step): void {
|
||||
<?php if ($status === WPH_Session::STATUS_BLOCKED && ($esc = $step->escalation())): ?>
|
||||
<div class="wph-escalation"><?php echo esc_html($esc); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php wph_render_autocheck($session, $step); ?>
|
||||
<p>
|
||||
<label>
|
||||
<strong>Status:</strong>
|
||||
@@ -257,6 +274,56 @@ function wph_handle_discard(): void {
|
||||
exit;
|
||||
}
|
||||
|
||||
function wph_render_autocheck(WPH_Session $session, WPH_Step $step): void {
|
||||
if (!$step->has_autocheck()) return;
|
||||
$result = $session->get_autocheck($step->id());
|
||||
?>
|
||||
<div class="wph-autocheck">
|
||||
<header>
|
||||
<h3>Automated checks</h3>
|
||||
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="display:inline">
|
||||
<?php wp_nonce_field('wph_refresh_checks_' . $step->id()); ?>
|
||||
<input type="hidden" name="action" value="wph_refresh_checks">
|
||||
<input type="hidden" name="step" value="<?php echo esc_attr($step->id()); ?>">
|
||||
<button class="button button-small"><?php echo $result ? 'Refresh' : 'Run checks'; ?></button>
|
||||
</form>
|
||||
</header>
|
||||
<?php if (!$result): ?>
|
||||
<p class="description">No automated checks have been run for this step yet.</p>
|
||||
<?php else: ?>
|
||||
<table>
|
||||
<?php foreach ($result['findings'] as $finding):
|
||||
$icon = ['ok' => '✓', 'warn' => '⚠', 'bad' => '✗', 'info' => '·'][$finding['level']] ?? '·';
|
||||
?>
|
||||
<tr>
|
||||
<td class="lvl lvl-<?php echo esc_attr($finding['level']); ?>"><?php echo esc_html($icon); ?></td>
|
||||
<td class="label"><?php echo esc_html($finding['label']); ?></td>
|
||||
<td class="value"><?php echo esc_html($finding['value']); ?></td>
|
||||
<td class="detail"><?php echo esc_html($finding['detail']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<p class="wph-checked-at">Checked <?php echo esc_html(human_time_diff((int) $result['checked_at'], time())); ?> ago (<?php echo esc_html(date('Y-m-d H:i', (int) $result['checked_at'])); ?>)</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
function wph_handle_refresh_checks(): void {
|
||||
if (!current_user_can('manage_options')) wp_die('Forbidden');
|
||||
$step_id = isset($_POST['step']) ? sanitize_key((string) $_POST['step']) : '';
|
||||
check_admin_referer('wph_refresh_checks_' . $step_id);
|
||||
$session = WPH_Session::current();
|
||||
if (!$session || $session->is_finished()) wp_die('No active session.');
|
||||
$step = WPH_Steps::instance()->get($step_id);
|
||||
if (!$step) wp_die('Unknown step.');
|
||||
@set_time_limit(60);
|
||||
$findings = $step->autocheck($session->data());
|
||||
$session->set_autocheck($step_id, $findings);
|
||||
wp_safe_redirect(admin_url('tools.php?page=site-healthcheck#step-' . rawurlencode($step_id)));
|
||||
exit;
|
||||
}
|
||||
|
||||
function wph_handle_download_report(): void {
|
||||
if (!current_user_can('manage_options')) wp_die('Forbidden');
|
||||
check_admin_referer('wph_download_report');
|
||||
|
||||
Reference in New Issue
Block a user