WordPress Version: 6.4
/**
* Creates a revision for the current version of a post.
*
* Typically used immediately after a post update, as every update is a revision,
* and the most recent revision always matches the current post.
*
* @since 2.6.0
*
* @param int $post_id The ID of the post to save as a revision.
* @return int|WP_Error|void Void or 0 if error, new revision ID, if success.
*/
function wp_save_post_revision($post_id)
{
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// Prevent saving post revisions if revisions should be saved on wp_after_insert_post.
if (doing_action('post_updated') && has_action('wp_after_insert_post', 'wp_save_post_revision_on_insert')) {
return;
}
$post = get_post($post_id);
if (!$post) {
return;
}
if (!post_type_supports($post->post_type, 'revisions')) {
return;
}
if ('auto-draft' === $post->post_status) {
return;
}
if (!wp_revisions_enabled($post)) {
return;
}
/*
* Compare the proposed update with the last stored revision verifying that
* they are different, unless a plugin tells us to always save regardless.
* If no previous revisions, save one.
*/
$revisions = wp_get_post_revisions($post_id);
if ($revisions) {
// Grab the latest revision, but not an autosave.
foreach ($revisions as $revision) {
if (str_contains($revision->post_name, "{$revision->post_parent}-revision")) {
$latest_revision = $revision;
break;
}
}
/**
* Filters whether the post has changed since the latest revision.
*
* By default a revision is saved only if one of the revisioned fields has changed.
* This filter can override that so a revision is saved even if nothing has changed.
*
* @since 3.6.0
*
* @param bool $check_for_changes Whether to check for changes before saving a new revision.
* Default true.
* @param WP_Post $latest_revision The latest revision post object.
* @param WP_Post $post The post object.
*/
if (isset($latest_revision) && apply_filters('wp_save_post_revision_check_for_changes', true, $latest_revision, $post)) {
$post_has_changed = false;
foreach (array_keys(_wp_post_revision_fields($post)) as $field) {
if (normalize_whitespace($post->{$field}) !== normalize_whitespace($latest_revision->{$field})) {
$post_has_changed = true;
break;
}
}
/**
* Filters whether a post has changed.
*
* By default a revision is saved only if one of the revisioned fields has changed.
* This filter allows for additional checks to determine if there were changes.
*
* @since 4.1.0
*
* @param bool $post_has_changed Whether the post has changed.
* @param WP_Post $latest_revision The latest revision post object.
* @param WP_Post $post The post object.
*/
$post_has_changed = (bool) apply_filters('wp_save_post_revision_post_has_changed', $post_has_changed, $latest_revision, $post);
// Don't save revision if post unchanged.
if (!$post_has_changed) {
return;
}
}
}
$return = _wp_put_post_revision($post);
/*
* If a limit for the number of revisions to keep has been set,
* delete the oldest ones.
*/
$revisions_to_keep = wp_revisions_to_keep($post);
if ($revisions_to_keep < 0) {
return $return;
}
$revisions = wp_get_post_revisions($post_id, array('order' => 'ASC'));
/**
* Filters the revisions to be considered for deletion.
*
* @since 6.2.0
*
* @param WP_Post[] $revisions Array of revisions, or an empty array if none.
* @param int $post_id The ID of the post to save as a revision.
*/
$revisions = apply_filters('wp_save_post_revision_revisions_before_deletion', $revisions, $post_id);
$delete = count($revisions) - $revisions_to_keep;
if ($delete < 1) {
return $return;
}
$revisions = array_slice($revisions, 0, $delete);
for ($i = 0; isset($revisions[$i]); $i++) {
if (str_contains($revisions[$i]->post_name, 'autosave')) {
continue;
}
wp_delete_post_revision($revisions[$i]->ID);
}
return $return;
}