Ticket #20564: 20564.14.diff
File 20564.14.diff, 12.9 KB (added by , 10 years ago) |
---|
-
src/wp-admin/includes/post.php
1523 1523 $new_autosave['ID'] = $old_autosave->ID; 1524 1524 $new_autosave['post_author'] = $post_author; 1525 1525 1526 // Auto-save revisioned meta fields. 1527 foreach ( _wp_post_revision_meta_keys() as $meta_key ) { 1528 if ( isset( $_POST[ $meta_key ] ) 1529 && get_post_meta( $new_autosave['ID'], $meta_key, true ) != wp_unslash( $_POST[ $meta_key ] ) ) 1530 { 1531 /* 1532 * Use the underlying delete_metadata() and add_metadata() functions 1533 * vs delete_post_meta() and add_post_meta() to make sure we're working 1534 * with the actual revision meta. 1535 */ 1536 delete_metadata( 'post', $new_autosave['ID'], $meta_key ); 1537 if ( ! empty( $_POST[ $meta_key ] ) ) { 1538 error_log('wp_create_post_autosave saving meta data for ' . $meta_key ); 1539 //add_metadata( 'post', $new_autosave['ID'], $meta_key, $_POST[ $meta_key ] ); 1540 } 1541 } 1542 } 1543 1526 1544 // If the new autosave has the same content as the post, delete the autosave. 1527 1545 $post = get_post( $post_id ); 1528 1546 $autosave_is_different = false; -
src/wp-includes/revision.php
70 70 } 71 71 72 72 /** 73 * Determine which post meta fields should be revisioned. 74 * 75 * @access private 76 * @since 4.0.0 77 * 78 * @return array An array of meta keys to be revisioned. 79 */ 80 function _wp_post_revision_meta_keys() { 81 /** 82 * Filter the list of post meta keys to be revisioned. 83 * 84 * @since 4.0.0 85 * 86 * @param array $keys An array of default meta fields to be revisioned. 87 */ 88 return apply_filters( 'wp_post_revision_meta_keys', array() ); 89 } 90 91 /** 73 92 * Saves an already existing post as a post revision. 74 93 * 75 94 * Typically used immediately after post updates. … … 127 146 if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', $check_for_changes = true, $last_revision, $post ) ) { 128 147 $post_has_changed = false; 129 148 149 // Check whether revisioned post fields have been changed. 130 150 foreach ( array_keys( _wp_post_revision_fields() ) as $field ) { 131 151 if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) { 132 152 $post_has_changed = true; … … 133 153 break; 134 154 } 135 155 } 136 //don't save revision if post unchanged 156 157 // Check whether revisioned post meta fields have changed. 158 foreach ( _wp_post_revision_meta_keys() as $meta_key ) { 159 if ( get_post_meta( $post->ID, $meta_key ) != get_revision_post_meta( $last_revision->ID, $meta_key ) ) { 160 $post_has_changed = true; 161 break; 162 } 163 } 164 165 // Don't save revision if the post is unchanged. 137 166 if( ! $post_has_changed ) 138 167 return; 139 168 } 140 169 } 141 142 170 $return = _wp_put_post_revision( $post ); 143 171 144 172 $revisions_to_keep = wp_revisions_to_keep( $post ); … … 229 257 return false; 230 258 } 231 259 260 232 261 /** 262 * Retrieves a post_meta value for a specific revision. 263 * If the meta key is being revisioned, but the meta value was not saved 264 * in that revision, searches backward through the post's revisions to 265 * find last saved meta value. 266 * 267 * @since 4.0.0 268 * 269 * @param int $revision_id ID of the revision to find meta for. 270 * @param string $meta_key The key to retrieve. 271 * @return mixed Last revisioned value of meta field, false if not stored 272 * for this revision, blank if revisioned but never saved. 273 * 274 */ 275 function get_revision_post_meta( $revision_id, $meta_key ) { 276 $metas_revisioned = wp_unslash( get_metadata( 'post', $revision_id, '_wp_post_revision_meta_keys' ) ); 277 278 // If this meta was not revisioned for this revision return false 279 if ( ! in_array( $meta_key, $metas_revisioned[0] ) ) { 280 return false; 281 } 282 // If the current revision contains the meta value,no need to search for it 283 if ( '' !== ( $meta_value = wp_unslash( get_metadata( 'post', $revision_id, $meta_key, true ) ) ) ) { 284 return $meta_value; 285 } 286 // Otherwise, try to find the most recent revision that contains the meta value 287 // First select all this post's revisions 288 $revision = get_post( $revision_id ); 289 $all_revisions = wp_get_post_revisions( $revision->post_parent ); 290 291 if ( empty( $all_revisions ) ) { 292 return ''; /* no revisions, return blank */ 293 } 294 $current_found = false; 295 foreach( $all_revisions as $single_revision ) { 296 // Keep going back until we find the current revision 297 if ( ! $current_found ){ 298 if ( $single_revision->ID !== $revision_id ) { 299 continue; /* Not yet, try the next one */ 300 } else { 301 $current_found = true; /* Found, now examine the rest */ 302 } 303 } 304 // Check if this meta was revisioned for this revision 305 $metas_revisioned = wp_unslash( get_metadata( 'post', $single_revision->ID, '_wp_post_revision_meta_keys' ) ); 306 if ( in_array( $meta_key, $metas_revisioned[0] ) ) { 307 // If the meta value is not blank, return it (blank meta values are not revisioned) 308 if ( '' !== ( $meta_value = wp_unslash( get_metadata( 'post', $single_revision->ID, $meta_key, true ) ) ) ) { 309 return $meta_value; 310 } 311 } 312 } 313 // Fallback, no revisioned meta was found so return blank 314 return ''; 315 } 316 /** 233 317 * Inserts post data into the posts table as a post revision. 234 318 * 235 319 * @since 2.6.0 … … 253 337 if ( isset($post['post_type']) && 'revision' == $post['post_type'] ) 254 338 return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); 255 339 340 $post_id = (int) $post['ID']; 256 341 $post = _wp_post_revision_fields( $post, $autosave ); 257 342 $post = wp_slash($post); //since data is from db 258 343 … … 271 356 do_action( '_wp_put_post_revision', $revision_id ); 272 357 } 273 358 359 // Save revisioned meta fields. 360 foreach ( _wp_post_revision_meta_keys() as $meta_key ) { 361 $meta_value = get_post_meta( $post_id, $meta_key, true ); 362 // Don't save unchanged meta values 363 $previous_revisions = wp_get_post_revisions( $post_id, array( 'posts_per_page' => 2 ) ); 364 array_shift( $previous_revisions ); 365 $last_revision = array_shift( $previous_revisions ); 366 367 // Only save if the meta value has changed 368 if ( null == $last_revision || $meta_value == get_revision_post_meta( $last_revision->ID, $meta_key ) ) { 369 continue; 370 } 371 /* 372 * Use the underlying add_metadata() function vs add_post_meta() 373 * to ensure metadata is added to the revision post and not its parent. 374 */ 375 add_metadata( 'post', $revision_id, $meta_key, wp_slash( $meta_value ) ); 376 } 377 // Save the list of revisioned meta so we know which meta keys were revisioned 378 add_metadata( 'post', $revision_id, '_wp_post_revision_meta_keys', wp_slash( _wp_post_revision_meta_keys() ) ); 379 274 380 return $revision_id; 275 381 } 276 382 … … 336 442 337 443 $update['ID'] = $revision['post_parent']; 338 444 445 // Restore revisioned meta fields. 446 foreach ( _wp_post_revision_meta_keys() as $meta_key ) { 447 $meta_value = get_post_meta( $revision['ID'], $meta_key, true ); 448 if ( empty( $meta_value ) ) { 449 $meta_value = ''; 450 } 451 // Add slashes to data pulled from the database. 452 update_post_meta( $update['ID'], $meta_key, wp_slash( $meta_value ) ); 453 } 454 339 455 $update = wp_slash( $update ); //since data is from db 340 456 341 457 $post_id = wp_update_post( $update ); … … 503 619 $post->post_excerpt = $preview->post_excerpt; 504 620 505 621 add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 ); 622 add_filter( 'get_post_metadata', '_wp_preview_meta_filter', 10, 4 ); 506 623 507 624 return $post; 508 625 } … … 526 643 } 527 644 528 645 /** 646 * Filters post meta retrieval to get values from the actual autosave post, 647 * and not its parent. 648 * 649 * Filters revisioned meta keys only. 650 * 651 * @access private 652 * @since 4.0.0 653 * 654 * @param mixed $value Meta value to filter. 655 * @param int $object_id Object ID. 656 * @param string $meta_key Meta key to filter a value for. 657 * @param bool $single Whether to return a single value. Default false. 658 * @return mixed Original meta value if the meta key isn't revisioned, the object doesn't exist, 659 * the post type is a revisionm or the post ID doesn't match the object ID. 660 * Otherwise, the revisioned meta value is returned for the preview. 661 */ 662 function _wp_preview_meta_filter( $value, $object_id, $meta_key, $single ) { 663 $post = get_post(); 664 if ( empty( $post ) 665 || $post->ID != $object_id 666 || ! in_array( $meta_key, _wp_post_revision_meta_keys() ) 667 || 'revision' == $post->post_type ) 668 { 669 return $value; 670 } 671 672 // Grab the autosave. 673 $preview = wp_get_post_autosave( $post->ID ); 674 if ( ! is_object( $preview ) ) { 675 return $value; 676 } 677 678 return get_post_meta( $preview->ID, $meta_key, $single ); 679 } 680 681 /** 529 682 * Filters terms lookup to set the post format. 530 683 * 531 684 * @since 3.6.0 -
tests/phpunit/tests/post/revisions.php
385 385 $this->assertEquals( 100, $ok ); 386 386 $this->assertEquals( 0, $reversed ); 387 387 } 388 389 /** 390 * Test the revisions system for storage of meta values 391 * @ticket 20564 392 */ 393 function test_revisions_stores_meta_values() { 394 // Set up a new post 395 $original_post_id = $post_id = $this->factory->post->create(); 396 // And update to store an initial revision 397 wp_update_post( array( 'post_content' => 'some initial content', 'ID' => $post_id ) ); 398 399 // One revision so far 400 $revisions = wp_get_post_revisions( $post_id ); 401 $this->assertCount( 1, $revisions ); 402 /** 403 * First set up a meta value 404 */ 405 406 // Store a custom meta value, which is not revisioned by default 407 update_post_meta( $post_id, 'meta_revision_test', 'original' ); 408 409 // Update the post, storing a revision 410 wp_update_post( array( 'post_content' => 'some more content', 'ID' => $post_id ) ); 411 412 $revisions = wp_get_post_revisions( $post_id ); 413 $this->assertCount( 2, $revisions ); 414 415 416 // Next, store some updated meta values for the same key 417 update_post_meta( $post_id, 'meta_revision_test', 'update1' ); 418 419 // Save the post, changing content to force a revision 420 wp_update_post( array( 'post_content' => 'some updated content', 'ID' => $post_id ) ); 421 422 $revisions = wp_get_post_revisions( $post_id ); 423 $this->assertCount( 3, $revisions ); 424 425 426 /** 427 * Now restore the original revision 428 */ 429 430 // Restore the previous revision 431 $revisions = (Array)wp_get_post_revisions( $post_id ); 432 // Go back two to load the previous revision 433 array_shift( $revisions ); 434 $last_revision = array_shift( $revisions ); 435 // Restore! 436 wp_restore_post_revision( $last_revision->ID ); 437 438 wp_update_post( array( 'ID' => $post_id ) ); 439 $revisions = wp_get_post_revisions( $post_id ); 440 $this->assertCount( 4, $revisions ); 441 442 /** 443 * Check the meta values to verify they are NOT revisioned - they are not revisioned by default 444 */ 445 446 // Custom post meta should NOT be restored, orignal value should not be restored, value still 'update1' 447 $this->assertEquals( 'update1', get_post_meta( $post_id, 'meta_revision_test', true ) ); 448 449 update_post_meta( $post_id, 'meta_revision_test', 'update2' ); 450 451 452 /* 453 * Now test the revisioning of custom meta when enabled by the wp_post_revision_meta_keys filter 454 */ 455 456 // Add the custom field to be revised via the wp_post_revision_meta_keys filter 457 add_filter( 'wp_post_revision_meta_keys', function( $keys ) { 458 $keys[] = 'meta_revision_test'; 459 return $keys; 460 }); 461 462 // Save the post, changing content to force a revision 463 wp_update_post( array( 'post_content' => 'more updated content', 'ID' => $post_id ) ); 464 465 $revisions = wp_get_post_revisions( $post_id ); 466 $this->assertCount( 5, $revisions ); 467 468 // Store custom meta values, which should now be revisioned 469 update_post_meta( $post_id, 'meta_revision_test', 'update3' ); 470 471 /** 472 * Save the post again, custom meta should now be revisioned 473 * 474 * Note that a revision is saved even though there is no change 475 * in post content, becaused the revisioned post_meta has changed 476 * 477 */ 478 wp_update_post( array( 'ID' => $post_id ) ); 479 480 // This revision contains the existing post meta ('update3') 481 $revisions = wp_get_post_revisions( $post_id ); 482 $this->assertCount( 6, $revisions ); 483 484 // Verify that previous post meta is set 485 $this->assertEquals( 'update3', get_post_meta( $post_id, 'meta_revision_test', true ) ); 486 487 // Retore the previous revision 488 $revisions = wp_get_post_revisions( $post_id ); 489 490 491 // Go back two to load the previous revision 492 array_shift( $revisions ); 493 $last_revision = array_shift( $revisions ); 494 wp_restore_post_revision( $last_revision->ID ); 495 496 // Verify that previous post meta is restored 497 $this->assertEquals( 'update2', get_post_meta( $post_id, 'meta_revision_test', true ) ); 498 499 // Cleanup! 500 wp_delete_post( $original_post_id ); 501 502 } 388 503 }