fix: skip ghost plugin entries and drop descriptions in SITE.md Active Plugins - #3523
Merged
Merged
Conversation
…e Plugins Plugins recorded in the active_plugins / active_sitewide_plugins options but deleted from disk without being deactivated first were still rendered by name in SITE.md and NETWORK.md, with no way to tell them apart from a real plugin except a missing description. - inc/setup/site-md.php:322 (datamachine_site_section_plugins) and :583 (datamachine_network_section_plugins) shared the same defect: file_exists() guarded the description lookup but not the unconditional name print. Both now skip the entry entirely when the plugin file is missing from disk. - get_mu_plugins() / get_dropins() enumerate the filesystem directly, so the Must-Use Plugins and Drop-ins sections cannot produce ghost entries and were left unchanged. - datamachine_site_section_plugins() now emits plugin names only, no Description header text. SITE.md is always-on AI context and descriptions carried near-zero value there; wp plugin list is one command away for the full metadata. Fixes #3521
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3521
The bug (ghost entries)
inc/setup/site-md.php:322(datamachine_site_section_plugins()) guarded the description lookup withfile_exists()but printed the plugin name unconditionally from theactive_pluginsoption:Live proof on extrachill.com:
Yet SITE.md line 56 listed
- **breeze**— the only entry in the entire Active Plugins list with no description, which is exactly what this code path produces for a deleted-but-not-deactivated plugin: it fell through to theelsebranch's bare-name fallback sincefile_exists()failed, butget_plugin_data()never having been asked for a name meant the rawdirname()/basename()fallback ('breeze') got printed with$plugin_desc = ''. Breeze was replaced byextrachill-cachemonths ago and deleted from disk without ever being deactivated — theactive_pluginsoption still carried the stale entry, and SITE.md, being always-on AI context, was maximally privileged in telling agents a caching plugin was active that didn't exist.Same defect, same file
Grepped every
get_plugin_data/file_existspair in the file.datamachine_network_section_plugins()at (pre-fix) line 583 had the identical pattern for the NETWORK.md "Network Plugins" block (network-activated plugins) — fixed identically.datamachine_site_section_mu_plugins()anddatamachine_site_section_dropins()use core'sget_mu_plugins()/get_dropins(), which enumerate the actualwp-content/mu-pluginsandwp-contentdirectories viaopendir()/readdir()rather than reading a stored option — verified againstwp-admin/includes/plugin.php. They cannot produce ghost entries structurally, so no fix was needed there.Fix
Both
datamachine_site_section_plugins()anddatamachine_network_section_plugins()nowcontinuepast the entry entirely whenfile_exists( $plugin_path )is false, before ever computing a name.function_exists( 'get_plugin_data' )is now checked independently, so a plugin that genuinely exists on disk still gets a real name even in the rare caseget_plugin_data()isn't loaded yet.The scope reduction (drop descriptions)
The
## Active Pluginsblock was 6,076 of SITE.md's 8,726 total bytes (issue reported ~6,097/8,726 — consistent, small option-list drift since). SITE.md is injected into every AI call as always-on context; the per-pluginDescriptionheader (marketing copy — Gutenberg's is literally "Printing since 1440.") carries near-zero value there, andwp plugin listis one command away for anyone who needs it.datamachine_site_section_plugins()now emits- **Plugin Name**only, dropping thewp_strip_all_tags( $plugin_data['Description'] )suffix entirely. Kept the## Active Pluginsheading and list structure unchanged.datamachine_network_section_plugins()(NETWORK.md) never printed descriptions to begin with, so it's untouched on this axis.Before / after (measured against extrachill.com's live composed SITE.md)
(Computed by extracting the live
## Active Pluginsblock and simulating both fixes against it — descriptions stripped and thebreezeline removed.)Verification
php -l inc/setup/site-md.php— clean.site-md.phpgeneration existed. Addedtests/site-md-plugin-ghost-entries-smoke.php(standalone smoke, run withphp tests/site-md-plugin-ghost-entries-smoke.php, following the repo's existing*-smoke.phpconvention — no bundled WordPress test suite exists locally). It stubsget_option/get_site_option/get_plugin_data/is_multisiteagainst a real tempWP_PLUGIN_DIRcontaining one plugin that exists on disk and one that's listed in the options but has no file, reproducing the exact breeze scenario for bothSITE.md's Active Plugins andNETWORK.md's Network Plugins. 8/8 assertions pass:composer lint(phpcs) fails identically on unmodifiedmain— there's nophpcs.xml/phpcs.xml.distin the repo, so the default PSR2 ruleset (4-space indent) flags every line of this tabs-indented, WPCS-style file. Confirmed viagit stashthat this is pre-existing and unrelated to this change; the repo's real lint gate runs elsewhere (homeboy baseline config), not via barecomposer lint.tests/*-smoke.phpsuite standalone before and after this change (42 pre-existing failures on unmodifiedmainfrom environment/ordering issues unrelated tosite-md.php, e.g. missing DB/WP runtime — identical failure set with this diff applied, confirming no regression).