=== Ghost Buster ===
Contributors: wordcraftstack
Tags: database, cleanup, optimization, performance, transients
Requires at least: 5.8
Tested up to: 6.9
Stable tag: 1.3.0
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Finds and removes orphaned database data across six categories — health score, active-plugin verification, and surgical per-row delete controls.

== Description ==

Unlike plugins that just give you a reckless "Delete All" button, Ghost Buster **categorizes** orphaned data and tells you exactly *why* each row is (or isn't) a ghost.

**Six-tab interface:**

* **Overview** — A 0–100 health score (CSS conic-gradient ring, no JavaScript chart library), a DB table size report from `information_schema`, and a prioritized cleanup checklist.
* **Autoloaded Options** — Every row loaded into RAM on every page request, ranked by size. Active-plugin verification cross-checks `active_plugins` so Medium rows show a green "Active" badge when the plugin is still live — no false alarms.
* **Transients** — Expiry status determined via a single SQL JOIN (no N+1 queries). "Delete Expired" and "Delete All" quick actions, plus per-row checkboxes.
* **Orphaned Post Meta** — `wp_postmeta` rows whose parent post no longer exists, identified by a LEFT JOIN. Guaranteed safe.
* **Orphaned User Meta** — `wp_usermeta` rows whose user has been deleted. Same guaranteed-safe pattern.
* **Post Revisions** — All `wp_posts` revision rows. "Keep Last N Per Post" quick action (choose 1 / 3 / 5 / 10), or cherry-pick individual rows.

**Safety architecture:**

Every delete operation passes through two independent guards:

1. A server-side protected-prefix blocklist (core WP keys: `siteurl`, `active_plugins`, auth salts, etc.) that can never be deleted regardless of what is sent.
2. A re-validation query that confirms the row is genuinely orphaned immediately before the DELETE runs.

No data leaves your server. No external API calls. No telemetry.

**60+ plugin prefix map** covering: Elementor, Jetpack, WooCommerce, Yoast SEO, Rank Math, Akismet, Contact Form 7, WPBakery, Revolution Slider, WPML, Polylang, WPForms, Gravity Forms, Mailchimp, Ninja Forms, Wordfence, Sucuri, iThemes Security, WP Rocket, W3 Total Cache, Autoptimize, EWWW, Imagify, ShortPixel, Smush, UpdraftPlus, BackWPup, Duplicator, All in One SEO, Divi, Avada, Astra, OceanWP, GeneratePress, Beaver Builder, Popup Maker, The Events Calendar, Easy Digital Downloads, GiveWP, YITH, MailPoet, TablePress, Loco Translate, and more.

== Installation ==

1. Upload the `ghost-buster` folder to `/wp-content/plugins/`.
2. Activate the plugin through the **Plugins** screen in WordPress.
3. Navigate to **Ghost Buster** in the admin sidebar.
4. Review the Overview tab health score, then work through each tab top-to-bottom.

== Frequently Asked Questions ==

= Is it safe to delete transients? =
Yes. Transients are temporary cache entries. WordPress regenerates them automatically the next time they are needed. Deleting them may cause one slightly slower page load as the cache warms up again — nothing more.

= What does the "Active" badge mean on the Autoloaded tab? =
It means the plugin that owns that option is currently active. The row is in use and should not be deleted. Ghost Buster cross-checks `active_plugins` in real time so you never delete live plugin data by mistake.

= How does "Keep Last N Per Post" work for revisions? =
Ghost Buster queries every post that has revisions, sorts them newest-first, skips the first N, and deletes the rest using WordPress's own `wp_delete_post_revision()` function — which also cleans up related post meta.

= Will Ghost Buster delete any WordPress core data? =
No. A protected-prefix blocklist (checked server-side on every request) prevents deletion of `siteurl`, `blogname`, `active_plugins`, authentication salts, widget data, and other core options regardless of what is submitted.

= Does Ghost Buster store any data of its own? =
No. It reads from your existing tables and deletes rows you explicitly select. Nothing is stored, no options are written, and the uninstall handler leaves your database exactly as it found it.

== Screenshots ==

1. Overview tab — health score ring + DB table sizes + priority checklist
2. Autoloaded Options tab — ghost probability with active-plugin verification
3. Transients tab — expiry status via SQL JOIN, expired/all quick actions
4. Orphaned Post Meta tab — LEFT JOIN orphan detection with bulk delete
5. Post Revisions tab — "Keep Last N" quick action + per-row checkboxes

== Changelog ==

= 1.3.0 =
* Added Overview tab with CSS conic-gradient health score (0–100) and DB table sizes from `information_schema`.
* Added Orphaned User Meta tab (mirrors Post Meta pattern for `wp_usermeta`).
* Added Post Revisions tab with "Keep Last N Per Post" server-side quick action.
* Added `uninstall.php`.

= 1.2.0 =
* Added three-tab interface: Autoloaded Options, Transients, Orphaned Post Meta.
* Transient expiry determined via SQL LEFT JOIN (no N+1 queries).
* Active-plugin verification: Medium rows downgrade to "Active" badge when plugin is live.
* Dedicated AJAX actions for transients (expired-only or all) and post meta (by meta_id).

= 1.1.0 =
* Expanded plugin prefix map to 60+ entries across 10 categories.
* Added checkbox-based per-row selection with "Exorcise Selected" AJAX action.
* Two-layer delete safety: protected-prefix blocklist + scanner re-validation.
* Separated code into `class-gb-scanner.php` and `class-gb-ajax.php`.

= 1.0.0 =
* Initial release. Basic autoloaded options scanner with ghost probability detection.
