[ Index ]

WordPress Cross Reference

title

Body

[close]

/wp-includes/ -> revision.php (source)

   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  }


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu