Post Revisions (changes)

Revisions are versions of content created when updating a post and during auto-saving.

General information

In WP there are Auto-drafts - these are posts that are created automatically when opening the post creation page - at that moment an auto-draft is created - post_status = auto-draft and on the first save it becomes a normal draft - post_status = draft.

Such a draft is not a revision - it is a technical post for temporary data storage until the first save.

There are two types of revisions:

  • Revisions — created when saving a post if there are changes in the content (or other significant fields).

  • Auto-saves — created once every 60 seconds in the editor (one per user).

Revisions are stored as separate posts in the wp_posts table with post_type = 'revision' and post_status = inherit.

Revisions are linked to the original post via the post_parent field.

In multisite the constant in wp-config.php applies to the entire network; revisions are stored separately in each site's tables.

There is a myth that disabling revisions speeds up the site. Revisions are not involved in frontend queries - there will be no speed gain. The only increase is in DB size.

Important fields in the wp_posts table

Revisions:

post_type   = revision
post_status = inherit
post_parent = 123
post_name   = 123-revision-v1
post_date   = 2025-03-13 08:24:05

post_name = {parent_post_id}-revision-v1, where v1 here is the revision system version.

Example:

+-------+-----------+-------------+-------------+-------------+---------------------+
| ID    | post_type | post_status | post_parent | post_author | post_date           |
+-------+-----------+-------------+-------------+-------------+---------------------+
| 14385 | revision  | inherit     |       14332 |           1 | 2024-08-24 13:00:39 |
| 14393 | revision  | inherit     |       14384 |           1 | 2024-08-24 13:24:23 |
| 14394 | revision  | inherit     |       14384 |           1 | 2024-08-24 13:24:39 |
+-------+-----------+-------------+-------------+-------------+---------------------+

Autosaves:

post_type   = revision
post_status = inherit
post_parent = 123
post_name   = 123-autosave-v1
post_date   = 2025-03-13 08:24:05

post_name = {parent_post_id}-autosave-v1, where v1 is the revision system version.

Example:

+-------+-----------+-------------+-------------+-------------+---------------------+
| ID    | post_type | post_status | post_parent | post_author | post_date           |
+-------+-----------+-------------+-------------+-------------+---------------------+
| 14722 | revision  | inherit     |       14139 |          11 | 2024-10-16 09:51:11 |
| 58093 | revision  | inherit     |       54997 |           1 | 2025-03-13 08:24:05 |
+-------+-----------+-------------+-------------+-------------+---------------------+

Revisions (classic)

A revision is created on save if there are changes in significant fields (post_title, post_content, post_excerpt). Significant fields are defined by the function _wp_post_revision_data() and can be changed via the hook _wp_post_revision_fields.

By default, revisions are created by the function wp_save_post_revision(), which is hooked to post_updated:

add_action( 'post_updated', 'wp_save_post_revision', 10, 1 );

You can adjust the check whether the post has changed (whether to add a revision) with the filter wp_save_post_revision_post_has_changed

Autosaves

Autosaves are a separate kind of revision that core creates/recognizes as an autosave and treats differently.

They differ by the post_name field. Formats of this field:

// autosaves
{parent_post_id}-autosave-v1

// revisions
{parent_post_id}-revision-v1

See more:

The WP_POST_REVISIONS limit does not apply to Autosaves.

Autosave interval

An autosave is created approximately every 60 seconds in the editor. One current autosave per user per post.

In wp-config.php there is a constant AUTOSAVE_INTERVAL:

define( 'AUTOSAVE_INTERVAL', 60 ); // seconds

0 - will disable autosaves.

Comments, taxonomies and meta-fields in revisions

By default revisions do not store any data except some data from the wp_posts table. That is:

  • Taxonomies - none.
  • Comments - none.
  • Meta-fields - none (by default). But technically they can be attached, however core does not create them, copy them from the parent or restore them on rollback. See _wp_post_revision_fields()

How to disable/limit revisions

Globally via wp-config.php:

define( 'WP_POST_REVISIONS', true );  // unlimited
define( 'WP_POST_REVISIONS', 10 );    // keep no more than 10
define( 'WP_POST_REVISIONS', false ); // disable revisions (autosave remains)

For a single post type:

Disable revision support in the supports array in register_post_type().

Or after registration:

add_action( 'init', function() {
	remove_post_type_support( 'promo', 'revisions' );
} );

Or via filter:

add_filter( 'wp_revisions_to_keep', 'change_revisions_limit', 10, 2 );
function change_revisions_limit( $num, $post ) {
	if ( 'news' === $post->post_type ) {
		return 0; // disable
	}

	if ( 'page' === $post->post_type ) {
		return 5; // limit
	}

	return $num;
}

How to enable revisions for post types

Enable support in register_post_type():

register_post_type( 'news', [
	'supports' => [ 'title', 'editor', 'revisions' ],
] );

Or after registration:

add_action( 'init', function() {
	add_post_type_support( 'product', 'revisions' );
} );

Functions and hooks

Function Description
wp_revisions_enabled() Check if revisions are enabled for the specified post.
wp_is_post_autosave() Determines whether the specified post is an autosave.
wp_delete_post_revision() Deletes a post revision by ID.
wp_revisions_to_keep() Defines how many of the latest revisions (changes) should be stored in the database for a specific post.
wp_get_post_revisions() Gets all revisions (edits, changes) of the specified post.
wp_get_post_autosave() Retrieves the autosaved data of the specified post.
wp_restore_post_revision() Restores a post to the specified revision.
wp_is_post_revision() Determines whether the specified post is a revision.
wp_save_post_revision() Creates a revision (copy) of the specified post. It also deletes excess revisions.
wp_list_post_revisions() Displays a list of a post's revisions.
wp_get_revision_ui_diff() Get the revision UI diff.
Hook Description
wp_revisions_to_keep Filters the number of revisions to save for the given post.
wp_save_post_revision_check_for_changes Filters whether the post has changed since the latest revision.
wp_save_post_revision_post_has_changed Filters whether a post has changed.

Developer notes

Restore a specific revision

$restored_id = wp_restore_post_revision( $revision_id );

Limit DB growth without disabling revisions

  • Set a reasonable limit via WP_POST_REVISIONS or the filter.
  • Keep autosave enabled for safety.

Cleaning up old revisions

WP-CLI - safer than direct SQL:

// Delete all revisions
wp post delete $(wp post list --post_type=revision --format=ids) --force

By parent post type - with a PHP script with checks so as not to touch current editors' autosaves.

$revs = get_posts( [
	'post_type'   => "revision",
	'numberposts' => -1,
	'date_query'  => [
		[ "before" => "2024-09-01" ],
	],
] );

foreach( $revs as $r ){
	$p = get_post( $r->post_parent );
	if( $p && "news" === $p->post_type ){
		wp_delete_post( $r->ID, true );
	}
}
echo "Done\n";

REST API

  • List revisions:

    GET /wp/v2/posts/{id}/revisions
  • Specific revision:

    GET /wp/v2/posts/{id}/revisions/{revisionId}