1<?php 2/** 3 * Post revision functions. 4 * 5 * @package WordPress 6 * @subpackage Post_Revisions 7 */ 8 9/** 10 * Determines which fields of posts are to be saved in revisions. 11 * 12 * @since 2.6.0 13 * @since 4.5.0 A `WP_Post` object can now be passed to the `$post` parameter. 14 * @since 4.5.0 The optional `$autosave` parameter was deprecated and renamed to `$deprecated`. 15 * @access private 16 * 17 * @param array|WP_Post $post Optional. A post array or a WP_Post object being processed 18 * for insertion as a post revision. Default empty array. 19 * @param bool $deprecated Not used. 20 * @return array Array of fields that can be versioned. 21 */ 22function _wp_post_revision_fields( $post = array(), $deprecated = false ) { 23 static $fields = null; 24 25 if ( ! is_array( $post ) ) { 26 $post = get_post( $post, ARRAY_A ); 27 } 28 29 if ( is_null( $fields ) ) { 30 // Allow these to be versioned. 31 $fields = array( 32 'post_title' => __( 'Title' ), 33 'post_content' => __( 'Content' ), 34 'post_excerpt' => __( 'Excerpt' ), 35 ); 36 } 37 38 /** 39 * Filters the list of fields saved in post revisions. 40 * 41 * Included by default: 'post_title', 'post_content' and 'post_excerpt'. 42 * 43 * Disallowed fields: 'ID', 'post_name', 'post_parent', 'post_date', 44 * 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 45 * and 'post_author'. 46 * 47 * @since 2.6.0 48 * @since 4.5.0 The `$post` parameter was added. 49 * 50 * @param array $fields List of fields to revision. Contains 'post_title', 51 * 'post_content', and 'post_excerpt' by default. 52 * @param array $post A post array being processed for insertion as a post revision. 53 */ 54 $fields = apply_filters( '_wp_post_revision_fields', $fields, $post ); 55 56 // WP uses these internally either in versioning or elsewhere - they cannot be versioned. 57 foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect ) { 58 unset( $fields[ $protect ] ); 59 } 60 61 return $fields; 62} 63 64/** 65 * Returns a post array ready to be inserted into the posts table as a post revision. 66 * 67 * @since 4.5.0 68 * @access private 69 * 70 * @param array|WP_Post $post Optional. A post array or a WP_Post object to be processed 71 * for insertion as a post revision. Default empty array. 72 * @param bool $autosave Optional. Is the revision an autosave? Default false. 73 * @return array Post array ready to be inserted as a post revision. 74 */ 75function _wp_post_revision_data( $post = array(), $autosave = false ) { 76 if ( ! is_array( $post ) ) { 77 $post = get_post( $post, ARRAY_A ); 78 } 79 80 $fields = _wp_post_revision_fields( $post ); 81 82 $revision_data = array(); 83 84 foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field ) { 85 $revision_data[ $field ] = $post[ $field ]; 86 } 87 88 $revision_data['post_parent'] = $post['ID']; 89 $revision_data['post_status'] = 'inherit'; 90 $revision_data['post_type'] = 'revision'; 91 $revision_data['post_name'] = $autosave ? "$post[ID]-autosave-v1" : "$post[ID]-revision-v1"; // "1" is the revisioning system version. 92 $revision_data['post_date'] = isset( $post['post_modified'] ) ? $post['post_modified'] : ''; 93 $revision_data['post_date_gmt'] = isset( $post['post_modified_gmt'] ) ? $post['post_modified_gmt'] : ''; 94 95 return $revision_data; 96} 97 98/** 99 * Creates a revision for the current version of a post. 100 * 101 * Typically used immediately after a post update, as every update is a revision, 102 * and the most recent revision always matches the current post. 103 * 104 * @since 2.6.0 105 * 106 * @param int $post_id The ID of the post to save as a revision. 107 * @return int|WP_Error|void Void or 0 if error, new revision ID, if success. 108 */ 109function wp_save_post_revision( $post_id ) { 110 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 111 return; 112 } 113 114 $post = get_post( $post_id ); 115 if ( ! $post ) { 116 return; 117 } 118 119 if ( ! post_type_supports( $post->post_type, 'revisions' ) ) { 120 return; 121 } 122 123 if ( 'auto-draft' === $post->post_status ) { 124 return; 125 } 126 127 if ( ! wp_revisions_enabled( $post ) ) { 128 return; 129 } 130 131 /* 132 * Compare the proposed update with the last stored revision verifying that 133 * they are different, unless a plugin tells us to always save regardless. 134 * If no previous revisions, save one. 135 */ 136 $revisions = wp_get_post_revisions( $post_id ); 137 if ( $revisions ) { 138 // Grab the last revision, but not an autosave. 139 foreach ( $revisions as $revision ) { 140 if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) { 141 $last_revision = $revision; 142 break; 143 } 144 } 145 146 /** 147 * Filters whether the post has changed since the last revision. 148 * 149 * By default a revision is saved only if one of the revisioned fields has changed. 150 * This filter can override that so a revision is saved even if nothing has changed. 151 * 152 * @since 3.6.0 153 * 154 * @param bool $check_for_changes Whether to check for changes before saving a new revision. 155 * Default true. 156 * @param WP_Post $last_revision The last revision post object. 157 * @param WP_Post $post The post object. 158 */ 159 if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) { 160 $post_has_changed = false; 161 162 foreach ( array_keys( _wp_post_revision_fields( $post ) ) as $field ) { 163 if ( normalize_whitespace( $post->$field ) !== normalize_whitespace( $last_revision->$field ) ) { 164 $post_has_changed = true; 165 break; 166 } 167 } 168 169 /** 170 * Filters whether a post has changed. 171 * 172 * By default a revision is saved only if one of the revisioned fields has changed. 173 * This filter allows for additional checks to determine if there were changes. 174 * 175 * @since 4.1.0 176 * 177 * @param bool $post_has_changed Whether the post has changed. 178 * @param WP_Post $last_revision The last revision post object. 179 * @param WP_Post $post The post object. 180 */ 181 $post_has_changed = (bool) apply_filters( 'wp_save_post_revision_post_has_changed', $post_has_changed, $last_revision, $post ); 182 183 // Don't save revision if post unchanged. 184 if ( ! $post_has_changed ) { 185 return; 186 } 187 } 188 } 189 190 $return = _wp_put_post_revision( $post ); 191 192 // If a limit for the number of revisions to keep has been set, 193 // delete the oldest ones. 194 $revisions_to_keep = wp_revisions_to_keep( $post ); 195 196 if ( $revisions_to_keep < 0 ) { 197 return $return; 198 } 199 200 $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) ); 201 202 $delete = count( $revisions ) - $revisions_to_keep; 203 204 if ( $delete < 1 ) { 205 return $return; 206 } 207 208 $revisions = array_slice( $revisions, 0, $delete ); 209 210 for ( $i = 0; isset( $revisions[ $i ] ); $i++ ) { 211 if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) ) { 212 continue; 213 } 214 215 wp_delete_post_revision( $revisions[ $i ]->ID ); 216 } 217 218 return $return; 219} 220 221/** 222 * Retrieve the autosaved data of the specified post. 223 * 224 * Returns a post object with the information that was autosaved for the specified post. 225 * If the optional $user_id is passed, returns the autosave for that user, otherwise 226 * returns the latest autosave. 227 * 228 * @since 2.6.0 229 * 230 * @global wpdb $wpdb WordPress database abstraction object. 231 * 232 * @param int $post_id The post ID. 233 * @param int $user_id Optional The post author ID. 234 * @return WP_Post|false The autosaved data or false on failure or when no autosave exists. 235 */ 236function wp_get_post_autosave( $post_id, $user_id = 0 ) { 237 global $wpdb; 238 239 $autosave_name = $post_id . '-autosave-v1'; 240 $user_id_query = ( 0 !== $user_id ) ? "AND post_author = $user_id" : null; 241 242 // Construct the autosave query. 243 $autosave_query = " 244 SELECT * 245 FROM $wpdb->posts 246 WHERE post_parent = %d 247 AND post_type = 'revision' 248 AND post_status = 'inherit' 249 AND post_name = %s " . $user_id_query . ' 250 ORDER BY post_date DESC 251 LIMIT 1'; 252 253 $autosave = $wpdb->get_results( 254 $wpdb->prepare( 255 $autosave_query, 256 $post_id, 257 $autosave_name 258 ) 259 ); 260 261 if ( ! $autosave ) { 262 return false; 263 } 264 265 return get_post( $autosave[0] ); 266} 267 268/** 269 * Determines if the specified post is a revision. 270 * 271 * @since 2.6.0 272 * 273 * @param int|WP_Post $post Post ID or post object. 274 * @return int|false ID of revision's parent on success, false if not a revision. 275 */ 276function wp_is_post_revision( $post ) { 277 $post = wp_get_post_revision( $post ); 278 if ( ! $post ) { 279 return false; 280 } 281 282 return (int) $post->post_parent; 283} 284 285/** 286 * Determines if the specified post is an autosave. 287 * 288 * @since 2.6.0 289 * 290 * @param int|WP_Post $post Post ID or post object. 291 * @return int|false ID of autosave's parent on success, false if not a revision. 292 */ 293function wp_is_post_autosave( $post ) { 294 $post = wp_get_post_revision( $post ); 295 if ( ! $post ) { 296 return false; 297 } 298 299 if ( false !== strpos( $post->post_name, "{$post->post_parent}-autosave" ) ) { 300 return (int) $post->post_parent; 301 } 302 303 return false; 304} 305 306/** 307 * Inserts post data into the posts table as a post revision. 308 * 309 * @since 2.6.0 310 * @access private 311 * 312 * @param int|WP_Post|array|null $post Post ID, post object OR post array. 313 * @param bool $autosave Optional. Is the revision an autosave? 314 * @return int|WP_Error WP_Error or 0 if error, new revision ID if success. 315 */ 316function _wp_put_post_revision( $post = null, $autosave = false ) { 317 if ( is_object( $post ) ) { 318 $post = get_object_vars( $post ); 319 } elseif ( ! is_array( $post ) ) { 320 $post = get_post( $post, ARRAY_A ); 321 } 322 323 if ( ! $post || empty( $post['ID'] ) ) { 324 return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) ); 325 } 326 327 if ( isset( $post['post_type'] ) && 'revision' === $post['post_type'] ) { 328 return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); 329 } 330 331 $post = _wp_post_revision_data( $post, $autosave ); 332 $post = wp_slash( $post ); // Since data is from DB. 333 334 $revision_id = wp_insert_post( $post, true ); 335 if ( is_wp_error( $revision_id ) ) { 336 return $revision_id; 337 } 338 339 if ( $revision_id ) { 340 /** 341 * Fires once a revision has been saved. 342 * 343 * @since 2.6.0 344 * 345 * @param int $revision_id Post revision ID. 346 */ 347 do_action( '_wp_put_post_revision', $revision_id ); 348 } 349 350 return $revision_id; 351} 352 353/** 354 * Gets a post revision. 355 * 356 * @since 2.6.0 357 * 358 * @param int|WP_Post $post The post ID or object. 359 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which 360 * correspond to a WP_Post object, an associative array, or a numeric array, 361 * respectively. Default OBJECT. 362 * @param string $filter Optional sanitation filter. See sanitize_post(). 363 * @return WP_Post|array|null WP_Post (or array) on success, or null on failure. 364 */ 365function wp_get_post_revision( &$post, $output = OBJECT, $filter = 'raw' ) { 366 $revision = get_post( $post, OBJECT, $filter ); 367 if ( ! $revision ) { 368 return $revision; 369 } 370 if ( 'revision' !== $revision->post_type ) { 371 return null; 372 } 373 374 if ( OBJECT === $output ) { 375 return $revision; 376 } elseif ( ARRAY_A === $output ) { 377 $_revision = get_object_vars( $revision ); 378 return $_revision; 379 } elseif ( ARRAY_N === $output ) { 380 $_revision = array_values( get_object_vars( $revision ) ); 381 return $_revision; 382 } 383 384 return $revision; 385} 386 387/** 388 * Restores a post to the specified revision. 389 * 390 * Can restore a past revision using all fields of the post revision, or only selected fields. 391 * 392 * @since 2.6.0 393 * 394 * @param int|WP_Post $revision_id Revision ID or revision object. 395 * @param array $fields Optional. What fields to restore from. Defaults to all. 396 * @return int|false|null Null if error, false if no fields to restore, (int) post ID if success. 397 */ 398function wp_restore_post_revision( $revision_id, $fields = null ) { 399 $revision = wp_get_post_revision( $revision_id, ARRAY_A ); 400 if ( ! $revision ) { 401 return $revision; 402 } 403 404 if ( ! is_array( $fields ) ) { 405 $fields = array_keys( _wp_post_revision_fields( $revision ) ); 406 } 407 408 $update = array(); 409 foreach ( array_intersect( array_keys( $revision ), $fields ) as $field ) { 410 $update[ $field ] = $revision[ $field ]; 411 } 412 413 if ( ! $update ) { 414 return false; 415 } 416 417 $update['ID'] = $revision['post_parent']; 418 419 $update = wp_slash( $update ); // Since data is from DB. 420 421 $post_id = wp_update_post( $update ); 422 if ( ! $post_id || is_wp_error( $post_id ) ) { 423 return $post_id; 424 } 425 426 // Update last edit user. 427 update_post_meta( $post_id, '_edit_last', get_current_user_id() ); 428 429 /** 430 * Fires after a post revision has been restored. 431 * 432 * @since 2.6.0 433 * 434 * @param int $post_id Post ID. 435 * @param int $revision_id Post revision ID. 436 */ 437 do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] ); 438 439 return $post_id; 440} 441 442/** 443 * Deletes a revision. 444 * 445 * Deletes the row from the posts table corresponding to the specified revision. 446 * 447 * @since 2.6.0 448 * 449 * @param int|WP_Post $revision_id Revision ID or revision object. 450 * @return array|false|WP_Post|WP_Error|null Null or WP_Error if error, deleted post if success. 451 */ 452function wp_delete_post_revision( $revision_id ) { 453 $revision = wp_get_post_revision( $revision_id ); 454 if ( ! $revision ) { 455 return $revision; 456 } 457 458 $delete = wp_delete_post( $revision->ID ); 459 if ( $delete ) { 460 /** 461 * Fires once a post revision has been deleted. 462 * 463 * @since 2.6.0 464 * 465 * @param int $revision_id Post revision ID. 466 * @param WP_Post $revision Post revision object. 467 */ 468 do_action( 'wp_delete_post_revision', $revision->ID, $revision ); 469 } 470 471 return $delete; 472} 473 474/** 475 * Returns all revisions of specified post. 476 * 477 * @since 2.6.0 478 * 479 * @see get_children() 480 * 481 * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global `$post`. 482 * @param array|null $args Optional. Arguments for retrieving post revisions. Default null. 483 * @return array An array of revisions, or an empty array if none. 484 */ 485function wp_get_post_revisions( $post_id = 0, $args = null ) { 486 $post = get_post( $post_id ); 487 if ( ! $post || empty( $post->ID ) ) { 488 return array(); 489 } 490 491 $defaults = array( 492 'order' => 'DESC', 493 'orderby' => 'date ID', 494 'check_enabled' => true, 495 ); 496 $args = wp_parse_args( $args, $defaults ); 497 498 if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) ) { 499 return array(); 500 } 501 502 $args = array_merge( 503 $args, 504 array( 505 'post_parent' => $post->ID, 506 'post_type' => 'revision', 507 'post_status' => 'inherit', 508 ) 509 ); 510 511 $revisions = get_children( $args ); 512 if ( ! $revisions ) { 513 return array(); 514 } 515 516 return $revisions; 517} 518 519/** 520 * Determine if revisions are enabled for a given post. 521 * 522 * @since 3.6.0 523 * 524 * @param WP_Post $post The post object. 525 * @return bool True if number of revisions to keep isn't zero, false otherwise. 526 */ 527function wp_revisions_enabled( $post ) { 528 return wp_revisions_to_keep( $post ) !== 0; 529} 530 531/** 532 * Determine how many revisions to retain for a given post. 533 * 534 * By default, an infinite number of revisions are kept. 535 * 536 * The constant WP_POST_REVISIONS can be set in wp-config to specify the limit 537 * of revisions to keep. 538 * 539 * @since 3.6.0 540 * 541 * @param WP_Post $post The post object. 542 * @return int The number of revisions to keep. 543 */ 544function wp_revisions_to_keep( $post ) { 545 $num = WP_POST_REVISIONS; 546 547 if ( true === $num ) { 548 $num = -1; 549 } else { 550 $num = (int) $num; 551 } 552 553 if ( ! post_type_supports( $post->post_type, 'revisions' ) ) { 554 $num = 0; 555 } 556 557 /** 558 * Filters the number of revisions to save for the given post. 559 * 560 * Overrides the value of WP_POST_REVISIONS. 561 * 562 * @since 3.6.0 563 * 564 * @param int $num Number of revisions to store. 565 * @param WP_Post $post Post object. 566 */ 567 $num = apply_filters( 'wp_revisions_to_keep', $num, $post ); 568 569 /** 570 * Filters the number of revisions to save for the given post by its post type. 571 * 572 * Overrides both the value of WP_POST_REVISIONS and the {@see 'wp_revisions_to_keep'} filter. 573 * 574 * The dynamic portion of the hook name, `$post->post_type`, refers to 575 * the post type slug. 576 * 577 * @since 5.8.0 578 * 579 * @param int $num Number of revisions to store. 580 * @param WP_Post $post Post object. 581 */ 582 $num = apply_filters( "wp_{$post->post_type}_revisions_to_keep", $num, $post ); 583 584 return (int) $num; 585} 586 587/** 588 * Sets up the post object for preview based on the post autosave. 589 * 590 * @since 2.7.0 591 * @access private 592 * 593 * @param WP_Post $post 594 * @return WP_Post|false 595 */ 596function _set_preview( $post ) { 597 if ( ! is_object( $post ) ) { 598 return $post; 599 } 600 601 $preview = wp_get_post_autosave( $post->ID ); 602 if ( ! is_object( $preview ) ) { 603 return $post; 604 } 605 606 $preview = sanitize_post( $preview ); 607 608 $post->post_content = $preview->post_content; 609 $post->post_title = $preview->post_title; 610 $post->post_excerpt = $preview->post_excerpt; 611 612 add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 ); 613 add_filter( 'get_post_metadata', '_wp_preview_post_thumbnail_filter', 10, 3 ); 614 615 return $post; 616} 617 618/** 619 * Filters the latest content for preview from the post autosave. 620 * 621 * @since 2.7.0 622 * @access private 623 */ 624function _show_post_preview() { 625 if ( isset( $_GET['preview_id'] ) && isset( $_GET['preview_nonce'] ) ) { 626 $id = (int) $_GET['preview_id']; 627 628 if ( false === wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) ) { 629 wp_die( __( 'Sorry, you are not allowed to preview drafts.' ), 403 ); 630 } 631 632 add_filter( 'the_preview', '_set_preview' ); 633 } 634} 635 636/** 637 * Filters terms lookup to set the post format. 638 * 639 * @since 3.6.0 640 * @access private 641 * 642 * @param array $terms 643 * @param int $post_id 644 * @param string $taxonomy 645 * @return array 646 */ 647function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { 648 $post = get_post(); 649 if ( ! $post ) { 650 return $terms; 651 } 652 653 if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id 654 || 'post_format' !== $taxonomy || 'revision' === $post->post_type 655 ) { 656 return $terms; 657 } 658 659 if ( 'standard' === $_REQUEST['post_format'] ) { 660 $terms = array(); 661 } else { 662 $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ); 663 if ( $term ) { 664 $terms = array( $term ); // Can only have one post format. 665 } 666 } 667 668 return $terms; 669} 670 671/** 672 * Filters post thumbnail lookup to set the post thumbnail. 673 * 674 * @since 4.6.0 675 * @access private 676 * 677 * @param null|array|string $value The value to return - a single metadata value, or an array of values. 678 * @param int $post_id Post ID. 679 * @param string $meta_key Meta key. 680 * @return null|array The default return value or the post thumbnail meta array. 681 */ 682function _wp_preview_post_thumbnail_filter( $value, $post_id, $meta_key ) { 683 $post = get_post(); 684 if ( ! $post ) { 685 return $value; 686 } 687 688 if ( empty( $_REQUEST['_thumbnail_id'] ) || 689 empty( $_REQUEST['preview_id'] ) || 690 $post->ID != $post_id || 691 '_thumbnail_id' !== $meta_key || 692 'revision' === $post->post_type || 693 $post_id != $_REQUEST['preview_id'] ) { 694 695 return $value; 696 } 697 698 $thumbnail_id = (int) $_REQUEST['_thumbnail_id']; 699 if ( $thumbnail_id <= 0 ) { 700 return ''; 701 } 702 703 return (string) $thumbnail_id; 704} 705 706/** 707 * Gets the post revision version. 708 * 709 * @since 3.6.0 710 * @access private 711 * 712 * @param WP_Post $revision 713 * @return int|false 714 */ 715function _wp_get_post_revision_version( $revision ) { 716 if ( is_object( $revision ) ) { 717 $revision = get_object_vars( $revision ); 718 } elseif ( ! is_array( $revision ) ) { 719 return false; 720 } 721 722 if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) ) { 723 return (int) $matches[1]; 724 } 725 726 return 0; 727} 728 729/** 730 * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1 731 * 732 * @since 3.6.0 733 * @access private 734 * 735 * @global wpdb $wpdb WordPress database abstraction object. 736 * 737 * @param WP_Post $post Post object 738 * @param array $revisions Current revisions of the post 739 * @return bool true if the revisions were upgraded, false if problems 740 */ 741function _wp_upgrade_revisions_of_post( $post, $revisions ) { 742 global $wpdb; 743 744 // Add post option exclusively. 745 $lock = "revision-upgrade-{$post->ID}"; 746 $now = time(); 747 $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) ); 748 if ( ! $result ) { 749 // If we couldn't get a lock, see how old the previous lock is. 750 $locked = get_option( $lock ); 751 if ( ! $locked ) { 752 // Can't write to the lock, and can't read the lock. 753 // Something broken has happened. 754 return false; 755 } 756 757 if ( $locked > $now - 3600 ) { 758 // Lock is not too old: some other process may be upgrading this post. Bail. 759 return false; 760 } 761 762 // Lock is too old - update it (below) and continue. 763 } 764 765 // If we could get a lock, re-"add" the option to fire all the correct filters. 766 update_option( $lock, $now ); 767 768 reset( $revisions ); 769 $add_last = true; 770 771 do { 772 $this_revision = current( $revisions ); 773 $prev_revision = next( $revisions ); 774 775 $this_revision_version = _wp_get_post_revision_version( $this_revision ); 776 777 // Something terrible happened. 778 if ( false === $this_revision_version ) { 779 continue; 780 } 781 782 // 1 is the latest revision version, so we're already up to date. 783 // No need to add a copy of the post as latest revision. 784 if ( 0 < $this_revision_version ) { 785 $add_last = false; 786 continue; 787 } 788 789 // Always update the revision version. 790 $update = array( 791 'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ), 792 ); 793 794 /* 795 * If this revision is the oldest revision of the post, i.e. no $prev_revision, 796 * the correct post_author is probably $post->post_author, but that's only a good guess. 797 * Update the revision version only and Leave the author as-is. 798 */ 799 if ( $prev_revision ) { 800 $prev_revision_version = _wp_get_post_revision_version( $prev_revision ); 801 802 // If the previous revision is already up to date, it no longer has the information we need :( 803 if ( $prev_revision_version < 1 ) { 804 $update['post_author'] = $prev_revision->post_author; 805 } 806 } 807 808 // Upgrade this revision. 809 $result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) ); 810 811 if ( $result ) { 812 wp_cache_delete( $this_revision->ID, 'posts' ); 813 } 814 } while ( $prev_revision ); 815 816 delete_option( $lock ); 817 818 // Add a copy of the post as latest revision. 819 if ( $add_last ) { 820 wp_save_post_revision( $post->ID ); 821 } 822 823 return true; 824} 825