Title: Revision Retention
Author: Acato
Published: <strong>September 24, 2026</strong>
Last modified: September 24, 2026

---

Search plugins

![](https://ps.w.org/revision-retention/assets/banner-772x250.png?rev=3711158)

![](https://ps.w.org/revision-retention/assets/icon-256x256.png?rev=3711158)

# Revision Retention

 By [Acato](https://profiles.wordpress.org/acato/)

[Download](https://downloads.wordpress.org/plugin/revision-retention.1.1.0.zip)

 * [Details](https://wordpress.org/plugins/revision-retention/#description)
 * [Reviews](https://wordpress.org/plugins/revision-retention/#reviews)
 *  [Installation](https://wordpress.org/plugins/revision-retention/#installation)
 * [Development](https://wordpress.org/plugins/revision-retention/#developers)

 [Support](https://wordpress.org/support/plugin/revision-retention/)

## Description

WordPress keeps post revisions forever unless you set `WP_POST_REVISIONS`, and even
then the only thing you can set is a count that applies to the whole site and only
takes effect while a post is being saved. A site that has been running for a few
years ends up with tens of thousands of revisions nobody will ever open, slowing
down queries and padding out every backup.

This plugin gives revisions a retention policy instead:

 * **Always keep the newest few.** A floor that is never crossed, however old those
   revisions are.
 * **Remove what is older than a threshold.** Anything past the floor and past the
   age you pick, from a week up to five years.
 * **Set both per post type.** Long history for posts, a short leash on pages, nothing
   at all for a custom post type that churns.
 * **Clean up what is already there.** A scheduled sweep works through the site 
   in batches, so an old site with a large `wp_posts` table is cleaned up over several
   quiet runs rather than one heavy one.

#### The two numbers work together

This is the part worth understanding, because it is what keeps the plugin safe to
switch on:

 * **Always keep** is a floor. The newest N revisions of a post are never deleted,
   whatever their age.
 * **Remove older than** is a ceiling, and it only applies to what is left above
   the floor.

So a page that was last edited three years ago, with forty revisions and a policy
of _keep 5, remove older than 365 days_, keeps its five most recent revisions and
loses the other thirty-five. It does not lose its whole history just because all
of it is old.

Setting **Always keep** to -1 means every revision is retained and that post type
is never swept, whatever the age threshold says.

Autosaves are never touched. An autosave is somebody’s unsaved work rather than 
a point in the history.

#### Enable revisions where WordPress does not

Some post types ship without revision support, so nothing is recorded at all. The
settings screen lists every eligible post type with a checkbox to switch revisions
on for it. It applies from the next time such a post is saved.

#### On a schedule

The sweep runs in the background at an interval you choose. Every run books the 
next one itself: another batch in a minute while there is work left, or the next
full run at your interval once the site is clean. A sweep that gets interrupted 
continues where it stopped instead of starting over.

There are also **Preview** and **Run one batch now** buttons on the settings screen.
Preview reports what the policy would remove without deleting anything.

#### A log of every sweep

Switch on the log and every sweep that removes revisions gets an entry on the **
Logs** tab: whether the schedule, somebody on the settings screen, or WP-CLI ran
it, who that was, how many revisions it removed from how many posts, and per post
type. A sweep spread over many batches is one entry. The tab shows them on a timeline,
with a bar per day for the last month. Entries are kept for as long as you choose,
from a week to a year, and older ones are deleted daily. Previews are never logged.

Each site keeps its own log, next to its own revisions. On multisite the network
screen’s **Logs** tab shows every site’s log together on one timeline, with each
entry naming the site it ran on and linking to that site’s own log.

#### From WP-CLI

    ```
    # What is the policy, and what has it still got to do?
    wp revision-retention status

    # The rule and the stored revisions of every post type.
    wp revision-retention post-types

    # See what would go, without deleting anything.
    wp revision-retention run --dry-run

    # Apply the policy to pages only.
    wp revision-retention run --post-type=page --yes
    ```

#### On multisite

The network admin sets the defaults for every site, under **Network Admin  Settings
Revision Retention**. A switch there decides whether sites may override them. When
they may, each site’s own screen inherits every field it leaves empty and shows 
the network value behind it; when they may not, that screen reports the policy and
nothing more.

Settings travel the other way too. Once you have a policy on one site that you want
everywhere, **Save as network default** on that site’s screen makes it the default
for the whole network and drops the site’s own copy, so the site simply inherits
what it already had. Sites with settings of their own keep them; only the defaults
underneath move. The button only appears for a network administrator, since it decides
what every other site starts from.

When the network keeps the policy to itself, a site’s screen can still **Preview**—
reading what the policy would take away costs nothing — but only a network administrator
can actually sweep that site. Otherwise a network could switch the scheduled sweep
off and a site administrator could still delete by hand, which is the opposite of
what locking the policy is for.

The network screen can **Preview every site**, walking the whole network and reporting
what the policy would remove without deleting anything, and **Sweep every site now**,
which books a run on each site that has the scheduled sweep switched on. The sweep
itself always runs per site, under whatever policy that site ends up with.

Its **Logs** tab brings the log of every site together, so you can see what was 
removed across the network, where, and by whom, without opening each site in turn.

#### For developers

    ```
    // Never touch these posts, whatever the policy says.
    add_filter( 'revision_retention_excluded_posts', fn( $ids ) => [ ...$ids, 42, 108 ] );

    // Decide the rule for a post type in code.
    add_filter( 'revision_retention_rule', function ( $rule, $post_type ) {
        return 'page' === $post_type ? new Retention_Rule( 20, 90 ) : $rule;
    }, 10, 2 );

    // Change which post types can have a policy at all.
    add_filter( 'revision_retention_eligible_post_types', $callback );
    ```

Deletion goes through `wp_delete_post_revision()` rather than a bulk query, so post
meta and term relationships are cleaned up the way WordPress expects and other plugins
see the hooks they are listening for.

Development happens at [github.com/acato-plugins/revision-retention](https://github.com/acato-plugins/revision-retention).

## Screenshots

[⌊The settings screen, with the policy in force at the top and every post type's
rule and stored revisions below it.⌉⌊The settings screen, with the policy in force
at the top and every post type's rule and stored revisions below it.⌉[

The settings screen, with the policy in force at the top and every post type’s rule
and stored revisions below it.

[⌊Preview reporting what the policy would take from each post, and what each post
keeps, before anything is deleted.⌉⌊Preview reporting what the policy would take
from each post, and what each post keeps, before anything is deleted.⌉[

Preview reporting what the policy would take from each post, and what each post 
keeps, before anything is deleted.

[⌊The schedule: how often the sweep runs, how many posts it looks at per batch, 
and the most it may delete in one.⌉⌊The schedule: how often the sweep runs, how 
many posts it looks at per batch, and the most it may delete in one.⌉[

The schedule: how often the sweep runs, how many posts it looks at per batch, and
the most it may delete in one.

[⌊The log as a timeline: a bar per day for the last month, and every sweep with 
who ran it, what it removed per post type, and whether it finished.⌉⌊The log as 
a timeline: a bar per day for the last month, and every sweep with who ran it, what
it removed per post type, and whether it finished.⌉[

The log as a timeline: a bar per day for the last month, and every sweep with who
ran it, what it removed per post type, and whether it finished.

[⌊The network's Logs tab, which shows every site's log together and names the site
each sweep ran on.⌉⌊The network's Logs tab, which shows every site's log together
and names the site each sweep ran on.⌉[

The network’s Logs tab, which shows every site’s log together and names the site
each sweep ran on.

## Installation

 1. Upload the plugin folder to `/wp-content/plugins/`, or install it through **Plugins
    Add New**.
 2. Activate the plugin through the **Plugins** screen. On multisite you can network
    activate it.
 3. Set the policy under **Settings  Revision Retention**, or **Network Admin  Settings
    Revision Retention** on multisite.
 4. Press **Preview** to see what the policy would remove before letting it run.

## FAQ

### Will this delete the revision I am about to restore?

Not if it is one of the newest ones you asked to keep. The **Always keep** floor
is applied per post and is never crossed on age. Press **Preview** first if you 
want to see the exact number before anything is deleted.

### Can I get deleted revisions back?

No. Revisions are deleted the same way WordPress deletes them, permanently. That
is why Preview and the `--dry-run` flag exist, and why the plugin ships with a conservative
default of keeping the newest five.

### Does it touch autosaves?

No. Autosaves are excluded from every query the sweep makes.

### Why has nothing been removed yet?

A sweep only has work to do for a post type with an age threshold. With **Remove
older than** set to Never the plugin only caps the count on save, which is WordPress’s
own behaviour, and there is nothing to clean up afterwards. `wp revision-retention
post-types` shows the rule in effect for each one.

### My site is huge. Will the sweep time out?

It works through a configurable number of posts per batch and books the next batch
itself, so each run stays short. Lower **Posts per batch** if the runs are still
too heavy.

### I enabled revisions for a post type but see nothing.

Revisions start being recorded from the next time such a post is saved. Nothing 
can recover a history that was never stored.

### Does the count limit work without the sweep?

Yes. The **Always keep** number is handed to WordPress through `wp_revisions_to_keep`,
so it caps revisions as posts are saved whether or not a sweep ever runs.

### Where are the translations?

Translations are managed on [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/revision-retention/)
and are downloaded by WordPress automatically. The plugin ships a `.pot` template
for translators, but no locale files of its own.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Revision Retention” is open source software. The following people have contributed
to this plugin.

Contributors

 *   [ Acato ](https://profiles.wordpress.org/acato/)
 *   [ Paul van Impelen ](https://profiles.wordpress.org/paulacato/)

[Translate “Revision Retention” into your language.](https://translate.wordpress.org/projects/wp-plugins/revision-retention)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/revision-retention/),
check out the [SVN repository](https://plugins.svn.wordpress.org/revision-retention/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/revision-retention/)
by [RSS](https://plugins.trac.wordpress.org/log/revision-retention/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.1.0

 * An optional log of every sweep, who ran it and what it removed, shown as a timeline
   on its own tab.
 * Log entries are kept for a period you choose, from a week to a year, and older
   ones are deleted daily.
 * On multisite, the network screen shows the logs of every site together.

#### 1.0.0

 * Initial release.
 * Keep the newest N revisions per post, and remove what is older than a threshold.
 * Per post type overrides for both numbers.
 * Switch revision support on for post types that ship without it.
 * Background sweep that works in batches and books its own next run.
 * WP-CLI commands `status`, `post-types` and `run`, with `--dry-run`.
 * Network wide defaults with optional per site overrides on multisite, and a way
   to promote one site’s settings to the network.

## Meta

 *  Version **1.1.0**
 *  Last updated **14 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.7 or higher **
 *  Tested up to **7.1.2**
 *  PHP version ** 8.2 or higher **
 * Tags
 * [cleanup](https://wordpress.org/plugins/tags/cleanup/)[database](https://wordpress.org/plugins/tags/database/)
   [performance](https://wordpress.org/plugins/tags/performance/)[post types](https://wordpress.org/plugins/tags/post-types/)
   [revisions](https://wordpress.org/plugins/tags/revisions/)
 *  [Advanced View](https://wordpress.org/plugins/revision-retention/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/revision-retention/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/revision-retention/reviews/)

## Contributors

 *   [ Acato ](https://profiles.wordpress.org/acato/)
 *   [ Paul van Impelen ](https://profiles.wordpress.org/paulacato/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/revision-retention/)