描述
WP-Sweep 会找出 WordPress 留下的数据行并将其移除。多年前你编辑过的文章的修订版本、属于已删除文章的元数据、未挂载到任何内容的术语、指向已不存在文章的术语关系、已过期的临时数据(transient):这些在 wp-admin 的任何地方都不可见,但它们全都存在于你的数据库中。
凡是可以触达数据行的,它都使用恰当的 WordPress 删除函数,而不是直接运行原始删除查询,因此其它插件依赖的钩子仍会被触发。只有 API 拒绝处理的行——对象 ID 为 0 的孤立元数据——才会被直接删除。
功能
- 修订版本
- 自动草稿
- 已删除的文章
- 未批准的评论
- 垃圾评论
- 删除的评论
- 孤立的文章元数据
- 孤立的评论元数据
- 孤立的用户元数据
- 孤立的分类项元数据
- 孤立的分类项关系
- 未使用的分类项
- 重复的文章元数据
- 重复的评论元数据
- 重复的用户元数据
- 重复的分类项元数据
- 瞬时选项
- 在文章元数据中嵌入缓存
- 优化数据库表
使用的删除函数
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()
已知的兼容性问题
这些插件会把数据存放在 WP-Sweep 视为「孤立」的位置。在清理前,请用「用法(Usage)」下的过滤器保护它们的元数据键。
捐赠
我大部分的空闲时间都花在了创建,更新,维护和支持这些插件上,如果您真的喜欢我的插件并且可以为我留下买一杯咖啡的钱,我将不胜感激。 如果没有,仍可随意使用它,没有任何义务。
用法
每次清理都不可撤销,因此请先备份你的数据库。
界面列出每一次清理,并简要说明它移除什么、有多少项、占表格的什么比例。勾选你想要的清理项并使用清理(Sweep)批量操作,或者逐行使用每行的清理(Sweep)和详情(Details)按钮。界面上没有任何东西需要 JavaScript:按钮都是普通链接,批量操作是一个普通表单。
没有设置界面。唯一值得调整的一项是详情(Details)列表显示多少项(默认 500),这由 wp_sweep_limit_details 过滤器控制。之所以有这个上限,是因为整个样本都会保存在内存中并写入页面。
WP-CLI
wp sweep --all
wp sweep revisions
wp sweep revisions auto_drafts deleted_posts
REST API
三条路由都需要 activate_plugins 权限。
GET /wp-json/sweep/v1/count/<name>
GET /wp-json/sweep/v1/details/<name>
DELETE /wp-json/sweep/v1/sweep/<name>
项目名
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`.
过滤器
wp_sweep_postmeta_whitelist(数组)——绝不可被删除的文章元数据键,作用于「孤立」或「重复」文章元数据清理项。*匹配任意连续字符。默认值:空。wp_sweep_commentmeta_whitelist(数组)——同上,针对评论元数据(comment meta)。wp_sweep_usermeta_whitelist(数组)——同上,针对用户元数据(user meta)。wp_sweep_termmeta_whitelist(数组)——同上,针对术语元数据(term meta)。wp_sweep_excluded_taxonomies(array)— 在清理孤立术语关系时排除的分类法。默认值:array( 'link_category' )。wp_sweep_excluded_termids(数组)——从「未使用术语」清理中排除的术语 ID。默认值:每个分类法的默认术语,以及任何作为其它术语上级的术语。wp_sweep_limit_details(整数)——「详情(Details)」列表显示多少项。默认值: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(字符串$capability、字符串$context)——所需的权限。$context为sweep、ajax或rest之一。wp_sweep_total_count(整数$count、字符串$name)——某次清理百分比所依据的数据行总数。wp_sweep_count(整数$count、字符串$name)——某次清理会移除多少项。wp_sweep_details(数组$details、字符串$name)——「详情(Details)」显示的样例列表。wp_sweep_sweep(string$message,string$name)— 过滤清理运行后返回的结果消息。
动作
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.
保护特定的文章元数据(post meta)键不被清理:
add_filter( 'wp_sweep_postmeta_whitelist', function ( $meta_keys ) {
$meta_keys[] = '_my_plugin_setting';
$meta_keys[] = '_acme_*';
return $meta_keys;
} );
示例 — 将额外分类法排除在孤立术语关系清理之外:
add_filter( 'wp_sweep_excluded_taxonomies', function ( $taxonomies ) {
$taxonomies[] = 'product_type';
return $taxonomies;
} );
屏幕截图



安装
- 安装并启用插件。界面位于
WP-Admin -> 工具(Tools)-> WP-Sweep。 - 在清理任何内容之前,请先备份你的数据库。每次清理都不可撤销,且没有撤消功能。
常见问题
-
工具 -> 清理(Sweep)界面有了新的地址
-
它仍在工具(Tools)下,但地址从
tools.php?page=wp-sweep/admin.php改为tools.php?page=wp-sweep。请更新你的书签。旧地址是传统的「以插件文件作为菜单别名(slug)」形式,会把插件的安装目录名写进页面 URL。这也正是为什么当有人把 WP-Sweep 安装到不同目录名(手动改名,或解压为
wp-sweep-2.0.0)时,该界面会出问题。现在这两种情况都不会发生了。 -
「全部清理(Sweep All)」去哪了?
-
每一行都有一个复选框,表格还有一个清理(Sweep)批量操作。勾选表头复选框并应用它,效果等同于以前的「全部清理(Sweep All)」,而且还能让你排除那些不想清理的项。
-
我调用 WPSweep::get_instance() 的代码片段失效了
-
类名在 2.0.0 中已重命名:
WPSweep现为WP_SweepWPSweep_Api现为WP_Sweep_APIWPSweep_Command现为WP_Sweep_Command
因此
WPSweep::get_instance()->sweep( 'revisions' )变为WP_Sweep::get_instance()->sweep( 'revisions' )。没有兼容别名,所以旧名称会触发致命错误,而非无声失败。每个过滤器和每个
wp_sweep_admin_*_sweep动作的命名都保持不变。 -
我可以使用哪些过滤器来防止数据被清理?
-
四个按类型的过滤器接收一份「绝不可删除」的元数据键列表,每个过滤器都支持用
*作为通配符:add_filter( 'wp_sweep_postmeta_whitelist', function ( $keys ) { $keys[] = '_my_plugin_setting'; $keys[] = '_acme_*'; return $keys; } );同样适用于
wp_sweep_commentmeta_whitelist、wp_sweep_usermeta_whitelist和wp_sweep_termmeta_whitelist。术语(term)由wp_sweep_excluded_termids保护,分类法(taxonomy)通过wp_sweep_excluded_taxonomies排除在「孤立术语关系」清理之外。在 2.0.0 中,这些列表同样保护重复元数据清理项——文档一直说它们会保护,但之前的代码从未做到。
-
我保护的某个键还是被清理了,或者保留了过多内容
-
在 2.0.0 之前,排除规则是一个 SQL
LIKE子句,而LIKE把下划线视为单字符通配符。因此模式_my_key也会匹配Xmy!key以及许多其它内容。现在匹配在 PHP 中进行,所以下划线就是下划线,只有*才是通配符。如果你依赖旧的行为,请检查你的列表。 -
删除 WP-Sweep 时,它会留下任何东西吗?
-
什么都不会留下。WP-Sweep 不存储任何选项行、不创建任何数据库表、不注册任何权限、也不安排任何定时事件。
uninstall.php仍会运行,并在整个网络(而非前一百个站点)范围内自行清理。
评价
贡献者及开发者
更新日志
2.0.1
- NEW: A Sweep link on the plugin’s row of the Plugins screen, opening Tools -> Sweep.
- FIXED: The Sweep screen timed out on large databases. 2.0.0 computed every count before printing a byte — and asked for each table’s total row count once per row instead of once, so
SELECT COUNT(*)ran against the postmeta table four times per load. The screen now renders at once and fetches the counts afterwards, one request at a time, so no single request outlives PHP’s time limit. Without JavaScript, a link computes them with the page the way 2.0.0 always did, and the newwp_sweep_defer_countsfilter restores that behaviour outright. - FIXED: Counting the duplicated meta sweeps fetched every duplicate row’s ids into PHP through
GROUP_CONCAT, just to add them up. On a postmeta table with millions of duplicates that alone could exhaust the request. The count now reads per-key totals only; the ids are read where they are needed, by the sweep that deletes them.
2.0.0
- 修复:「未使用术语」从计数列读取「未使用」,而核心自带的计数器统计的是已发布的文章——因此只被草稿、待审核文章、私密文章或回收站文章使用的术语会显示计数为零并被删除,连带删除其关系。这些文章恢复后失去标签,且无从知晓原因。现在一个术语必须完全没有任何关联才会被判定为未使用
- 修复:清理「已无任何内容注册的分类法」的术语时,最终执行
DELETE FROM wp_terms WHERE term_id NOT IN ( SELECT term_id FROM wp_term_taxonomy ),即表中所有游离的行,而非该清理项刚刚孤立的那些行。界面既未计数也未列出的行也一并被删除。现在它会明确列出它孤立的术语 - 修复:「孤立术语关系」通过在其
object_id中查找wp_posts来判断某行是否为孤立项——这只在分类法属于文章时才问对了问题。对于注册在用户或评论上的分类法,object_id是用户或评论 ID,因此任何 ID 恰好大于文章数量的关联关系都会被删除,而用户当时仍在。正因如此link_category曾被手工排除;现在该排除项由每个分类法注册时所针对的对象推导而来 - 修复:oEmbed 清理匹配
%_oembed_%,而在 LIKE 模式中下划线匹配任意单个字符——因此它的含义是「任何两侧带字符、且包含 oembed 的元数据键」,属于包含匹配而非前缀匹配。其它插件的键会连同缓存一起被硬删除。WordPress 将这些键写为_oembed_{hash},因此该模式现在已锚定在开头,并将下划线进行了转义 - 修复:oEmbed 清理是唯一一个从未查询受保护键列表的元数据清理项,因此站点显式添加到
wp_sweep_postmeta_whitelist的键还是被删除了——甚至读取了该列表却又将其忽略 - 修复:优化数据库时运行不带前缀的
SHOW TABLES,即整个 schema 中的每一个表。在多个安装共享的数据库上——一种常见的托管方式——详情视图会列出每个同租户的表,而清理会对本管理员并不管理的安装执行OPTIMIZE TABLE。现已将其限定在本安装的前缀范围内,并提供wp_sweep_optimize_tables供需要更多表的站点使用 - BREAKING: Requires WordPress 6.8 and PHP 8.2.
- 破坏性变更:界面仍在工具(Tools)下,但地址从
tools.php?page=wp-sweep/admin.php改为tools.php?page=wp-sweep。旧形式会把安装目录名写进 URL。 - 破坏性变更:类名已重命名:
WPSweep->WP_Sweep、WPSweep_Api->WP_Sweep_API、WPSweep_Command->WP_Sweep_Command。所有过滤器与动作的名称保持不变。 - 破坏性变更:
WP_Sweep::$limit_details已移除。请用limit_details()读取它,并用wp_sweep_limit_details过滤器修改它。 - 破坏性变更:六个
wp_sweep_admin_*_sweep动作现在在单一的清理表下方触发,顺序与以往一致,而不是分散在六个独立的表下方。 - 破坏性变更:「全部清理(Sweep All)」已移除。请改为勾选表头复选框并应用
清理(Sweep)批量操作,效果相同,且可让你排除不想清理的行。 - 新增:批量清理。勾选你想要清理的项,一次性运行,而不必一次点击一项。
- 新增:清理项在界面上按组划分。未筛选的视图将每项放在一个带图标的标题下——文章(Post)、评论(Comment)、用户(User)、术语(Term)、选项(Option)、数据库(Database)——同时仍是一张表,因此一次批量清理仍会运行你勾选的所有项。对某一列排序时会移除这些标题,而不是让它们继续描述已不再归组的行。
- 新增:分组过滤器与可排序列,基于真正的
WP_List_Table。 - 新增:整个界面在关闭 JavaScript 时也能工作。行操作是普通的带随机数(nonce)的链接,批量操作是普通的表单提交。
- 新增:元数据键白名单现在同样保护「重复」元数据清理项,而不仅是「孤立」项——readme 一直声称如此,但之前的代码从未做到。
- 新增:
wp_sweep_capability与wp_sweep_limit_details过滤器。WP-Sweep 没有设置界面:wp_sweep_limit_details就是修改「详情」上限的方式。 - 新增:每次清理都带有「移除什么」的描述,显示在其名称下方,并且值得关注的计数会被突出显示。
- 新增:
uninstall.php会在整个网络(而非前一百个站点)范围内清理。WP-Sweep 自身不存储任何内容:无选项行、无数据表、无权限、无定时事件。 - 新增:按照《插件手册》重构为
includes/结构。 - 新增:PHPUnit 与 vitest 测试套件,以及覆盖六种 WordPress 与 PHP 组合、单站点与多站点的 GitHub Actions CI。
- 变更:元数据键排除规则改为在 PHP 中匹配,而非使用 SQL
LIKE,因此受保护键中的下划线就是下划线,而不是通配符。 - 变更:每次数据库调用都经过同一个方法,且每条查询都已预处理。
- 修复:管理界面上一个存储型 XSS 漏洞。「详情」列表通过字符串拼接构建并以 HTML 注入,因此包含标记的评论作者名会在管理员浏览器中作为脚本执行。
- 修复:插件不再根据自身目录名构建路径,因此当它安装在
wp-sweep以外的目录时,管理脚本也能正常加载。 - 修复:将
wp_sweep_excluded_termids过滤为空数组会产生无效的 SQL,导致「未使用术语」计数显示为空白。 - 修复:只要术语 ID 与某个
default_<taxonomy>选项匹配,它就会从「未使用术语」清理中被排除,即使该选项指向的术语已不存在。WordPress 默认将default_link_category设为 2,因此在大多数站点上,任何 ID 为 2 的术语都会悄悄拒绝被清理。 - 修复:关闭 JavaScript 时清理数据后不显示任何结果;现在会显示结果。
- 修复:多站点卸载循环原先停在 100 个站点,为读取一个字段而实例化整个站点对象,并导致切换堆栈少退了一层。
- 修复:请求参数已进行净化,并与插件自身的清理项列表进行校验。
- 修复:
wp sweep打印的两条「Sweep Complete(清理完成)」消息,是插件中唯一从未经过翻译函数的字符串
