From fdca9c30790f9bb54b6a18a220709f4f982f6e62 Mon Sep 17 00:00:00 2001 From: Steve Hanlon Date: Fri, 12 Jun 2026 10:22:29 +0100 Subject: [PATCH] Theme step: identify removal candidates explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the 'inactive themes count' finding with a clearer breakdown: Keep set (each gets a 'Keep — ' row): - The active theme (always) - The parent of the active theme (if a child theme is in use and the parent exists on disk) - The newest Twenty* default installed (as a fallback we can swap to if the active theme breaks during work) Removal candidates (one row per inactive theme not in the keep set): - 'Candidate' rows for the technician to walk down and remove - Summary line warns at >3 candidates - 'none' ok row if every installed theme is a keeper Smoke-tested on testsite with three configurations: - Default theme active, no child: keep active + Twenty Twenty-Five fallback; one removal candidate. - Cluttered (Astra + Hello Elementor + extra Twenty* installed): same keepers, 4 candidates surfaced. - Astra active (custom, no child): keep Astra + Twenty Twenty-Five fallback; 4 candidates including any unused Twenty* and Hello Elementor. --- includes/steps/50-theme.php | 86 +++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 12 deletions(-) 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; }