sandywp / plugins / wp-sweep
WP-Sweep
WP-Sweep allows you to clean up unused, orphaned and duplicated data in your WordPress. It also optimizes your database tables.
Ready in seconds.
v2.0.1 100,000+ installs WP 6.8+ PHP 8.2+

What you get inside
3 screens-
Tools -> WP-Sweep, listing every sweep with what it removes and how much of it there is
-
A Details list, showing a sample of what one sweep would remove
-
The same screen after a bulk sweep, reporting what went
About this plugin
WP-Sweep finds the rows WordPress leaves behind and removes them. Revisions of posts you edited years ago, meta belonging to a post that was deleted, terms attached to nothing, term relationships pointing at posts that no longer exist, expired transients: none of it is visible anywhere in wp-admin, and all of it is in your database.
It uses the proper WordPress delete functions wherever they can reach the row, rather than running raw delete queries, so the hooks other plugins rely on still fire. Only the rows the API refuses to touch — orphaned meta whose object ID is 0 — are deleted directly.
Features
- Revisions
- Auto drafts
- Deleted posts
- Unapproved comments
- Spammed comments
- Deleted comments
- Orphaned post meta
- Orphaned comment meta
- Orphaned user meta
- Orphaned term meta
- Orphaned term relationships
- Unused terms
- Duplicated post meta
- Duplicated comment meta
- Duplicated user meta
- Duplicated term meta
- Transient options
- oEmbed caches in post meta
- Optimizes database tables
Delete functions used
wp_delete_post_revision()wp_delete_post()wp_delete_comment()delete_post_meta()delete_comment_meta()delete_user_meta()delete_term_meta()wp_remove_object_terms()wp_delete_term()delete_transient()delete_site_transient()
Known incompatibilities
These plugins keep data in places WP-Sweep reads as orphaned. Protect their meta keys with the filters under Usage before sweeping.
- Custom Fonts
- Elementor Popup Builder
- MailPress
- Meta Slider
- Polylang
- Slider Revolution
- Viba Portfolio
- WPML
Donations
I spent most of my free time creating, updating, maintaining and supporting these plugins, if you really love my plugins and could spare me a couple of bucks, I will really appreciate it. If not feel free to use it without any obligations.
Usage
Every sweep is irreversible, so back your database up first.
The screen lists every sweep with a short description of what it removes, how many items that is, and what proportion of the table they are. Tick the ones you want and use the Sweep bulk action, or use each row’s Sweep and Details buttons one at a time. Nothing on the screen needs JavaScript: the buttons are ordinary links and the bulk action is an ordinary form.
There is no settings screen. The one thing worth tuning — how many items Details lists, 500 by default — is the wp_sweep_limit_details filter. The cap exists because the whole sample is held in memory and written into the page.
WP-CLI
wp sweep --all
wp sweep revisions
wp sweep revisions auto_drafts deleted_posts
REST API
All three routes need the activate_plugins capability.
GET /wp-json/sweep/v1/count/<name>
GET /wp-json/sweep/v1/details/<name>
DELETE /wp-json/sweep/v1/sweep/<name>
Item names
revisions, `auto_drafts`, `deleted_posts`, `unapproved_comments`, `spam_comments`, `deleted_comments`, `transient_options`, `orphan_postmeta`, `orphan_commentmeta`, `orphan_usermeta`, `orphan_termmeta`, `orphan_term_relationships`, `unused_terms`, `duplicated_postmeta`, `duplicated_commentmeta`, `duplicated_usermeta`, `duplicated_termmeta`, `optimize_database`, `oembed_postmeta`.
Filters
wp_sweep_postmeta_whitelist(array) — post meta keys that must never be deleted, by the orphaned or the duplicated post meta sweep.*matches any run of characters. Default: empty.wp_sweep_commentmeta_whitelist(array) — the same, for comment meta.wp_sweep_usermeta_whitelist(array) — the same, for user meta.wp_sweep_termmeta_whitelist(array) — the same, for term meta.wp_sweep_excluded_taxonomies(array) — taxonomies left out of the orphaned term relationships sweep. Default:array( 'link_category' ).wp_sweep_excluded_termids(array) — term IDs left out of the unused terms sweep. Default: each taxonomy’s default term, plus any term that is the parent of another.wp_sweep_limit_details(int) — how many items a Details list shows. Default: 500.wp_sweep_defer_counts(bool) — whether the Sweep screen renders first and fetches its counts afterwards, one at a time. Returnfalseto compute every count with the page, as versions before 2.0.1 always did. Default:true.wp_sweep_capability(string$capability, string$context) — the capability required.$contextis one ofsweep,ajaxorrest.wp_sweep_total_count(int$count, string$name) — the total number of rows a sweep’s percentage is measured against.wp_sweep_count(int$count, string$name) — how many items a sweep would remove.wp_sweep_details(array$details, string$name) — the sample list shown by Details.wp_sweep_sweep(string$message, string$name) — the message reported after a sweep has run.
Actions
wp_sweep_admin_post_sweep, `wp_sweep_admin_comment_sweep`, `wp_sweep_admin_user_sweep`, `wp_sweep_admin_term_sweep`, `wp_sweep_admin_option_sweep` and `wp_sweep_admin_database_sweep` all fire below the sweep table, in that order.
Protect specific post meta keys from being swept:
add_filter( 'wp_sweep_postmeta_whitelist', function ( $meta_keys ) {
$meta_keys[] = '_my_plugin_setting';
$meta_keys[] = '_acme_*';
return $meta_keys;
} );
Exclude an additional taxonomy from the orphaned term relationships sweep:
add_filter( 'wp_sweep_excluded_taxonomies', function ( $taxonomies ) {
$taxonomies[] = 'product_type';
return $taxonomies;
} );
Questions
- The Tools -> Sweep screen has a new address
It is still under Tools, but the address changed from
tools.php?page=wp-sweep/admin.phptotools.php?page=wp-sweep. Update any bookmark.The old address was the legacy “plugin file as menu slug” form, which put the plugin’s installation directory name into the page URL. That is also why the screen used to break for anyone who installed WP-Sweep under a different directory name — renamed by hand, or unzipped as
wp-sweep-2.0.0. Neither happens now.- Where did Sweep All go?
Every row has a checkbox and the table has a Sweep bulk action, so ticking the header checkbox and applying it does what Sweep All did — and lets you leave out the ones you do not want.
- My snippet calling WPSweep::get_instance() stopped working
The classes are renamed in 2.0.0:
WPSweepis nowWP_SweepWPSweep_Apiis nowWP_Sweep_APIWPSweep_Commandis nowWP_Sweep_Command
So
WPSweep::get_instance()->sweep( 'revisions' )becomesWP_Sweep::get_instance()->sweep( 'revisions' ). There is no compatibility alias, so the old name raises a fatal error rather than failing quietly.Every filter and every
wp_sweep_admin_*_sweepaction keeps the name it had.- Which filters can I use to protect data from being swept?
Four per-type filters take a list of meta keys that must never be deleted, and each supports
*as a wildcard:add_filter( 'wp_sweep_postmeta_whitelist', function ( $keys ) { $keys[] = '_my_plugin_setting'; $keys[] = '_acme_*'; return $keys; } );The same applies to
wp_sweep_commentmeta_whitelist,wp_sweep_usermeta_whitelistandwp_sweep_termmeta_whitelist. Terms are protected withwp_sweep_excluded_termids, and taxonomies are kept out of the orphaned term relationships sweep withwp_sweep_excluded_taxonomies.In 2.0.0 these lists also protect the duplicated meta sweeps, which the documentation always said they did and the code never did.
- A key I protected was swept anyway, or far too much was kept
Before 2.0.0 the exclusion was a SQL
LIKEclause, andLIKEtreats an underscore as a single-character wildcard. A pattern of_my_keytherefore also matchedXmy!key, and a good deal else. Matching happens in PHP now, so an underscore is an underscore and only*is a wildcard. Check your list if you were relying on the old behaviour.- Does WP-Sweep leave anything behind when I delete it?
Nothing. WP-Sweep stores no option rows, creates no database tables, registers no capabilities and schedules no events.
uninstall.phpruns anyway and sweeps up after itself across a whole network rather than the first hundred sites.
sandywp / also on the shelf
Try another plugin
4.9 · 10K+ installs
Simple Revisions Delete adds a discreet link within a post submit box to let you purge (delete) its revisions via AJAX. Bulk…
4.8 · 10K+ installs
Get rid of duplicate posts and pages (any post type) on your blog with manual or automatic modes.
4.6 · 9K+ installs
Plugin that tracks autoloaded options usage and allows the user to optimize them.
Spin up a real WordPress site in seconds.
Test plugins, build a demo, hand a client a link — then squash it and start again. No local setup, no Docker.