diff --git a/includes/steps/50-theme.php b/includes/steps/50-theme.php index 6c4ee9a..58ab6d8 100644 --- a/includes/steps/50-theme.php +++ b/includes/steps/50-theme.php @@ -78,20 +78,82 @@ return new class extends WPH_Step { $f[] = $this->finding('active_update', 'ok', 'Active theme update', 'up to date', ''); } - // Inactive themes + // --- Themes to keep vs. removal candidates --------------------------- + // Keep: the active theme, its parent (if a child), and the newest default + // Twenty* theme installed (as a fallback we can swap to if the active + // theme breaks during work). Everything else is a removal candidate. $all = wp_get_themes(); - $inactive = []; - foreach ($all as $slug => $t) { - if ($slug === $active->get_stylesheet() || ($is_child && $slug === $parent->get_stylesheet())) continue; - $inactive[$slug] = (string) $t->get('Name'); + + $keep_slugs = [$active->get_stylesheet()]; + $keep_reasons = [$active->get_stylesheet() => 'active theme']; + if ($is_child && $parent && $parent->exists()) { + $parent_slug = $parent->get_stylesheet(); + $keep_slugs[] = $parent_slug; + $keep_reasons[$parent_slug] = 'parent of active theme'; + } + + // Find the newest default theme installed (priority by release year). + $default_priority = [ + 'twentytwentyfive', 'twentytwentyfour', 'twentytwentythree', + 'twentytwentytwo', 'twentytwentyone', 'twentytwenty', + 'twentynineteen', 'twentyseventeen', 'twentysixteen', + 'twentyfifteen', 'twentyfourteen', 'twentythirteen', + 'twentytwelve', 'twentyeleven', 'twentyten', + ]; + $fallback_slug = null; + foreach ($default_priority as $slug) { + if (isset($all[$slug])) { + $fallback_slug = $slug; + break; + } + } + if ($fallback_slug && !in_array($fallback_slug, $keep_slugs, true)) { + $keep_slugs[] = $fallback_slug; + $keep_reasons[$fallback_slug] = 'fallback default (newest Twenty* installed)'; + } elseif ($fallback_slug && in_array($fallback_slug, $keep_slugs, true)) { + // Active theme already is the newest Twenty* — note it but no extra entry. + $keep_reasons[$fallback_slug] .= ' (also serves as the default fallback)'; + } + + // Emit keeper rows (ok level). + foreach ($keep_slugs as $slug) { + if (!isset($all[$slug])) continue; // theme missing on disk + $f[] = $this->finding( + 'keep_' . sanitize_key($slug), + 'ok', + 'Keep — ' . $keep_reasons[$slug], + (string) $all[$slug]->get('Name') . ' (' . $slug . ')', + '' + ); + } + + // Emit removal candidates (info level). + $candidates = []; + foreach ($all as $slug => $t) { + if (in_array($slug, $keep_slugs, true)) continue; + $candidates[$slug] = (string) $t->get('Name'); + } + if (!$candidates) { + $f[] = $this->finding('rm_none', 'ok', 'Removal candidates', 'none', 'No inactive themes left to clear out.'); + } else { + // Summary line first, then each candidate. + $f[] = $this->finding( + 'rm_count', + count($candidates) > 3 ? 'warn' : 'info', + 'Removal candidates', + count($candidates) . ' theme(s)', + 'Inactive themes that aren\'t the active theme, its parent, or the fallback default — safe to remove unless flagged by the client.' + ); + foreach ($candidates as $slug => $name) { + $f[] = $this->finding( + 'rm_' . sanitize_key($slug), + 'info', + 'Candidate', + $name . ' (' . $slug . ')', + 'Delete via Appearance → Themes if not needed.' + ); + } } - $f[] = $this->finding( - 'inactive_themes', - count($inactive) > 3 ? 'warn' : 'info', - 'Inactive themes', - (string) count($inactive), - $inactive ? implode(', ', array_slice($inactive, 0, 6)) . (count($inactive) > 6 ? ' …' : '') : '' - ); return $f; }