Completes the grading rubric and the artifact surface. Grade B was published
from the start but could never be assigned, because nothing detected the
conditional cleanup it describes; that gap is now closed, and the last artifact
types the manifest reserved are detected.
Added
-
Conditional cleanup detection, and with it grade B. An uninstall routine
gated on a stored setting —if (!get_option('..._delete_data')) return;, or
the same removals wrapped inside theif— is now recognised, and the gating
option and its default are reported in the cleanup block and the manifest.
This is the plugin that is technically clean and practically dirty: the setting
almost always defaults to off, so on a real site nothing is removed. Naming it
B is more useful than folding it into A or C.A guard only counts when it actually gates cleanup — it bails out early, or a
removal sits inside it — so an unrelatedif (get_option('schema') === 'v2')
in the same routine does not cost an otherwise clean plugin its A. -
Directories —
wp_mkdir_pandmkdir, withWP_CONTENT_DIR,
WP_PLUGIN_DIR, andABSPATHrewritten to portable{content_dir},
{plugin_dir}, and{abspath}tokens, the same way{prefix}works for
tables. A path that is only a root with nothing under it is skipped rather than
reported as a directory the plugin created. -
Rewrite rules —
add_rewrite_rule,add_rewrite_endpoint, and
add_rewrite_tag. They weigh lightly: a rule is one entry in a single option
and disappears on the next permalink flush. -
Action Scheduler jobs —
as_schedule_recurring_action,
as_schedule_single_action,as_schedule_cron_action, and
as_enqueue_async_action. A queued job behaves like a cron event, so it weighs
like one.
Fixed
-
A cron event scheduled with arguments is no longer reported as cleaned by an
argument-lesswp_clear_scheduled_hook(). That call only removes events
registered without arguments, so the event actually survives and keeps firing —
Sediment was crediting a cleanup that does not happen. Clearing it needs
wp_unschedule_hook(), which is what the generateduninstall.phpnow emits
for those events. -
The
$wpdbhandle is recognised when held as a property ($this->wpdb),
not only as the global variable, so table creation and drops written that way
are no longer missed. Recognition lives in one helper rather than three
hand-rolled checks, and still requires the namewpdb— an alias under a
different name is missed rather than guessed at. -
Cleanup detection for the new types —
as_unschedule_all_actions,
as_unschedule_action,rmdir, andflush_rewrite_rules— so a plugin that
tidies up after itself is credited for it.
Changed
- A key written from several places counts as cleaned only when every write of
it is cleaned. A hook scheduled both with and without arguments is one key
with two fates; the previous "any write cleaned" merge could report such a
plugin as spotless while an event kept firing. - Scores are held inside the band their letter allows, so a C with one stray
transient can no longer outrank a B on a leaderboard. - Grade summaries no longer state which way a gating setting must be set.
Sediment sees which option decides, not the polarity of the comparison, and
"keep my data" gates are as common as "delete my data" ones — so the wording
names the setting and its default rather than asserting a direction. - Every artifact type the manifest reserves is now populated by detection; the
createsgroups are unchanged, so consumers need no update. A finding type
with no group now raises an error instead of vanishing from the document. - WordPress's own directories (
uploads,plugins,themes, …) are recognised
as core, so they are never attributed to a plugin or offered for deletion.
Security
- A table name cut short by a dynamic tail is no longer claimed. Resolving
"CREATE TABLE {$wpdb->prefix}logs{$suffix}"stops mid-name, and treating the
fragment as the table invented one the plugin never creates — which a generated
uninstall.phpwould then drop. Such names now require proof that the name
ended before the cut. wp_clear_scheduled_hook($hook, $args)no longer credits an argument-less
event, since it clears only events registered with those exact arguments.- The
$wpdbhandle is accepted only as$wpdb,$this->wpdb, or
self::$wpdb, so an unrelated object's->wpdbcannot credit a table drop.