wp/wp-includes/revision.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
    13  * to be inserted into the posts table as a post revision. Otherwise, returns
    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.
    14  * an array whose keys are the post fields to be saved for post revisions.
    15  *
    15  *
    16  * @since 2.6.0
    16  * @since 2.6.0
    17  * @access private
    17  * @access private
    18  *
       
    19  * @uses apply_filters() Calls '_wp_post_revision_fields' on 'title', 'content' and 'excerpt' fields.
       
    20  *
    18  *
    21  * @param array $post Optional a post array to be processed for insertion as a post revision.
    19  * @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?
    20  * @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.
    21  * @return array Post array ready to be inserted as a post revision or array of fields that can be versioned.
    24  */
    22  */
    31 			'post_title' => __( 'Title' ),
    29 			'post_title' => __( 'Title' ),
    32 			'post_content' => __( 'Content' ),
    30 			'post_content' => __( 'Content' ),
    33 			'post_excerpt' => __( 'Excerpt' ),
    31 			'post_excerpt' => __( 'Excerpt' ),
    34 		);
    32 		);
    35 
    33 
    36 		// Runs only once
    34 		/**
       
    35 		 * Filter the list of fields saved in post revisions.
       
    36 		 *
       
    37 		 * Included by default: 'post_title', 'post_content' and 'post_excerpt'.
       
    38 		 *
       
    39 		 * Disallowed fields: 'ID', 'post_name', 'post_parent', 'post_date',
       
    40 		 * 'post_date_gmt', 'post_status', 'post_type', 'comment_count',
       
    41 		 * and 'post_author'.
       
    42 		 *
       
    43 		 * @since 2.6.0
       
    44 		 *
       
    45 		 * @param array $fields List of fields to revision. Contains 'post_title',
       
    46 		 *                      'post_content', and 'post_excerpt' by default.
       
    47 		 */
    37 		$fields = apply_filters( '_wp_post_revision_fields', $fields );
    48 		$fields = apply_filters( '_wp_post_revision_fields', $fields );
    38 
    49 
    39 		// WP uses these internally either in versioning or elsewhere - they cannot be versioned
    50 		// 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 )
    51 		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] );
    52 			unset( $fields[$protect] );
    57 
    68 
    58 	return $return;
    69 	return $return;
    59 }
    70 }
    60 
    71 
    61 /**
    72 /**
    62  * Saves an already existing post as a post revision.
    73  * Creates a revision for the current version of a post.
    63  *
    74  *
    64  * Typically used immediately after post updates.
    75  * Typically used immediately after a post update, as every update is a revision,
    65  * Adds a copy of the current post as a revision, so latest revision always matches current post
    76  * and the most recent revision always matches the current post.
    66  *
    77  *
    67  * @since 2.6.0
    78  * @since 2.6.0
    68  *
    79  *
    69  * @uses _wp_put_post_revision()
    80  * @param  int $post_id The ID of the post to save as a revision.
    70  *
    81  * @return null|int Null or 0 if error, new revision ID, if success.
    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  */
    82  */
    74 function wp_save_post_revision( $post_id ) {
    83 function wp_save_post_revision( $post_id ) {
    75 	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
    84 	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
    76 		return;
    85 		return;
    77 
    86 
    97 				$last_revision = $revision;
   106 				$last_revision = $revision;
    98 				break;
   107 				break;
    99 			}
   108 			}
   100 		}
   109 		}
   101 
   110 
   102 		if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) {
   111 		/**
       
   112 		 * Filter whether the post has changed since the last revision.
       
   113 		 *
       
   114 		 * By default a revision is saved only if one of the revisioned fields has changed.
       
   115 		 * This filter can override that so a revision is saved even if nothing has changed.
       
   116 		 *
       
   117 		 * @since 3.6.0
       
   118 		 *
       
   119 		 * @param bool    $check_for_changes Whether to check for changes before saving a new revision.
       
   120 		 *                                   Default true.
       
   121 		 * @param WP_Post $last_revision     The the last revision post object.
       
   122 		 * @param WP_Post $post              The post object.
       
   123 		 *
       
   124 		 */
       
   125 		if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', $check_for_changes = true, $last_revision, $post ) ) {
   103 			$post_has_changed = false;
   126 			$post_has_changed = false;
   104 
   127 
   105 			foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
   128 			foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
   106 				if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
   129 				if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
   107 					$post_has_changed = true;
   130 					$post_has_changed = true;
   108 					break;
   131 					break;
   109 				}
   132 				}
   110 			}
   133 			}
       
   134 
       
   135 			/**
       
   136 			 * Filter whether a post has changed.
       
   137 			 *
       
   138 			 * By default a revision is saved only if one of the revisioned fields has changed.
       
   139 			 * This filter allows for additional checks to determine if there were changes.
       
   140 			 *
       
   141 			 * @since 4.1.0
       
   142 			 *
       
   143 			 * @param bool    $post_has_changed Whether the post has changed.
       
   144 			 * @param WP_Post $last_revision    The last revision post object.
       
   145 			 * @param WP_Post $post             The post object.
       
   146 			 *
       
   147 			 */
       
   148 			$post_has_changed = (bool) apply_filters( 'wp_save_post_revision_post_has_changed', $post_has_changed, $last_revision, $post );
       
   149 
   111 			//don't save revision if post unchanged
   150 			//don't save revision if post unchanged
   112 			if( ! $post_has_changed )
   151 			if( ! $post_has_changed ) {
   113 				return;
   152 				return;
       
   153 			}
   114 		}
   154 		}
   115 	}
   155 	}
   116 
   156 
   117 	$return = _wp_put_post_revision( $post );
   157 	$return = _wp_put_post_revision( $post );
   118 
   158 
       
   159 	// If a limit for the number of revisions to keep has been set,
       
   160 	// delete the oldest ones.
   119 	$revisions_to_keep = wp_revisions_to_keep( $post );
   161 	$revisions_to_keep = wp_revisions_to_keep( $post );
   120 
   162 
   121 	if ( $revisions_to_keep < 0 )
   163 	if ( $revisions_to_keep < 0 )
   122 		return $return;
   164 		return $return;
   123 
   165 
   124 	// all revisions and autosaves
       
   125 	$revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) );
   166 	$revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) );
   126 
   167 
   127 	$delete = count($revisions) - $revisions_to_keep;
   168 	$delete = count($revisions) - $revisions_to_keep;
   128 
   169 
   129 	if ( $delete < 1 )
   170 	if ( $delete < 1 )
   147  * Returns a post object containing the information that was autosaved for the
   188  * 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
   189  * specified post. If the optional $user_id is passed, returns the autosave for that user
   149  * otherwise returns the latest autosave.
   190  * otherwise returns the latest autosave.
   150  *
   191  *
   151  * @since 2.6.0
   192  * @since 2.6.0
   152  *
       
   153  * @uses wp_get_post_revisions()
       
   154  *
   193  *
   155  * @param int $post_id The post ID.
   194  * @param int $post_id The post ID.
   156  * @param int $user_id optional The post author ID.
   195  * @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.
   196  * @return object|bool The autosaved data or false on failure or when no autosave exists.
   158  */
   197  */
   163 		if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) {
   202 		if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) {
   164 			if ( $user_id && $user_id != $revision->post_author )
   203 			if ( $user_id && $user_id != $revision->post_author )
   165 				continue;
   204 				continue;
   166 
   205 
   167 			return $revision;
   206 			return $revision;
   168 			break;
       
   169 		}
   207 		}
   170 	}
   208 	}
   171 
   209 
   172 	return false;
   210 	return false;
   173 }
   211 }
   209  * Inserts post data into the posts table as a post revision.
   247  * Inserts post data into the posts table as a post revision.
   210  *
   248  *
   211  * @since 2.6.0
   249  * @since 2.6.0
   212  * @access private
   250  * @access private
   213  *
   251  *
   214  * @uses wp_insert_post()
       
   215  *
       
   216  * @param int|object|array $post Post ID, post object OR post array.
   252  * @param int|object|array $post Post ID, post object OR post array.
   217  * @param bool $autosave Optional. Is the revision an autosave?
   253  * @param bool $autosave Optional. Is the revision an autosave?
   218  * @return mixed Null or 0 if error, new revision ID if success.
   254  * @return mixed WP_Error or 0 if error, new revision ID if success.
   219  */
   255  */
   220 function _wp_put_post_revision( $post = null, $autosave = false ) {
   256 function _wp_put_post_revision( $post = null, $autosave = false ) {
   221 	if ( is_object($post) )
   257 	if ( is_object($post) )
   222 		$post = get_object_vars( $post );
   258 		$post = get_object_vars( $post );
   223 	elseif ( !is_array($post) )
   259 	elseif ( !is_array($post) )
   224 		$post = get_post($post, ARRAY_A);
   260 		$post = get_post($post, ARRAY_A);
   225 
   261 
   226 	if ( !$post || empty($post['ID']) )
   262 	if ( ! $post || empty($post['ID']) )
   227 		return;
   263 		return new WP_Error( 'invalid_post', __( 'Invalid post ID' ) );
   228 
   264 
   229 	if ( isset($post['post_type']) && 'revision' == $post['post_type'] )
   265 	if ( isset($post['post_type']) && 'revision' == $post['post_type'] )
   230 		return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) );
   266 		return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) );
   231 
   267 
   232 	$post_id = $post['ID'];
       
   233 	$post = _wp_post_revision_fields( $post, $autosave );
   268 	$post = _wp_post_revision_fields( $post, $autosave );
   234 	$post = wp_slash($post); //since data is from db
   269 	$post = wp_slash($post); //since data is from db
   235 
   270 
   236 	$revision_id = wp_insert_post( $post );
   271 	$revision_id = wp_insert_post( $post );
   237 	if ( is_wp_error($revision_id) )
   272 	if ( is_wp_error($revision_id) )
   238 		return $revision_id;
   273 		return $revision_id;
   239 
   274 
   240 	if ( $revision_id )
   275 	if ( $revision_id ) {
       
   276 		/**
       
   277 		 * Fires once a revision has been saved.
       
   278 		 *
       
   279 		 * @since 2.6.0
       
   280 		 *
       
   281 		 * @param int $revision_id Post revision ID.
       
   282 		 */
   241 		do_action( '_wp_put_post_revision', $revision_id );
   283 		do_action( '_wp_put_post_revision', $revision_id );
       
   284 	}
   242 
   285 
   243 	return $revision_id;
   286 	return $revision_id;
   244 }
   287 }
   245 
   288 
   246 /**
   289 /**
   247  * Gets a post revision.
   290  * Gets a post revision.
   248  *
   291  *
   249  * @since 2.6.0
   292  * @since 2.6.0
   250  *
       
   251  * @uses get_post()
       
   252  *
   293  *
   253  * @param int|object $post The post ID or object.
   294  * @param int|object $post The post ID or object.
   254  * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N.
   295  * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N.
   255  * @param string $filter Optional sanitation filter. @see sanitize_post().
   296  * @param string $filter Optional sanitation filter. @see sanitize_post().
   256  * @return mixed Null if error or post object if success.
   297  * @return mixed Null if error or post object if success.
   257  */
   298  */
   258 function wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') {
   299 function wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') {
   259 	$null = null;
       
   260 	if ( !$revision = get_post( $post, OBJECT, $filter ) )
   300 	if ( !$revision = get_post( $post, OBJECT, $filter ) )
   261 		return $revision;
   301 		return $revision;
   262 	if ( 'revision' !== $revision->post_type )
   302 	if ( 'revision' !== $revision->post_type )
   263 		return $null;
   303 		return null;
   264 
   304 
   265 	if ( $output == OBJECT ) {
   305 	if ( $output == OBJECT ) {
   266 		return $revision;
   306 		return $revision;
   267 	} elseif ( $output == ARRAY_A ) {
   307 	} elseif ( $output == ARRAY_A ) {
   268 		$_revision = get_object_vars($revision);
   308 		$_revision = get_object_vars($revision);
   280  *
   320  *
   281  * Can restore a past revision using all fields of the post revision, or only selected fields.
   321  * Can restore a past revision using all fields of the post revision, or only selected fields.
   282  *
   322  *
   283  * @since 2.6.0
   323  * @since 2.6.0
   284  *
   324  *
   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.
   325  * @param int|object $revision_id Revision ID or revision object.
   291  * @param array $fields Optional. What fields to restore from. Defaults to all.
   326  * @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.
   327  * @return mixed Null if error, false if no fields to restore, (int) post ID if success.
   293  */
   328  */
   294 function wp_restore_post_revision( $revision_id, $fields = null ) {
   329 function wp_restore_post_revision( $revision_id, $fields = null ) {
   323 	update_post_meta( $post_id, '_post_restored_from', $restore_details );
   358 	update_post_meta( $post_id, '_post_restored_from', $restore_details );
   324 
   359 
   325 	// Update last edit user
   360 	// Update last edit user
   326 	update_post_meta( $post_id, '_edit_last', get_current_user_id() );
   361 	update_post_meta( $post_id, '_edit_last', get_current_user_id() );
   327 
   362 
       
   363 	/**
       
   364 	 * Fires after a post revision has been restored.
       
   365 	 *
       
   366 	 * @since 2.6.0
       
   367 	 *
       
   368 	 * @param int $post_id     Post ID.
       
   369 	 * @param int $revision_id Post revision ID.
       
   370 	 */
   328 	do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] );
   371 	do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] );
   329 
   372 
   330 	return $post_id;
   373 	return $post_id;
   331 }
   374 }
   332 
   375 
   334  * Deletes a revision.
   377  * Deletes a revision.
   335  *
   378  *
   336  * Deletes the row from the posts table corresponding to the specified revision.
   379  * Deletes the row from the posts table corresponding to the specified revision.
   337  *
   380  *
   338  * @since 2.6.0
   381  * @since 2.6.0
   339  *
       
   340  * @uses wp_get_post_revision()
       
   341  * @uses wp_delete_post()
       
   342  *
   382  *
   343  * @param int|object $revision_id Revision ID or revision object.
   383  * @param int|object $revision_id Revision ID or revision object.
   344  * @return mixed Null or WP_Error if error, deleted post if success.
   384  * @return mixed Null or WP_Error if error, deleted post if success.
   345  */
   385  */
   346 function wp_delete_post_revision( $revision_id ) {
   386 function wp_delete_post_revision( $revision_id ) {
   349 
   389 
   350 	$delete = wp_delete_post( $revision->ID );
   390 	$delete = wp_delete_post( $revision->ID );
   351 	if ( is_wp_error( $delete ) )
   391 	if ( is_wp_error( $delete ) )
   352 		return $delete;
   392 		return $delete;
   353 
   393 
   354 	if ( $delete )
   394 	if ( $delete ) {
       
   395 		/**
       
   396 		 * Fires once a post revision has been deleted.
       
   397 		 *
       
   398 		 * @since 2.6.0
       
   399 		 *
       
   400 		 * @param int          $revision_id Post revision ID.
       
   401 		 * @param object|array $revision    Post revision object or array.
       
   402 		 */
   355 		do_action( 'wp_delete_post_revision', $revision->ID, $revision );
   403 		do_action( 'wp_delete_post_revision', $revision->ID, $revision );
       
   404 	}
   356 
   405 
   357 	return $delete;
   406 	return $delete;
   358 }
   407 }
   359 
   408 
   360 /**
   409 /**
   361  * Returns all revisions of specified post.
   410  * Returns all revisions of specified post.
   362  *
   411  *
   363  * @since 2.6.0
   412  * @since 2.6.0
   364  *
   413  *
   365  * @uses get_children()
   414  * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post.
   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.
   415  * @return array An array of revisions, or an empty array if none.
   369  */
   416  */
   370 function wp_get_post_revisions( $post_id = 0, $args = null ) {
   417 function wp_get_post_revisions( $post_id = 0, $args = null ) {
   371 	$post = get_post( $post_id );
   418 	$post = get_post( $post_id );
   372 	if ( ! $post || empty( $post->ID ) )
   419 	if ( ! $post || empty( $post->ID ) )
   373 		return array();
   420 		return array();
   374 
   421 
   375 	$defaults = array( 'order' => 'DESC', 'orderby' => 'date', 'check_enabled' => true );
   422 	$defaults = array( 'order' => 'DESC', 'orderby' => 'date ID', 'check_enabled' => true );
   376 	$args = wp_parse_args( $args, $defaults );
   423 	$args = wp_parse_args( $args, $defaults );
   377 
   424 
   378 	if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) )
   425 	if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) )
   379 		return array();
   426 		return array();
   380 
   427 
   389 /**
   436 /**
   390  * Determine if revisions are enabled for a given post.
   437  * Determine if revisions are enabled for a given post.
   391  *
   438  *
   392  * @since 3.6.0
   439  * @since 3.6.0
   393  *
   440  *
   394  * @uses wp_revisions_to_keep()
   441  * @param WP_Post $post The post object.
   395  *
       
   396  * @param object $post The post object.
       
   397  * @return bool True if number of revisions to keep isn't zero, false otherwise.
   442  * @return bool True if number of revisions to keep isn't zero, false otherwise.
   398  */
   443  */
   399 function wp_revisions_enabled( $post ) {
   444 function wp_revisions_enabled( $post ) {
   400 	return wp_revisions_to_keep( $post ) != 0;
   445 	return wp_revisions_to_keep( $post ) != 0;
   401 }
   446 }
   402 
   447 
   403 /**
   448 /**
   404  * Determine how many revisions to retain for a given post.
   449  * 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.
   450  *
       
   451  * By default, an infinite number of revisions are kept.
       
   452  *
       
   453  * The constant WP_POST_REVISIONS can be set in wp-config to specify the limit
       
   454  * of revisions to keep.
   406  *
   455  *
   407  * @since 3.6.0
   456  * @since 3.6.0
   408  *
   457  *
   409  * @uses post_type_supports()
   458  * @param WP_Post $post The post object.
   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.
   459  * @return int The number of revisions to keep.
   414  */
   460  */
   415 function wp_revisions_to_keep( $post ) {
   461 function wp_revisions_to_keep( $post ) {
   416 	$num = WP_POST_REVISIONS;
   462 	$num = WP_POST_REVISIONS;
   417 
   463 
   421 		$num = intval( $num );
   467 		$num = intval( $num );
   422 
   468 
   423 	if ( ! post_type_supports( $post->post_type, 'revisions' ) )
   469 	if ( ! post_type_supports( $post->post_type, 'revisions' ) )
   424 		$num = 0;
   470 		$num = 0;
   425 
   471 
       
   472 	/**
       
   473 	 * Filter the number of revisions to save for the given post.
       
   474 	 *
       
   475 	 * Overrides the value of WP_POST_REVISIONS.
       
   476 	 *
       
   477 	 * @since 3.6.0
       
   478 	 *
       
   479 	 * @param int     $num  Number of revisions to store.
       
   480 	 * @param WP_Post $post Post object.
       
   481 	 */
   426 	return (int) apply_filters( 'wp_revisions_to_keep', $num, $post );
   482 	return (int) apply_filters( 'wp_revisions_to_keep', $num, $post );
   427 }
   483 }
   428 
   484 
   429 /**
   485 /**
   430  * Sets up the post object for preview based on the post autosave.
   486  * Sets up the post object for preview based on the post autosave.
   514  * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1
   570  * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1
   515  *
   571  *
   516  * @since 3.6.0
   572  * @since 3.6.0
   517  * @access private
   573  * @access private
   518  *
   574  *
   519  * @uses wp_get_post_revisions()
   575  * @param WP_Post $post Post object
   520  *
       
   521  * @param object $post Post object
       
   522  * @param array $revisions Current revisions of the post
   576  * @param array $revisions Current revisions of the post
   523  * @return bool true if the revisions were upgraded, false if problems
   577  * @return bool true if the revisions were upgraded, false if problems
   524  */
   578  */
   525 function _wp_upgrade_revisions_of_post( $post, $revisions ) {
   579 function _wp_upgrade_revisions_of_post( $post, $revisions ) {
   526 	global $wpdb;
   580 	global $wpdb;