Make WordPress Core


Ignore:
Timestamp:
03/29/2013 05:28:44 AM (12 years ago)
Author:
azaozz
Message:

Post revisions:

  • Always update the revision version when updating post authors.
  • Check if revisions have been updated and return early.
  • Update the revisions by direct query to avoid resetting post_modified.
  • Fix a bug where we may be comparing with an autosave but need to compare with the latest revision.

Fixes #16215.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/revision.php

    r23823 r23849  
    6464 * Saves an already existing post as a post revision.
    6565 *
    66  * Typically used immediately prior and after post updates.
    67  * Prior to update checks for old revision data (latest revision != current post before update) and adds a copy of the current post as a revision if missing
    68  * After update adds a copy of the current post as a revision, so latest revision always matches current post
     66 * Typically used immediately after post updates.
     67 * Adds a copy of the current post as a revision, so latest revision always matches current post
    6968 *
    7069 * @package WordPress
     
    7372 *
    7473 * @uses _wp_put_post_revision()
    75  * @uses wp_first_revision_matches_current_version()
    7674 *
    7775 * @param int $post_id The ID of the post to save as a revision.
     
    7977 */
    8078function wp_save_post_revision( $post_id ) {
    81     //check to see if the post's first revision already matches the post data
    82     //should be true before post update, _except_ for old data which
    83     //doesn't include a copy of the current post data in revisions
    84     if ( wp_first_revision_matches_current_version( $post_id ) )
    85         return;
    86 
    8779    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
    8880        return;
    8981
    90     if ( ! $post = get_post( $post_id, ARRAY_A ) )
     82    if ( ! $post = get_post( $post_id ) )
    9183        return;
    9284
    93     if ( ! wp_revisions_enabled( (object) $post ) )
     85    if ( ! post_type_supports( $post->post_type, 'revisions' ) )
    9486        return;
    9587
    96     if ( 'auto-draft' == $post['post_status'] )
     88    if ( 'auto-draft' == $post->post_status )
    9789        return;
    9890
    99     if ( ! post_type_supports( $post['post_type'], 'revisions' ) )
     91    if ( ! wp_revisions_enabled( $post ) )
    10092        return;
    10193
    102     // compare the proposed update with the last stored revision, verify
    103     // different, unless a plugin tells us to always save regardless
     94    // Compare the proposed update with the last stored revision verifying that
     95    // they are different, unless a plugin tells us to always save regardless.
     96    // If no previous revisions, save one
    10497    if ( $revisions = wp_get_post_revisions( $post_id ) ) {
    105         // grab the last revision
    106         $last_revision = array_shift( $revisions );
    107 
    108         //if no previous revisions, save one for sure
    109         if ( $last_revision_array = get_post( $last_revision->ID, ARRAY_A ) ) {
    110 
    111             if ( apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision_array, $post ) && is_array( $post ) ) {
    112                 $post_has_changed = false;
    113 
    114                 foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
    115 
    116                     if ( normalize_whitespace( $post[ $field ] ) != normalize_whitespace( $last_revision_array[ $field ] ) ) {
    117                         $post_has_changed = true;
    118                         break;
    119 
    120                     }
     98        // grab the last revision, but not an autosave
     99        foreach ( $revisions as $revision ) {
     100            if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) {
     101                $last_revision = $revision;
     102                break;
     103            }
     104        }
     105
     106        if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) {
     107            $post_has_changed = false;
     108
     109            foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
     110                if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
     111                    $post_has_changed = true;
     112                    break;
    121113                }
    122 
    123                 //don't save revision if post unchanged
    124                 if( ! $post_has_changed )
    125                     return;
    126114            }
     115
     116            //don't save revision if post unchanged
     117            if( ! $post_has_changed )
     118                return;
    127119        }
    128120    }
     
    130122    $return = _wp_put_post_revision( $post );
    131123
    132     $revisions_to_keep = wp_revisions_to_keep( (object) $post );
     124    $revisions_to_keep = wp_revisions_to_keep( $post );
    133125
    134126    if ( $revisions_to_keep < 0 )
    135127        return $return;
    136128
    137     // all revisions and (possibly) one autosave
     129    // all revisions and autosaves
    138130    $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) );
    139131
     
    145137    $revisions = array_slice( $revisions, 0, $delete );
    146138
    147     for ( $i = 0; isset($revisions[$i]); $i++ ) {
     139    for ( $i = 0; isset( $revisions[$i] ); $i++ ) {
    148140        if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) )
    149141            continue;
     142
    150143        wp_delete_post_revision( $revisions[ $i ]->ID );
    151144    }
     
    445438}
    446439
    447 
    448440function _set_preview($post) {
    449441
     
    465457}
    466458
    467 function _wp_get_post_revision_version( $post ) {
    468     if ( is_array( $post ) ) {
    469         if ( ! isset( $post['post_name'] ) ) {
    470             return false;
    471         }
    472 
    473         $name = $post['post_name'];
    474     } elseif ( is_object( $post ) ) {
    475         if ( ! isset( $post->post_name ) ) {
    476             return false;
    477         }
    478 
    479         $name = $post->post_name;
    480     } else {
    481         return false;
    482     }
    483 
    484     if ( ! preg_match( '/^(\d+-)(?:autosave|revision)(?:-v)(\d+)$/', $name, $matches ) ) {
    485         return 0;
    486     }
    487 
    488     if ( '1' === $matches[2] ) {
    489         return 1;
    490     }
     459function _wp_get_post_revision_version( $revision ) {
     460    if ( is_object( $revision ) )
     461        $revision = get_object_vars( $revision );
     462    elseif ( !is_array( $revision ) )
     463        return false;
     464
     465    if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) )
     466        return (int) $matches[1];
    491467
    492468    return 0;
     
    503479 * @uses post_type_supports()
    504480 * @uses wp_get_post_revisions()
    505  * @uses wp_save_post_revision()
    506481 *
    507482 * @param int|object $post_id Post ID or post object
     
    515490        return false;
    516491
    517     //make sure we have a current revision, only adds one if missing
    518     wp_save_post_revision( $post->ID );
    519 
    520492    if ( ! post_type_supports( $post->post_type, 'revisions' ) )
    521493        return false;
     
    523495    $revisions = wp_get_post_revisions( $post->ID ); // array( 'order' => 'DESC', 'orderby' => 'date' ); // Always work from most recent to oldest
    524496
    525 
    526     if ( ! $revisions )
     497    if ( ! $first = reset( $revisions ) )
    527498        return true;
    528499
     500    // Check if the revisions have already been updated
     501    if ( preg_match( '/^\d+-(?:autosave|revision)-v\d+$/', $first->post_name ) )
     502        return true;
     503
    529504    // Add post option exclusively
    530     $lock      = "revision-upgrade-{$post->ID}";
    531     $locked_at = number_format( microtime( true ), 10, '.', '' );
    532     $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $locked_at ) );
     505    $lock = "revision-upgrade-{$post->ID}";
     506    $now = time();
     507    $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) );
    533508    if ( ! $result ) {
    534509        // If we couldn't get a lock, see how old the previous lock is
    535         $locked_at = get_option( $lock );
    536         if ( !$locked_at ) {
     510        $locked = get_option( $lock );
     511        if ( ! $locked ) {
    537512            // Can't write to the lock, and can't read the lock.
    538513            // Something broken has happened
     
    540515        }
    541516
    542         if ( $lock_at < number_format( microtime( true ), 10, '.', '' ) - 3600 ) {
    543             // Lock is too old - try again
    544             delete_option( $lock );
    545             return wp_upgrade_revisions_of_post( $post );
    546         }
    547 
    548         // Lock is not too old: some other process may be upgrading this post.  Bail.
    549         return;
    550     } else {
    551         // If we could get a lock, re-"add" the option to fire all the correct filters.
    552         add_option( $lock, $locked_at );
    553     }
    554 
    555     $success = true;
     517        if ( $locked > $now - 3600 ) {
     518            // Lock is not too old: some other process may be upgrading this post.  Bail.
     519            return false;
     520        }
     521
     522        // Lock is too old - update it (below) and continue
     523    }
     524
     525    // If we could get a lock, re-"add" the option to fire all the correct filters.
     526    update_option( $lock, $now );
    556527
    557528    reset( $revisions );
     529
    558530    do {
    559531        $this_revision = current( $revisions );
     
    562534        $this_revision_version = _wp_get_post_revision_version( $this_revision );
    563535
    564         error_log($this_revision_version);
    565 
    566536        // Something terrible happened
    567537        if ( false === $this_revision_version )
     
    572542            continue;
    573543
    574         // This revision is the oldest revision of the post.
    575         // The correct post_author is probably $post->post_author, but that's only a good guess.
    576         // Leave un-upgraded.
    577         if ( ! $prev_revision ) {
    578             continue;
    579         }
    580 
    581         $prev_revision_version = _wp_get_post_revision_version( $prev_revision );
    582 
    583         // If the previous revision is already up to date, it no longer has the information we need :(
    584         if ( 0 < $prev_revision_version ) {
    585             continue;
     544        // Always update the revision version
     545        $update = array(
     546            'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ),
     547        );
     548
     549        // If this revision is the oldest revision of the post, i.e. no $prev_revision,
     550        // the correct post_author is probably $post->post_author, but that's only a good guess.
     551        // Update the revision version only and Leave the author as-is.
     552        if ( $prev_revision ) {
     553            $prev_revision_version = _wp_get_post_revision_version( $prev_revision );
     554
     555            // If the previous revision is already up to date, it no longer has the information we need :(
     556            if ( $prev_revision_version < 1 )
     557                $update['post_author'] = $prev_revision->post_author;
    586558        }
    587559
    588560        // Upgrade this revision
    589         // Cast as object so that wp_update_post() handles slashing for us
    590         $update = (object) array(
    591             'ID'          => $this_revision->ID,
    592             'post_name'   => preg_replace( '/^(\d+-)(autosave|revision)-(\d+)$/', '$1$2-v1', $this_revision->post_name ),
    593             'post_author' => $prev_revision->post_author,
    594         );
    595         //error_log(json_encode($update));
    596         $result = wp_update_post( $update );
    597         if ( ! $result || is_wp_error( $result ) ) {
    598             // Wilhelm!
    599             $success = false;
    600             break;
    601         }
     561        $result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) );
     562
     563        if ( $result )
     564            wp_cache_delete( $this_revision->ID, 'posts' );
     565
    602566    } while ( $prev_revision );
    603567
    604568    delete_option( $lock );
     569
     570    // Add a copy of the post as latest revision.
     571    wp_save_post_revision( $post->ID );
    605572    return true;
    606573}
     
    629596 * @return bool false if not a match, otherwise true.
    630597 */
    631 function wp_first_revision_matches_current_version( $post ) {
    632 
     598function _wp_last_revision_matches_current_post( $post ) {
    633599    if ( ! $post = get_post( $post ) )
    634600        return false;
     
    637603        return false;
    638604
    639     $last_revision = array_shift( $revisions );
    640 
    641     if ( ! ($last_revision->post_modified == $post->post_modified ) )
    642         return false;
    643 
    644     return true;
     605    foreach ( $revisions as $revision ) {
     606        if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) {
     607            $last_revision = $revision;
     608            break;
     609        }
     610    }
     611
     612    // No revisions yet, only autosaves
     613    if ( ! isset( $last_revision ) )
     614        return false;
     615
     616    $post_has_changed = false;
     617    if ( $last_revision->post_modified == $post->post_modified ) {
     618        foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
     619            if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
     620                $post_has_changed = true;
     621                break;
     622            }
     623        }
     624    } else {
     625        return false;
     626    }
     627
     628    return ! $post_has_changed;
    645629}
    646630
     
    707691
    708692    return array( 'html' => $r, 'linesadded' => $linesadded, 'linesdeleted' => $linesdeleted );
    709     }
     693}
Note: See TracChangeset for help on using the changeset viewer.