[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
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 */ 22 function _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 */ 75 function _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 */ 109 function 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 */ 236 function 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 */ 276 function 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 */ 293 function 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 */ 316 function _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 */ 365 function 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 */ 398 function 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 WP_Post|false|null Null or false if error, deleted post object if success. 451 */ 452 function 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 */ 485 function 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 * Returns the url for viewing and potentially restoring revisions of a given post. 521 * 522 * @since 5.9.0 523 * 524 * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global `$post`. 525 * @return null|string The URL for editing revisions on the given post, otherwise null. 526 */ 527 function wp_get_post_revisions_url( $post_id = 0 ) { 528 $post = get_post( $post_id ); 529 530 if ( ! $post instanceof WP_Post ) { 531 return null; 532 } 533 534 // If the post is a revision, return early. 535 if ( 'revision' === $post->post_type ) { 536 return get_edit_post_link( $post ); 537 } 538 539 if ( ! wp_revisions_enabled( $post ) ) { 540 return null; 541 } 542 543 $revisions = wp_get_post_revisions( $post->ID, array( 'posts_per_page' => 1 ) ); 544 545 if ( 0 === count( $revisions ) ) { 546 return null; 547 } 548 549 $revision = reset( $revisions ); 550 return get_edit_post_link( $revision ); 551 } 552 553 /** 554 * Determine if revisions are enabled for a given post. 555 * 556 * @since 3.6.0 557 * 558 * @param WP_Post $post The post object. 559 * @return bool True if number of revisions to keep isn't zero, false otherwise. 560 */ 561 function wp_revisions_enabled( $post ) { 562 return wp_revisions_to_keep( $post ) !== 0; 563 } 564 565 /** 566 * Determine how many revisions to retain for a given post. 567 * 568 * By default, an infinite number of revisions are kept. 569 * 570 * The constant WP_POST_REVISIONS can be set in wp-config to specify the limit 571 * of revisions to keep. 572 * 573 * @since 3.6.0 574 * 575 * @param WP_Post $post The post object. 576 * @return int The number of revisions to keep. 577 */ 578 function wp_revisions_to_keep( $post ) { 579 $num = WP_POST_REVISIONS; 580 581 if ( true === $num ) { 582 $num = -1; 583 } else { 584 $num = (int) $num; 585 } 586 587 if ( ! post_type_supports( $post->post_type, 'revisions' ) ) { 588 $num = 0; 589 } 590 591 /** 592 * Filters the number of revisions to save for the given post. 593 * 594 * Overrides the value of WP_POST_REVISIONS. 595 * 596 * @since 3.6.0 597 * 598 * @param int $num Number of revisions to store. 599 * @param WP_Post $post Post object. 600 */ 601 $num = apply_filters( 'wp_revisions_to_keep', $num, $post ); 602 603 /** 604 * Filters the number of revisions to save for the given post by its post type. 605 * 606 * Overrides both the value of WP_POST_REVISIONS and the {@see 'wp_revisions_to_keep'} filter. 607 * 608 * The dynamic portion of the hook name, `$post->post_type`, refers to 609 * the post type slug. 610 * 611 * Possible hook names include: 612 * 613 * - `wp_post_revisions_to_keep` 614 * - `wp_page_revisions_to_keep` 615 * 616 * @since 5.8.0 617 * 618 * @param int $num Number of revisions to store. 619 * @param WP_Post $post Post object. 620 */ 621 $num = apply_filters( "wp_{$post->post_type}_revisions_to_keep", $num, $post ); 622 623 return (int) $num; 624 } 625 626 /** 627 * Sets up the post object for preview based on the post autosave. 628 * 629 * @since 2.7.0 630 * @access private 631 * 632 * @param WP_Post $post 633 * @return WP_Post|false 634 */ 635 function _set_preview( $post ) { 636 if ( ! is_object( $post ) ) { 637 return $post; 638 } 639 640 $preview = wp_get_post_autosave( $post->ID ); 641 642 if ( is_object( $preview ) ) { 643 $preview = sanitize_post( $preview ); 644 645 $post->post_content = $preview->post_content; 646 $post->post_title = $preview->post_title; 647 $post->post_excerpt = $preview->post_excerpt; 648 } 649 650 add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 ); 651 add_filter( 'get_post_metadata', '_wp_preview_post_thumbnail_filter', 10, 3 ); 652 653 return $post; 654 } 655 656 /** 657 * Filters the latest content for preview from the post autosave. 658 * 659 * @since 2.7.0 660 * @access private 661 */ 662 function _show_post_preview() { 663 if ( isset( $_GET['preview_id'] ) && isset( $_GET['preview_nonce'] ) ) { 664 $id = (int) $_GET['preview_id']; 665 666 if ( false === wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) ) { 667 wp_die( __( 'Sorry, you are not allowed to preview drafts.' ), 403 ); 668 } 669 670 add_filter( 'the_preview', '_set_preview' ); 671 } 672 } 673 674 /** 675 * Filters terms lookup to set the post format. 676 * 677 * @since 3.6.0 678 * @access private 679 * 680 * @param array $terms 681 * @param int $post_id 682 * @param string $taxonomy 683 * @return array 684 */ 685 function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { 686 $post = get_post(); 687 if ( ! $post ) { 688 return $terms; 689 } 690 691 if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id 692 || 'post_format' !== $taxonomy || 'revision' === $post->post_type 693 ) { 694 return $terms; 695 } 696 697 if ( 'standard' === $_REQUEST['post_format'] ) { 698 $terms = array(); 699 } else { 700 $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ); 701 if ( $term ) { 702 $terms = array( $term ); // Can only have one post format. 703 } 704 } 705 706 return $terms; 707 } 708 709 /** 710 * Filters post thumbnail lookup to set the post thumbnail. 711 * 712 * @since 4.6.0 713 * @access private 714 * 715 * @param null|array|string $value The value to return - a single metadata value, or an array of values. 716 * @param int $post_id Post ID. 717 * @param string $meta_key Meta key. 718 * @return null|array The default return value or the post thumbnail meta array. 719 */ 720 function _wp_preview_post_thumbnail_filter( $value, $post_id, $meta_key ) { 721 $post = get_post(); 722 if ( ! $post ) { 723 return $value; 724 } 725 726 if ( empty( $_REQUEST['_thumbnail_id'] ) || 727 empty( $_REQUEST['preview_id'] ) || 728 $post->ID != $post_id || 729 '_thumbnail_id' !== $meta_key || 730 'revision' === $post->post_type || 731 $post_id != $_REQUEST['preview_id'] ) { 732 733 return $value; 734 } 735 736 $thumbnail_id = (int) $_REQUEST['_thumbnail_id']; 737 if ( $thumbnail_id <= 0 ) { 738 return ''; 739 } 740 741 return (string) $thumbnail_id; 742 } 743 744 /** 745 * Gets the post revision version. 746 * 747 * @since 3.6.0 748 * @access private 749 * 750 * @param WP_Post $revision 751 * @return int|false 752 */ 753 function _wp_get_post_revision_version( $revision ) { 754 if ( is_object( $revision ) ) { 755 $revision = get_object_vars( $revision ); 756 } elseif ( ! is_array( $revision ) ) { 757 return false; 758 } 759 760 if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) ) { 761 return (int) $matches[1]; 762 } 763 764 return 0; 765 } 766 767 /** 768 * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1 769 * 770 * @since 3.6.0 771 * @access private 772 * 773 * @global wpdb $wpdb WordPress database abstraction object. 774 * 775 * @param WP_Post $post Post object 776 * @param array $revisions Current revisions of the post 777 * @return bool true if the revisions were upgraded, false if problems 778 */ 779 function _wp_upgrade_revisions_of_post( $post, $revisions ) { 780 global $wpdb; 781 782 // Add post option exclusively. 783 $lock = "revision-upgrade-{$post->ID}"; 784 $now = time(); 785 $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) ); 786 if ( ! $result ) { 787 // If we couldn't get a lock, see how old the previous lock is. 788 $locked = get_option( $lock ); 789 if ( ! $locked ) { 790 // Can't write to the lock, and can't read the lock. 791 // Something broken has happened. 792 return false; 793 } 794 795 if ( $locked > $now - 3600 ) { 796 // Lock is not too old: some other process may be upgrading this post. Bail. 797 return false; 798 } 799 800 // Lock is too old - update it (below) and continue. 801 } 802 803 // If we could get a lock, re-"add" the option to fire all the correct filters. 804 update_option( $lock, $now ); 805 806 reset( $revisions ); 807 $add_last = true; 808 809 do { 810 $this_revision = current( $revisions ); 811 $prev_revision = next( $revisions ); 812 813 $this_revision_version = _wp_get_post_revision_version( $this_revision ); 814 815 // Something terrible happened. 816 if ( false === $this_revision_version ) { 817 continue; 818 } 819 820 // 1 is the latest revision version, so we're already up to date. 821 // No need to add a copy of the post as latest revision. 822 if ( 0 < $this_revision_version ) { 823 $add_last = false; 824 continue; 825 } 826 827 // Always update the revision version. 828 $update = array( 829 'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ), 830 ); 831 832 /* 833 * If this revision is the oldest revision of the post, i.e. no $prev_revision, 834 * the correct post_author is probably $post->post_author, but that's only a good guess. 835 * Update the revision version only and Leave the author as-is. 836 */ 837 if ( $prev_revision ) { 838 $prev_revision_version = _wp_get_post_revision_version( $prev_revision ); 839 840 // If the previous revision is already up to date, it no longer has the information we need :( 841 if ( $prev_revision_version < 1 ) { 842 $update['post_author'] = $prev_revision->post_author; 843 } 844 } 845 846 // Upgrade this revision. 847 $result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) ); 848 849 if ( $result ) { 850 wp_cache_delete( $this_revision->ID, 'posts' ); 851 } 852 } while ( $prev_revision ); 853 854 delete_option( $lock ); 855 856 // Add a copy of the post as latest revision. 857 if ( $add_last ) { 858 wp_save_post_revision( $post->ID ); 859 } 860 861 return true; 862 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Dec 22 01:00:02 2024 | Cross-referenced by PHPXref 0.7.1 |