[ Index ] |
WordPress Cross Reference |
[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 * Does two things. If passed a post *array*, it will return a post array ready 13 * to be inserted into the posts table as a post revision. Otherwise, returns 14 * an array whose keys are the post fields to be saved for post revisions. 15 * 16 * @since 2.6.0 17 * @access private 18 * 19 * @uses apply_filters() Calls '_wp_post_revision_fields' on 'title', 'content' and 'excerpt' fields. 20 * 21 * @param array $post Optional a post array to be processed for insertion as a post revision. 22 * @param bool $autosave optional Is the revision an autosave? 23 * @return array Post array ready to be inserted as a post revision or array of fields that can be versioned. 24 */ 25 function _wp_post_revision_fields( $post = null, $autosave = false ) { 26 static $fields = false; 27 28 if ( !$fields ) { 29 // Allow these to be versioned 30 $fields = array( 31 'post_title' => __( 'Title' ), 32 'post_content' => __( 'Content' ), 33 'post_excerpt' => __( 'Excerpt' ), 34 ); 35 36 // Runs only once 37 $fields = apply_filters( '_wp_post_revision_fields', $fields ); 38 39 // WP uses these internally either in versioning or elsewhere - they cannot be versioned 40 foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect ) 41 unset( $fields[$protect] ); 42 } 43 44 if ( !is_array($post) ) 45 return $fields; 46 47 $return = array(); 48 foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field ) 49 $return[$field] = $post[$field]; 50 51 $return['post_parent'] = $post['ID']; 52 $return['post_status'] = 'inherit'; 53 $return['post_type'] = 'revision'; 54 $return['post_name'] = $autosave ? "$post[ID]-autosave-v1" : "$post[ID]-revision-v1"; // "1" is the revisioning system version 55 $return['post_date'] = isset($post['post_modified']) ? $post['post_modified'] : ''; 56 $return['post_date_gmt'] = isset($post['post_modified_gmt']) ? $post['post_modified_gmt'] : ''; 57 58 return $return; 59 } 60 61 /** 62 * Saves an already existing post as a post revision. 63 * 64 * Typically used immediately after post updates. 65 * Adds a copy of the current post as a revision, so latest revision always matches current post 66 * 67 * @since 2.6.0 68 * 69 * @uses _wp_put_post_revision() 70 * 71 * @param int $post_id The ID of the post to save as a revision. 72 * @return mixed Null or 0 if error, new revision ID, if success. 73 */ 74 function wp_save_post_revision( $post_id ) { 75 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 76 return; 77 78 if ( ! $post = get_post( $post_id ) ) 79 return; 80 81 if ( ! post_type_supports( $post->post_type, 'revisions' ) ) 82 return; 83 84 if ( 'auto-draft' == $post->post_status ) 85 return; 86 87 if ( ! wp_revisions_enabled( $post ) ) 88 return; 89 90 // Compare the proposed update with the last stored revision verifying that 91 // they are different, unless a plugin tells us to always save regardless. 92 // If no previous revisions, save one 93 if ( $revisions = wp_get_post_revisions( $post_id ) ) { 94 // grab the last revision, but not an autosave 95 foreach ( $revisions as $revision ) { 96 if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) { 97 $last_revision = $revision; 98 break; 99 } 100 } 101 102 if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) { 103 $post_has_changed = false; 104 105 foreach ( array_keys( _wp_post_revision_fields() ) as $field ) { 106 if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) { 107 $post_has_changed = true; 108 break; 109 } 110 } 111 //don't save revision if post unchanged 112 if( ! $post_has_changed ) 113 return; 114 } 115 } 116 117 $return = _wp_put_post_revision( $post ); 118 119 $revisions_to_keep = wp_revisions_to_keep( $post ); 120 121 if ( $revisions_to_keep < 0 ) 122 return $return; 123 124 // all revisions and autosaves 125 $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) ); 126 127 $delete = count($revisions) - $revisions_to_keep; 128 129 if ( $delete < 1 ) 130 return $return; 131 132 $revisions = array_slice( $revisions, 0, $delete ); 133 134 for ( $i = 0; isset( $revisions[$i] ); $i++ ) { 135 if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) ) 136 continue; 137 138 wp_delete_post_revision( $revisions[ $i ]->ID ); 139 } 140 141 return $return; 142 } 143 144 /** 145 * Retrieve the autosaved data of the specified post. 146 * 147 * Returns a post object containing the information that was autosaved for the 148 * specified post. If the optional $user_id is passed, returns the autosave for that user 149 * otherwise returns the latest autosave. 150 * 151 * @since 2.6.0 152 * 153 * @uses wp_get_post_revisions() 154 * 155 * @param int $post_id The post ID. 156 * @param int $user_id optional The post author ID. 157 * @return object|bool The autosaved data or false on failure or when no autosave exists. 158 */ 159 function wp_get_post_autosave( $post_id, $user_id = 0 ) { 160 $revisions = wp_get_post_revisions( $post_id, array( 'check_enabled' => false ) ); 161 162 foreach ( $revisions as $revision ) { 163 if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) { 164 if ( $user_id && $user_id != $revision->post_author ) 165 continue; 166 167 return $revision; 168 break; 169 } 170 } 171 172 return false; 173 } 174 175 /** 176 * Determines if the specified post is a revision. 177 * 178 * @since 2.6.0 179 * 180 * @param int|object $post Post ID or post object. 181 * @return bool|int False if not a revision, ID of revision's parent otherwise. 182 */ 183 function wp_is_post_revision( $post ) { 184 if ( !$post = wp_get_post_revision( $post ) ) 185 return false; 186 187 return (int) $post->post_parent; 188 } 189 190 /** 191 * Determines if the specified post is an autosave. 192 * 193 * @since 2.6.0 194 * 195 * @param int|object $post Post ID or post object. 196 * @return bool|int False if not a revision, ID of autosave's parent otherwise 197 */ 198 function wp_is_post_autosave( $post ) { 199 if ( !$post = wp_get_post_revision( $post ) ) 200 return false; 201 202 if ( false !== strpos( $post->post_name, "{$post->post_parent}-autosave" ) ) 203 return (int) $post->post_parent; 204 205 return false; 206 } 207 208 /** 209 * Inserts post data into the posts table as a post revision. 210 * 211 * @since 2.6.0 212 * @access private 213 * 214 * @uses wp_insert_post() 215 * 216 * @param int|object|array $post Post ID, post object OR post array. 217 * @param bool $autosave Optional. Is the revision an autosave? 218 * @return mixed Null or 0 if error, new revision ID if success. 219 */ 220 function _wp_put_post_revision( $post = null, $autosave = false ) { 221 if ( is_object($post) ) 222 $post = get_object_vars( $post ); 223 elseif ( !is_array($post) ) 224 $post = get_post($post, ARRAY_A); 225 226 if ( !$post || empty($post['ID']) ) 227 return; 228 229 if ( isset($post['post_type']) && 'revision' == $post['post_type'] ) 230 return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); 231 232 $post_id = $post['ID']; 233 $post = _wp_post_revision_fields( $post, $autosave ); 234 $post = wp_slash($post); //since data is from db 235 236 $revision_id = wp_insert_post( $post ); 237 if ( is_wp_error($revision_id) ) 238 return $revision_id; 239 240 if ( $revision_id ) 241 do_action( '_wp_put_post_revision', $revision_id ); 242 243 return $revision_id; 244 } 245 246 /** 247 * Gets a post revision. 248 * 249 * @since 2.6.0 250 * 251 * @uses get_post() 252 * 253 * @param int|object $post The post ID or object. 254 * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. 255 * @param string $filter Optional sanitation filter. @see sanitize_post(). 256 * @return mixed Null if error or post object if success. 257 */ 258 function wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') { 259 $null = null; 260 if ( !$revision = get_post( $post, OBJECT, $filter ) ) 261 return $revision; 262 if ( 'revision' !== $revision->post_type ) 263 return $null; 264 265 if ( $output == OBJECT ) { 266 return $revision; 267 } elseif ( $output == ARRAY_A ) { 268 $_revision = get_object_vars($revision); 269 return $_revision; 270 } elseif ( $output == ARRAY_N ) { 271 $_revision = array_values(get_object_vars($revision)); 272 return $_revision; 273 } 274 275 return $revision; 276 } 277 278 /** 279 * Restores a post to the specified revision. 280 * 281 * Can restore a past revision using all fields of the post revision, or only selected fields. 282 * 283 * @since 2.6.0 284 * 285 * @uses wp_get_post_revision() 286 * @uses wp_update_post() 287 * @uses do_action() Calls 'wp_restore_post_revision' on post ID and revision ID if wp_update_post() 288 * is successful. 289 * 290 * @param int|object $revision_id Revision ID or revision object. 291 * @param array $fields Optional. What fields to restore from. Defaults to all. 292 * @return mixed Null if error, false if no fields to restore, (int) post ID if success. 293 */ 294 function wp_restore_post_revision( $revision_id, $fields = null ) { 295 if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) ) 296 return $revision; 297 298 if ( !is_array( $fields ) ) 299 $fields = array_keys( _wp_post_revision_fields() ); 300 301 $update = array(); 302 foreach( array_intersect( array_keys( $revision ), $fields ) as $field ) { 303 $update[$field] = $revision[$field]; 304 } 305 306 if ( !$update ) 307 return false; 308 309 $update['ID'] = $revision['post_parent']; 310 311 $update = wp_slash( $update ); //since data is from db 312 313 $post_id = wp_update_post( $update ); 314 if ( ! $post_id || is_wp_error( $post_id ) ) 315 return $post_id; 316 317 // Add restore from details 318 $restore_details = array( 319 'restored_revision_id' => $revision_id, 320 'restored_by_user' => get_current_user_id(), 321 'restored_time' => time() 322 ); 323 update_post_meta( $post_id, '_post_restored_from', $restore_details ); 324 325 // Update last edit user 326 update_post_meta( $post_id, '_edit_last', get_current_user_id() ); 327 328 do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] ); 329 330 return $post_id; 331 } 332 333 /** 334 * Deletes a revision. 335 * 336 * Deletes the row from the posts table corresponding to the specified revision. 337 * 338 * @since 2.6.0 339 * 340 * @uses wp_get_post_revision() 341 * @uses wp_delete_post() 342 * 343 * @param int|object $revision_id Revision ID or revision object. 344 * @return mixed Null or WP_Error if error, deleted post if success. 345 */ 346 function wp_delete_post_revision( $revision_id ) { 347 if ( !$revision = wp_get_post_revision( $revision_id ) ) 348 return $revision; 349 350 $delete = wp_delete_post( $revision->ID ); 351 if ( is_wp_error( $delete ) ) 352 return $delete; 353 354 if ( $delete ) 355 do_action( 'wp_delete_post_revision', $revision->ID, $revision ); 356 357 return $delete; 358 } 359 360 /** 361 * Returns all revisions of specified post. 362 * 363 * @since 2.6.0 364 * 365 * @uses get_children() 366 * 367 * @param int|object $post_id Post ID or post object 368 * @return array An array of revisions, or an empty array if none. 369 */ 370 function wp_get_post_revisions( $post_id = 0, $args = null ) { 371 $post = get_post( $post_id ); 372 if ( ! $post || empty( $post->ID ) ) 373 return array(); 374 375 $defaults = array( 'order' => 'DESC', 'orderby' => 'date', 'check_enabled' => true ); 376 $args = wp_parse_args( $args, $defaults ); 377 378 if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) ) 379 return array(); 380 381 $args = array_merge( $args, array( 'post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit' ) ); 382 383 if ( ! $revisions = get_children( $args ) ) 384 return array(); 385 386 return $revisions; 387 } 388 389 /** 390 * Determine if revisions are enabled for a given post. 391 * 392 * @since 3.6.0 393 * 394 * @uses wp_revisions_to_keep() 395 * 396 * @param object $post The post object. 397 * @return bool True if number of revisions to keep isn't zero, false otherwise. 398 */ 399 function wp_revisions_enabled( $post ) { 400 return wp_revisions_to_keep( $post ) != 0; 401 } 402 403 /** 404 * Determine how many revisions to retain for a given post. 405 * By default, an infinite number of revisions are stored if a post type supports revisions. 406 * 407 * @since 3.6.0 408 * 409 * @uses post_type_supports() 410 * @uses apply_filters() Calls 'wp_revisions_to_keep' hook on the number of revisions. 411 * 412 * @param object $post The post object. 413 * @return int The number of revisions to keep. 414 */ 415 function wp_revisions_to_keep( $post ) { 416 $num = WP_POST_REVISIONS; 417 418 if ( true === $num ) 419 $num = -1; 420 else 421 $num = intval( $num ); 422 423 if ( ! post_type_supports( $post->post_type, 'revisions' ) ) 424 $num = 0; 425 426 return (int) apply_filters( 'wp_revisions_to_keep', $num, $post ); 427 } 428 429 /** 430 * Sets up the post object for preview based on the post autosave. 431 * 432 * @since 2.7.0 433 * @access private 434 */ 435 function _set_preview($post) { 436 437 if ( ! is_object($post) ) 438 return $post; 439 440 $preview = wp_get_post_autosave($post->ID); 441 442 if ( ! is_object($preview) ) 443 return $post; 444 445 $preview = sanitize_post($preview); 446 447 $post->post_content = $preview->post_content; 448 $post->post_title = $preview->post_title; 449 $post->post_excerpt = $preview->post_excerpt; 450 451 add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 ); 452 453 return $post; 454 } 455 456 /** 457 * Filters the latest content for preview from the post autosave. 458 * 459 * @since 2.7.0 460 * @access private 461 */ 462 function _show_post_preview() { 463 464 if ( isset($_GET['preview_id']) && isset($_GET['preview_nonce']) ) { 465 $id = (int) $_GET['preview_id']; 466 467 if ( false == wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) ) 468 wp_die( __('You do not have permission to preview drafts.') ); 469 470 add_filter('the_preview', '_set_preview'); 471 } 472 } 473 474 /** 475 * Filters terms lookup to set the post format. 476 * 477 * @since 3.6.0 478 * @access private 479 */ 480 function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { 481 if ( ! $post = get_post() ) 482 return $terms; 483 484 if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id || 'post_format' != $taxonomy || 'revision' == $post->post_type ) 485 return $terms; 486 487 if ( 'standard' == $_REQUEST['post_format'] ) 488 $terms = array(); 489 elseif ( $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ) ) 490 $terms = array( $term ); // Can only have one post format 491 492 return $terms; 493 } 494 495 /** 496 * Gets the post revision version. 497 * 498 * @since 3.6.0 499 * @access private 500 */ 501 function _wp_get_post_revision_version( $revision ) { 502 if ( is_object( $revision ) ) 503 $revision = get_object_vars( $revision ); 504 elseif ( !is_array( $revision ) ) 505 return false; 506 507 if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) ) 508 return (int) $matches[1]; 509 510 return 0; 511 } 512 513 /** 514 * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1 515 * 516 * @since 3.6.0 517 * @access private 518 * 519 * @uses wp_get_post_revisions() 520 * 521 * @param object $post Post object 522 * @param array $revisions Current revisions of the post 523 * @return bool true if the revisions were upgraded, false if problems 524 */ 525 function _wp_upgrade_revisions_of_post( $post, $revisions ) { 526 global $wpdb; 527 528 // Add post option exclusively 529 $lock = "revision-upgrade-{$post->ID}"; 530 $now = time(); 531 $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) ); 532 if ( ! $result ) { 533 // If we couldn't get a lock, see how old the previous lock is 534 $locked = get_option( $lock ); 535 if ( ! $locked ) { 536 // Can't write to the lock, and can't read the lock. 537 // Something broken has happened 538 return false; 539 } 540 541 if ( $locked > $now - 3600 ) { 542 // Lock is not too old: some other process may be upgrading this post. Bail. 543 return false; 544 } 545 546 // Lock is too old - update it (below) and continue 547 } 548 549 // If we could get a lock, re-"add" the option to fire all the correct filters. 550 update_option( $lock, $now ); 551 552 reset( $revisions ); 553 $add_last = true; 554 555 do { 556 $this_revision = current( $revisions ); 557 $prev_revision = next( $revisions ); 558 559 $this_revision_version = _wp_get_post_revision_version( $this_revision ); 560 561 // Something terrible happened 562 if ( false === $this_revision_version ) 563 continue; 564 565 // 1 is the latest revision version, so we're already up to date. 566 // No need to add a copy of the post as latest revision. 567 if ( 0 < $this_revision_version ) { 568 $add_last = false; 569 continue; 570 } 571 572 // Always update the revision version 573 $update = array( 574 'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ), 575 ); 576 577 // If this revision is the oldest revision of the post, i.e. no $prev_revision, 578 // the correct post_author is probably $post->post_author, but that's only a good guess. 579 // Update the revision version only and Leave the author as-is. 580 if ( $prev_revision ) { 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 ( $prev_revision_version < 1 ) 585 $update['post_author'] = $prev_revision->post_author; 586 } 587 588 // Upgrade this revision 589 $result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) ); 590 591 if ( $result ) 592 wp_cache_delete( $this_revision->ID, 'posts' ); 593 594 } while ( $prev_revision ); 595 596 delete_option( $lock ); 597 598 // Add a copy of the post as latest revision. 599 if ( $add_last ) 600 wp_save_post_revision( $post->ID ); 601 602 return true; 603 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 25 01:41:18 2014 | WordPress honlapkészítés: online1.hu |