The hidden rows eating your database
You pull a fresh database backup and notice it's nearly double the size it was six months ago. You open the dump and scan for clues. The wp_posts table has ten times more rows than you have actual posts and pages. The extra rows are revisions — every draft save, every accidentally-hit Update button, every content tweak. WordPress keeps them all, forever, and never prompts you to clean them up.
On a WooCommerce store with 400 products edited an average of twelve times each, that's 4,800 revision rows quietly slowing every query, bloating every backup, and serving no purpose a week after the edit.
What most people do instead
DELETE FROM wp_posts WHERE post_type = 'revision'. One typo away from deleting real posts. Requires server access.A better way: one command, all revisions gone
Run clear revisions from the navigator. The command uses wp_delete_post($id, true) on every row in wp_posts where post_type = 'revision'. That calls the full WordPress delete pipeline — each revision's postmeta rows are cleaned up too, so there's no orphan meta left behind.
Type-filtered cleanup. Pass -post_type=product to clear only product revisions. Leave it out to clear every revision type (posts, pages, products, CPTs). Useful when you want aggressive cleanup on one content type but keep recent history on another.
How it works
Without -post_type: one query pulls every post_type = 'revision' ID. With -post_type: a subquery restricts to revisions whose parent matches that post type. Then each ID runs through wp_delete_post($id, true) — the second argument forces a true delete instead of trash, and all deleted_post hooks fire so any companion plugins can react.
-post_type=product to scope the cleanup. Omit for every type.wp_delete_post($id, true). Meta rows cleaned. Delete hooks fire.deleted return field — zero match means nothing to clean.| Parameter | Value |
|---|---|
-post_type | Optional. Restrict to revisions whose parent is of this post type (post, page, product, any CPT). Omit for all types. |
| Returns | deleted — count of revisions removed (iterable in branch conditions) |
| Delete mode | Hard delete via wp_delete_post(..., true). Not trash — rows are gone. |
| Pairs with | limit revisions — cap future revisions so the bloat doesn't come back |
| Can be used in |
Real example
You inherit a WooCommerce store with 400 products, each edited a dozen times during the catalog migration last year. You pull a fresh backup and it clocks in at 180 MB. You run clear revisions -post_type=product and get 4,812 deleted. Next backup: 95 MB. The wp_posts table just shed over four thousand dead rows.
You add the same command as a monthly Cron Schedule so the next round of catalog edits never accumulates more than a month of backup bloat.