15 * @access private |
15 * @access private |
16 * |
16 * |
17 * @param array|WP_Post $post Optional. A post array or a WP_Post object being processed |
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. |
18 * for insertion as a post revision. Default empty array. |
19 * @param bool $deprecated Not used. |
19 * @param bool $deprecated Not used. |
20 * @return array Array of fields that can be versioned. |
20 * @return string[] Array of fields that can be versioned. |
21 */ |
21 */ |
22 function _wp_post_revision_fields( $post = array(), $deprecated = false ) { |
22 function _wp_post_revision_fields( $post = array(), $deprecated = false ) { |
23 static $fields = null; |
23 static $fields = null; |
24 |
24 |
25 if ( ! is_array( $post ) ) { |
25 if ( ! is_array( $post ) ) { |
45 * and 'post_author'. |
45 * and 'post_author'. |
46 * |
46 * |
47 * @since 2.6.0 |
47 * @since 2.6.0 |
48 * @since 4.5.0 The `$post` parameter was added. |
48 * @since 4.5.0 The `$post` parameter was added. |
49 * |
49 * |
50 * @param array $fields List of fields to revision. Contains 'post_title', |
50 * @param string[] $fields List of fields to revision. Contains 'post_title', |
51 * 'post_content', and 'post_excerpt' by default. |
51 * 'post_content', and 'post_excerpt' by default. |
52 * @param array $post A post array being processed for insertion as a post revision. |
52 * @param array $post A post array being processed for insertion as a post revision. |
53 */ |
53 */ |
54 $fields = apply_filters( '_wp_post_revision_fields', $fields, $post ); |
54 $fields = apply_filters( '_wp_post_revision_fields', $fields, $post ); |
55 |
55 |
56 // WP uses these internally either in versioning or elsewhere - they cannot be versioned. |
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 ) { |
57 foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect ) { |
94 |
94 |
95 return $revision_data; |
95 return $revision_data; |
96 } |
96 } |
97 |
97 |
98 /** |
98 /** |
|
99 * Saves revisions for a post after all changes have been made. |
|
100 * |
|
101 * @since 6.4.0 |
|
102 * |
|
103 * @param int $post_id The post id that was inserted. |
|
104 * @param WP_Post $post The post object that was inserted. |
|
105 * @param bool $update Whether this insert is updating an existing post. |
|
106 */ |
|
107 function wp_save_post_revision_on_insert( $post_id, $post, $update ) { |
|
108 if ( ! $update ) { |
|
109 return; |
|
110 } |
|
111 |
|
112 if ( ! has_action( 'post_updated', 'wp_save_post_revision' ) ) { |
|
113 return; |
|
114 } |
|
115 |
|
116 wp_save_post_revision( $post_id ); |
|
117 } |
|
118 |
|
119 /** |
99 * Creates a revision for the current version of a post. |
120 * Creates a revision for the current version of a post. |
100 * |
121 * |
101 * Typically used immediately after a post update, as every update is a revision, |
122 * Typically used immediately after a post update, as every update is a revision, |
102 * and the most recent revision always matches the current post. |
123 * and the most recent revision always matches the current post. |
103 * |
124 * |
133 * they are different, unless a plugin tells us to always save regardless. |
160 * they are different, unless a plugin tells us to always save regardless. |
134 * If no previous revisions, save one. |
161 * If no previous revisions, save one. |
135 */ |
162 */ |
136 $revisions = wp_get_post_revisions( $post_id ); |
163 $revisions = wp_get_post_revisions( $post_id ); |
137 if ( $revisions ) { |
164 if ( $revisions ) { |
138 // Grab the last revision, but not an autosave. |
165 // Grab the latest revision, but not an autosave. |
139 foreach ( $revisions as $revision ) { |
166 foreach ( $revisions as $revision ) { |
140 if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) { |
167 if ( str_contains( $revision->post_name, "{$revision->post_parent}-revision" ) ) { |
141 $last_revision = $revision; |
168 $latest_revision = $revision; |
142 break; |
169 break; |
143 } |
170 } |
144 } |
171 } |
145 |
172 |
146 /** |
173 /** |
147 * Filters whether the post has changed since the last revision. |
174 * Filters whether the post has changed since the latest revision. |
148 * |
175 * |
149 * By default a revision is saved only if one of the revisioned fields has changed. |
176 * 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. |
177 * This filter can override that so a revision is saved even if nothing has changed. |
151 * |
178 * |
152 * @since 3.6.0 |
179 * @since 3.6.0 |
153 * |
180 * |
154 * @param bool $check_for_changes Whether to check for changes before saving a new revision. |
181 * @param bool $check_for_changes Whether to check for changes before saving a new revision. |
155 * Default true. |
182 * Default true. |
156 * @param WP_Post $last_revision The last revision post object. |
183 * @param WP_Post $latest_revision The latest revision post object. |
157 * @param WP_Post $post The post object. |
184 * @param WP_Post $post The post object. |
158 */ |
185 */ |
159 if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) { |
186 if ( isset( $latest_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $latest_revision, $post ) ) { |
160 $post_has_changed = false; |
187 $post_has_changed = false; |
161 |
188 |
162 foreach ( array_keys( _wp_post_revision_fields( $post ) ) as $field ) { |
189 foreach ( array_keys( _wp_post_revision_fields( $post ) ) as $field ) { |
163 if ( normalize_whitespace( $post->$field ) !== normalize_whitespace( $last_revision->$field ) ) { |
190 if ( normalize_whitespace( $post->$field ) !== normalize_whitespace( $latest_revision->$field ) ) { |
164 $post_has_changed = true; |
191 $post_has_changed = true; |
165 break; |
192 break; |
166 } |
193 } |
167 } |
194 } |
168 |
195 |
173 * This filter allows for additional checks to determine if there were changes. |
200 * This filter allows for additional checks to determine if there were changes. |
174 * |
201 * |
175 * @since 4.1.0 |
202 * @since 4.1.0 |
176 * |
203 * |
177 * @param bool $post_has_changed Whether the post has changed. |
204 * @param bool $post_has_changed Whether the post has changed. |
178 * @param WP_Post $last_revision The last revision post object. |
205 * @param WP_Post $latest_revision The latest revision post object. |
179 * @param WP_Post $post The post object. |
206 * @param WP_Post $post The post object. |
180 */ |
207 */ |
181 $post_has_changed = (bool) apply_filters( 'wp_save_post_revision_post_has_changed', $post_has_changed, $last_revision, $post ); |
208 $post_has_changed = (bool) apply_filters( 'wp_save_post_revision_post_has_changed', $post_has_changed, $latest_revision, $post ); |
182 |
209 |
183 // Don't save revision if post unchanged. |
210 // Don't save revision if post unchanged. |
184 if ( ! $post_has_changed ) { |
211 if ( ! $post_has_changed ) { |
185 return; |
212 return; |
186 } |
213 } |
187 } |
214 } |
188 } |
215 } |
189 |
216 |
190 $return = _wp_put_post_revision( $post ); |
217 $return = _wp_put_post_revision( $post ); |
191 |
218 |
192 // If a limit for the number of revisions to keep has been set, |
219 /* |
193 // delete the oldest ones. |
220 * If a limit for the number of revisions to keep has been set, |
|
221 * delete the oldest ones. |
|
222 */ |
194 $revisions_to_keep = wp_revisions_to_keep( $post ); |
223 $revisions_to_keep = wp_revisions_to_keep( $post ); |
195 |
224 |
196 if ( $revisions_to_keep < 0 ) { |
225 if ( $revisions_to_keep < 0 ) { |
197 return $return; |
226 return $return; |
198 } |
227 } |
199 |
228 |
200 $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) ); |
229 $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) ); |
201 |
230 |
|
231 /** |
|
232 * Filters the revisions to be considered for deletion. |
|
233 * |
|
234 * @since 6.2.0 |
|
235 * |
|
236 * @param WP_Post[] $revisions Array of revisions, or an empty array if none. |
|
237 * @param int $post_id The ID of the post to save as a revision. |
|
238 */ |
|
239 $revisions = apply_filters( |
|
240 'wp_save_post_revision_revisions_before_deletion', |
|
241 $revisions, |
|
242 $post_id |
|
243 ); |
|
244 |
202 $delete = count( $revisions ) - $revisions_to_keep; |
245 $delete = count( $revisions ) - $revisions_to_keep; |
203 |
246 |
204 if ( $delete < 1 ) { |
247 if ( $delete < 1 ) { |
205 return $return; |
248 return $return; |
206 } |
249 } |
207 |
250 |
208 $revisions = array_slice( $revisions, 0, $delete ); |
251 $revisions = array_slice( $revisions, 0, $delete ); |
209 |
252 |
210 for ( $i = 0; isset( $revisions[ $i ] ); $i++ ) { |
253 for ( $i = 0; isset( $revisions[ $i ] ); $i++ ) { |
211 if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) ) { |
254 if ( str_contains( $revisions[ $i ]->post_name, 'autosave' ) ) { |
212 continue; |
255 continue; |
213 } |
256 } |
214 |
257 |
215 wp_delete_post_revision( $revisions[ $i ]->ID ); |
258 wp_delete_post_revision( $revisions[ $i ]->ID ); |
216 } |
259 } |
217 |
260 |
218 return $return; |
261 return $return; |
219 } |
262 } |
220 |
263 |
221 /** |
264 /** |
222 * Retrieve the autosaved data of the specified post. |
265 * Retrieves the autosaved data of the specified post. |
223 * |
266 * |
224 * Returns a post object with the information that was autosaved for the specified post. |
267 * 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 |
268 * If the optional $user_id is passed, returns the autosave for that user, otherwise |
226 * returns the latest autosave. |
269 * returns the latest autosave. |
227 * |
270 * |
228 * @since 2.6.0 |
271 * @since 2.6.0 |
229 * |
272 * |
230 * @global wpdb $wpdb WordPress database abstraction object. |
273 * @global wpdb $wpdb WordPress database abstraction object. |
231 * |
274 * |
232 * @param int $post_id The post ID. |
275 * @param int $post_id The post ID. |
233 * @param int $user_id Optional The post author ID. |
276 * @param int $user_id Optional. The post author ID. Default 0. |
234 * @return WP_Post|false The autosaved data or false on failure or when no autosave exists. |
277 * @return WP_Post|false The autosaved data or false on failure or when no autosave exists. |
235 */ |
278 */ |
236 function wp_get_post_autosave( $post_id, $user_id = 0 ) { |
279 function wp_get_post_autosave( $post_id, $user_id = 0 ) { |
237 global $wpdb; |
280 global $wpdb; |
238 |
281 |
308 * |
353 * |
309 * @since 2.6.0 |
354 * @since 2.6.0 |
310 * @access private |
355 * @access private |
311 * |
356 * |
312 * @param int|WP_Post|array|null $post Post ID, post object OR post array. |
357 * @param int|WP_Post|array|null $post Post ID, post object OR post array. |
313 * @param bool $autosave Optional. Is the revision an autosave? |
358 * @param bool $autosave Optional. Whether the revision is an autosave or not. |
|
359 * Default false. |
314 * @return int|WP_Error WP_Error or 0 if error, new revision ID if success. |
360 * @return int|WP_Error WP_Error or 0 if error, new revision ID if success. |
315 */ |
361 */ |
316 function _wp_put_post_revision( $post = null, $autosave = false ) { |
362 function _wp_put_post_revision( $post = null, $autosave = false ) { |
317 if ( is_object( $post ) ) { |
363 if ( is_object( $post ) ) { |
318 $post = get_object_vars( $post ); |
364 $post = get_object_vars( $post ); |
339 if ( $revision_id ) { |
385 if ( $revision_id ) { |
340 /** |
386 /** |
341 * Fires once a revision has been saved. |
387 * Fires once a revision has been saved. |
342 * |
388 * |
343 * @since 2.6.0 |
389 * @since 2.6.0 |
|
390 * @since 6.4.0 The post_id parameter was added. |
344 * |
391 * |
345 * @param int $revision_id Post revision ID. |
392 * @param int $revision_id Post revision ID. |
|
393 * @param int $post_id Post ID. |
346 */ |
394 */ |
347 do_action( '_wp_put_post_revision', $revision_id ); |
395 do_action( '_wp_put_post_revision', $revision_id, $post['post_parent'] ); |
348 } |
396 } |
349 |
397 |
350 return $revision_id; |
398 return $revision_id; |
351 } |
399 } |
352 |
400 |
|
401 |
|
402 /** |
|
403 * Save the revisioned meta fields. |
|
404 * |
|
405 * @since 6.4.0 |
|
406 * |
|
407 * @param int $revision_id The ID of the revision to save the meta to. |
|
408 * @param int $post_id The ID of the post the revision is associated with. |
|
409 */ |
|
410 function wp_save_revisioned_meta_fields( $revision_id, $post_id ) { |
|
411 $post_type = get_post_type( $post_id ); |
|
412 if ( ! $post_type ) { |
|
413 return; |
|
414 } |
|
415 |
|
416 foreach ( wp_post_revision_meta_keys( $post_type ) as $meta_key ) { |
|
417 if ( metadata_exists( 'post', $post_id, $meta_key ) ) { |
|
418 _wp_copy_post_meta( $post_id, $revision_id, $meta_key ); |
|
419 } |
|
420 } |
|
421 } |
|
422 |
353 /** |
423 /** |
354 * Gets a post revision. |
424 * Gets a post revision. |
355 * |
425 * |
356 * @since 2.6.0 |
426 * @since 2.6.0 |
357 * |
427 * |
358 * @param int|WP_Post $post The post ID or object. |
428 * @param int|WP_Post $post Post ID or post object. |
359 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which |
429 * @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, |
430 * correspond to a WP_Post object, an associative array, or a numeric array, |
361 * respectively. Default OBJECT. |
431 * respectively. Default OBJECT. |
362 * @param string $filter Optional sanitation filter. See sanitize_post(). |
432 * @param string $filter Optional sanitization filter. See sanitize_post(). Default 'raw'. |
363 * @return WP_Post|array|null WP_Post (or array) on success, or null on failure. |
433 * @return WP_Post|array|null WP_Post (or array) on success, or null on failure. |
364 */ |
434 */ |
365 function wp_get_post_revision( &$post, $output = OBJECT, $filter = 'raw' ) { |
435 function wp_get_post_revision( &$post, $output = OBJECT, $filter = 'raw' ) { |
366 $revision = get_post( $post, OBJECT, $filter ); |
436 $revision = get_post( $post, OBJECT, $filter ); |
|
437 |
367 if ( ! $revision ) { |
438 if ( ! $revision ) { |
368 return $revision; |
439 return $revision; |
369 } |
440 } |
|
441 |
370 if ( 'revision' !== $revision->post_type ) { |
442 if ( 'revision' !== $revision->post_type ) { |
371 return null; |
443 return null; |
372 } |
444 } |
373 |
445 |
374 if ( OBJECT === $output ) { |
446 if ( OBJECT === $output ) { |
389 * |
461 * |
390 * Can restore a past revision using all fields of the post revision, or only selected fields. |
462 * Can restore a past revision using all fields of the post revision, or only selected fields. |
391 * |
463 * |
392 * @since 2.6.0 |
464 * @since 2.6.0 |
393 * |
465 * |
394 * @param int|WP_Post $revision_id Revision ID or revision object. |
466 * @param int|WP_Post $revision Revision ID or revision object. |
395 * @param array $fields Optional. What fields to restore from. Defaults to all. |
467 * @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. |
468 * @return int|false|null Null if error, false if no fields to restore, (int) post ID if success. |
397 */ |
469 */ |
398 function wp_restore_post_revision( $revision_id, $fields = null ) { |
470 function wp_restore_post_revision( $revision, $fields = null ) { |
399 $revision = wp_get_post_revision( $revision_id, ARRAY_A ); |
471 $revision = wp_get_post_revision( $revision, ARRAY_A ); |
|
472 |
400 if ( ! $revision ) { |
473 if ( ! $revision ) { |
401 return $revision; |
474 return $revision; |
402 } |
475 } |
403 |
476 |
404 if ( ! is_array( $fields ) ) { |
477 if ( ! is_array( $fields ) ) { |
438 |
512 |
439 return $post_id; |
513 return $post_id; |
440 } |
514 } |
441 |
515 |
442 /** |
516 /** |
|
517 * Restore the revisioned meta values for a post. |
|
518 * |
|
519 * @since 6.4.0 |
|
520 * |
|
521 * @param int $post_id The ID of the post to restore the meta to. |
|
522 * @param int $revision_id The ID of the revision to restore the meta from. |
|
523 */ |
|
524 function wp_restore_post_revision_meta( $post_id, $revision_id ) { |
|
525 $post_type = get_post_type( $post_id ); |
|
526 if ( ! $post_type ) { |
|
527 return; |
|
528 } |
|
529 |
|
530 // Restore revisioned meta fields. |
|
531 foreach ( wp_post_revision_meta_keys( $post_type ) as $meta_key ) { |
|
532 |
|
533 // Clear any existing meta. |
|
534 delete_post_meta( $post_id, $meta_key ); |
|
535 |
|
536 _wp_copy_post_meta( $revision_id, $post_id, $meta_key ); |
|
537 } |
|
538 } |
|
539 |
|
540 /** |
|
541 * Copy post meta for the given key from one post to another. |
|
542 * |
|
543 * @since 6.4.0 |
|
544 * |
|
545 * @param int $source_post_id Post ID to copy meta value(s) from. |
|
546 * @param int $target_post_id Post ID to copy meta value(s) to. |
|
547 * @param string $meta_key Meta key to copy. |
|
548 */ |
|
549 function _wp_copy_post_meta( $source_post_id, $target_post_id, $meta_key ) { |
|
550 |
|
551 foreach ( get_post_meta( $source_post_id, $meta_key ) as $meta_value ) { |
|
552 /** |
|
553 * We use add_metadata() function vs add_post_meta() here |
|
554 * to allow for a revision post target OR regular post. |
|
555 */ |
|
556 add_metadata( 'post', $target_post_id, $meta_key, wp_slash( $meta_value ) ); |
|
557 } |
|
558 } |
|
559 |
|
560 /** |
|
561 * Determine which post meta fields should be revisioned. |
|
562 * |
|
563 * @since 6.4.0 |
|
564 * |
|
565 * @param string $post_type The post type being revisioned. |
|
566 * @return array An array of meta keys to be revisioned. |
|
567 */ |
|
568 function wp_post_revision_meta_keys( $post_type ) { |
|
569 $registered_meta = array_merge( |
|
570 get_registered_meta_keys( 'post' ), |
|
571 get_registered_meta_keys( 'post', $post_type ) |
|
572 ); |
|
573 |
|
574 $wp_revisioned_meta_keys = array(); |
|
575 |
|
576 foreach ( $registered_meta as $name => $args ) { |
|
577 if ( $args['revisions_enabled'] ) { |
|
578 $wp_revisioned_meta_keys[ $name ] = true; |
|
579 } |
|
580 } |
|
581 |
|
582 $wp_revisioned_meta_keys = array_keys( $wp_revisioned_meta_keys ); |
|
583 |
|
584 /** |
|
585 * Filter the list of post meta keys to be revisioned. |
|
586 * |
|
587 * @since 6.4.0 |
|
588 * |
|
589 * @param array $keys An array of meta fields to be revisioned. |
|
590 * @param string $post_type The post type being revisioned. |
|
591 */ |
|
592 return apply_filters( 'wp_post_revision_meta_keys', $wp_revisioned_meta_keys, $post_type ); |
|
593 } |
|
594 |
|
595 /** |
|
596 * Check whether revisioned post meta fields have changed. |
|
597 * |
|
598 * @since 6.4.0 |
|
599 * |
|
600 * @param bool $post_has_changed Whether the post has changed. |
|
601 * @param WP_Post $last_revision The last revision post object. |
|
602 * @param WP_Post $post The post object. |
|
603 * @return bool Whether the post has changed. |
|
604 */ |
|
605 function wp_check_revisioned_meta_fields_have_changed( $post_has_changed, WP_Post $last_revision, WP_Post $post ) { |
|
606 foreach ( wp_post_revision_meta_keys( $post->post_type ) as $meta_key ) { |
|
607 if ( get_post_meta( $post->ID, $meta_key ) !== get_post_meta( $last_revision->ID, $meta_key ) ) { |
|
608 $post_has_changed = true; |
|
609 break; |
|
610 } |
|
611 } |
|
612 return $post_has_changed; |
|
613 } |
|
614 |
|
615 /** |
443 * Deletes a revision. |
616 * Deletes a revision. |
444 * |
617 * |
445 * Deletes the row from the posts table corresponding to the specified revision. |
618 * Deletes the row from the posts table corresponding to the specified revision. |
446 * |
619 * |
447 * @since 2.6.0 |
620 * @since 2.6.0 |
448 * |
621 * |
449 * @param int|WP_Post $revision_id Revision ID or revision object. |
622 * @param int|WP_Post $revision Revision ID or revision object. |
450 * @return WP_Post|false|null Null or false if error, deleted post object if success. |
623 * @return WP_Post|false|null Null or false if error, deleted post object if success. |
451 */ |
624 */ |
452 function wp_delete_post_revision( $revision_id ) { |
625 function wp_delete_post_revision( $revision ) { |
453 $revision = wp_get_post_revision( $revision_id ); |
626 $revision = wp_get_post_revision( $revision ); |
|
627 |
454 if ( ! $revision ) { |
628 if ( ! $revision ) { |
455 return $revision; |
629 return $revision; |
456 } |
630 } |
457 |
631 |
458 $delete = wp_delete_post( $revision->ID ); |
632 $delete = wp_delete_post( $revision->ID ); |
|
633 |
459 if ( $delete ) { |
634 if ( $delete ) { |
460 /** |
635 /** |
461 * Fires once a post revision has been deleted. |
636 * Fires once a post revision has been deleted. |
462 * |
637 * |
463 * @since 2.6.0 |
638 * @since 2.6.0 |
476 * |
651 * |
477 * @since 2.6.0 |
652 * @since 2.6.0 |
478 * |
653 * |
479 * @see get_children() |
654 * @see get_children() |
480 * |
655 * |
481 * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global `$post`. |
656 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`. |
482 * @param array|null $args Optional. Arguments for retrieving post revisions. Default null. |
657 * @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. |
658 * @return WP_Post[]|int[] Array of revision objects or IDs, or an empty array if none. |
484 */ |
659 */ |
485 function wp_get_post_revisions( $post_id = 0, $args = null ) { |
660 function wp_get_post_revisions( $post = 0, $args = null ) { |
486 $post = get_post( $post_id ); |
661 $post = get_post( $post ); |
|
662 |
487 if ( ! $post || empty( $post->ID ) ) { |
663 if ( ! $post || empty( $post->ID ) ) { |
488 return array(); |
664 return array(); |
489 } |
665 } |
490 |
666 |
491 $defaults = array( |
667 $defaults = array( |
507 'post_status' => 'inherit', |
683 'post_status' => 'inherit', |
508 ) |
684 ) |
509 ); |
685 ); |
510 |
686 |
511 $revisions = get_children( $args ); |
687 $revisions = get_children( $args ); |
|
688 |
512 if ( ! $revisions ) { |
689 if ( ! $revisions ) { |
513 return array(); |
690 return array(); |
514 } |
691 } |
515 |
692 |
516 return $revisions; |
693 return $revisions; |
517 } |
694 } |
518 |
695 |
519 /** |
696 /** |
|
697 * Returns the latest revision ID and count of revisions for a post. |
|
698 * |
|
699 * @since 6.1.0 |
|
700 * |
|
701 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
|
702 * @return array|WP_Error { |
|
703 * Returns associative array with latest revision ID and total count, |
|
704 * or a WP_Error if the post does not exist or revisions are not enabled. |
|
705 * |
|
706 * @type int $latest_id The latest revision post ID or 0 if no revisions exist. |
|
707 * @type int $count The total count of revisions for the given post. |
|
708 * } |
|
709 */ |
|
710 function wp_get_latest_revision_id_and_total_count( $post = 0 ) { |
|
711 $post = get_post( $post ); |
|
712 |
|
713 if ( ! $post ) { |
|
714 return new WP_Error( 'invalid_post', __( 'Invalid post.' ) ); |
|
715 } |
|
716 |
|
717 if ( ! wp_revisions_enabled( $post ) ) { |
|
718 return new WP_Error( 'revisions_not_enabled', __( 'Revisions not enabled.' ) ); |
|
719 } |
|
720 |
|
721 $args = array( |
|
722 'post_parent' => $post->ID, |
|
723 'fields' => 'ids', |
|
724 'post_type' => 'revision', |
|
725 'post_status' => 'inherit', |
|
726 'order' => 'DESC', |
|
727 'orderby' => 'date ID', |
|
728 'posts_per_page' => 1, |
|
729 'ignore_sticky_posts' => true, |
|
730 ); |
|
731 |
|
732 $revision_query = new WP_Query(); |
|
733 $revisions = $revision_query->query( $args ); |
|
734 |
|
735 if ( ! $revisions ) { |
|
736 return array( |
|
737 'latest_id' => 0, |
|
738 'count' => 0, |
|
739 ); |
|
740 } |
|
741 |
|
742 return array( |
|
743 'latest_id' => $revisions[0], |
|
744 'count' => $revision_query->found_posts, |
|
745 ); |
|
746 } |
|
747 |
|
748 /** |
520 * Returns the url for viewing and potentially restoring revisions of a given post. |
749 * Returns the url for viewing and potentially restoring revisions of a given post. |
521 * |
750 * |
522 * @since 5.9.0 |
751 * @since 5.9.0 |
523 * |
752 * |
524 * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global `$post`. |
753 * @param int|WP_Post $post 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. |
754 * @return string|null The URL for editing revisions on the given post, otherwise null. |
526 */ |
755 */ |
527 function wp_get_post_revisions_url( $post_id = 0 ) { |
756 function wp_get_post_revisions_url( $post = 0 ) { |
528 $post = get_post( $post_id ); |
757 $post = get_post( $post ); |
529 |
758 |
530 if ( ! $post instanceof WP_Post ) { |
759 if ( ! $post instanceof WP_Post ) { |
531 return null; |
760 return null; |
532 } |
761 } |
533 |
762 |
538 |
767 |
539 if ( ! wp_revisions_enabled( $post ) ) { |
768 if ( ! wp_revisions_enabled( $post ) ) { |
540 return null; |
769 return null; |
541 } |
770 } |
542 |
771 |
543 $revisions = wp_get_post_revisions( $post->ID, array( 'posts_per_page' => 1 ) ); |
772 $revisions = wp_get_latest_revision_id_and_total_count( $post->ID ); |
544 |
773 |
545 if ( 0 === count( $revisions ) ) { |
774 if ( is_wp_error( $revisions ) || 0 === $revisions['count'] ) { |
546 return null; |
775 return null; |
547 } |
776 } |
548 |
777 |
549 $revision = reset( $revisions ); |
778 return get_edit_post_link( $revisions['latest_id'] ); |
550 return get_edit_post_link( $revision ); |
779 } |
551 } |
780 |
552 |
781 /** |
553 /** |
782 * Determines whether revisions are enabled for a given post. |
554 * Determine if revisions are enabled for a given post. |
|
555 * |
783 * |
556 * @since 3.6.0 |
784 * @since 3.6.0 |
557 * |
785 * |
558 * @param WP_Post $post The post object. |
786 * @param WP_Post $post The post object. |
559 * @return bool True if number of revisions to keep isn't zero, false otherwise. |
787 * @return bool True if number of revisions to keep isn't zero, false otherwise. |
682 * @param string $taxonomy |
911 * @param string $taxonomy |
683 * @return array |
912 * @return array |
684 */ |
913 */ |
685 function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { |
914 function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { |
686 $post = get_post(); |
915 $post = get_post(); |
|
916 |
687 if ( ! $post ) { |
917 if ( ! $post ) { |
688 return $terms; |
918 return $terms; |
689 } |
919 } |
690 |
920 |
691 if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id |
921 if ( empty( $_REQUEST['post_format'] ) || $post->ID !== $post_id |
692 || 'post_format' !== $taxonomy || 'revision' === $post->post_type |
922 || 'post_format' !== $taxonomy || 'revision' === $post->post_type |
693 ) { |
923 ) { |
694 return $terms; |
924 return $terms; |
695 } |
925 } |
696 |
926 |
697 if ( 'standard' === $_REQUEST['post_format'] ) { |
927 if ( 'standard' === $_REQUEST['post_format'] ) { |
698 $terms = array(); |
928 $terms = array(); |
699 } else { |
929 } else { |
700 $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ); |
930 $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ); |
|
931 |
701 if ( $term ) { |
932 if ( $term ) { |
702 $terms = array( $term ); // Can only have one post format. |
933 $terms = array( $term ); // Can only have one post format. |
703 } |
934 } |
704 } |
935 } |
705 |
936 |
717 * @param string $meta_key Meta key. |
948 * @param string $meta_key Meta key. |
718 * @return null|array The default return value or the post thumbnail meta array. |
949 * @return null|array The default return value or the post thumbnail meta array. |
719 */ |
950 */ |
720 function _wp_preview_post_thumbnail_filter( $value, $post_id, $meta_key ) { |
951 function _wp_preview_post_thumbnail_filter( $value, $post_id, $meta_key ) { |
721 $post = get_post(); |
952 $post = get_post(); |
|
953 |
722 if ( ! $post ) { |
954 if ( ! $post ) { |
723 return $value; |
955 return $value; |
724 } |
956 } |
725 |
957 |
726 if ( empty( $_REQUEST['_thumbnail_id'] ) || |
958 if ( empty( $_REQUEST['_thumbnail_id'] ) || empty( $_REQUEST['preview_id'] ) |
727 empty( $_REQUEST['preview_id'] ) || |
959 || $post->ID !== $post_id || $post_id !== (int) $_REQUEST['preview_id'] |
728 $post->ID != $post_id || |
960 || '_thumbnail_id' !== $meta_key || 'revision' === $post->post_type |
729 '_thumbnail_id' !== $meta_key || |
961 ) { |
730 'revision' === $post->post_type || |
|
731 $post_id != $_REQUEST['preview_id'] ) { |
|
732 |
|
733 return $value; |
962 return $value; |
734 } |
963 } |
735 |
964 |
736 $thumbnail_id = (int) $_REQUEST['_thumbnail_id']; |
965 $thumbnail_id = (int) $_REQUEST['_thumbnail_id']; |
|
966 |
737 if ( $thumbnail_id <= 0 ) { |
967 if ( $thumbnail_id <= 0 ) { |
738 return ''; |
968 return ''; |
739 } |
969 } |
740 |
970 |
741 return (string) $thumbnail_id; |
971 return (string) $thumbnail_id; |
763 |
993 |
764 return 0; |
994 return 0; |
765 } |
995 } |
766 |
996 |
767 /** |
997 /** |
768 * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1 |
998 * Upgrades the revisions author, adds the current post as a revision and sets the revisions version to 1. |
769 * |
999 * |
770 * @since 3.6.0 |
1000 * @since 3.6.0 |
771 * @access private |
1001 * @access private |
772 * |
1002 * |
773 * @global wpdb $wpdb WordPress database abstraction object. |
1003 * @global wpdb $wpdb WordPress database abstraction object. |
774 * |
1004 * |
775 * @param WP_Post $post Post object |
1005 * @param WP_Post $post Post object. |
776 * @param array $revisions Current revisions of the post |
1006 * @param array $revisions Current revisions of the post. |
777 * @return bool true if the revisions were upgraded, false if problems |
1007 * @return bool true if the revisions were upgraded, false if problems. |
778 */ |
1008 */ |
779 function _wp_upgrade_revisions_of_post( $post, $revisions ) { |
1009 function _wp_upgrade_revisions_of_post( $post, $revisions ) { |
780 global $wpdb; |
1010 global $wpdb; |
781 |
1011 |
782 // Add post option exclusively. |
1012 // Add post option exclusively. |
783 $lock = "revision-upgrade-{$post->ID}"; |
1013 $lock = "revision-upgrade-{$post->ID}"; |
784 $now = time(); |
1014 $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 ) ); |
1015 $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'off') /* LOCK */", $lock, $now ) ); |
|
1016 |
786 if ( ! $result ) { |
1017 if ( ! $result ) { |
787 // If we couldn't get a lock, see how old the previous lock is. |
1018 // If we couldn't get a lock, see how old the previous lock is. |
788 $locked = get_option( $lock ); |
1019 $locked = get_option( $lock ); |
|
1020 |
789 if ( ! $locked ) { |
1021 if ( ! $locked ) { |
790 // Can't write to the lock, and can't read the lock. |
1022 /* |
791 // Something broken has happened. |
1023 * Can't write to the lock, and can't read the lock. |
|
1024 * Something broken has happened. |
|
1025 */ |
792 return false; |
1026 return false; |
793 } |
1027 } |
794 |
1028 |
795 if ( $locked > $now - 3600 ) { |
1029 if ( $locked > $now - HOUR_IN_SECONDS ) { |
796 // Lock is not too old: some other process may be upgrading this post. Bail. |
1030 // Lock is not too old: some other process may be upgrading this post. Bail. |
797 return false; |
1031 return false; |
798 } |
1032 } |
799 |
1033 |
800 // Lock is too old - update it (below) and continue. |
1034 // Lock is too old - update it (below) and continue. |
858 wp_save_post_revision( $post->ID ); |
1094 wp_save_post_revision( $post->ID ); |
859 } |
1095 } |
860 |
1096 |
861 return true; |
1097 return true; |
862 } |
1098 } |
|
1099 |
|
1100 /** |
|
1101 * Filters preview post meta retrieval to get values from the autosave. |
|
1102 * |
|
1103 * Filters revisioned meta keys only. |
|
1104 * |
|
1105 * @since 6.4.0 |
|
1106 * |
|
1107 * @param mixed $value Meta value to filter. |
|
1108 * @param int $object_id Object ID. |
|
1109 * @param string $meta_key Meta key to filter a value for. |
|
1110 * @param bool $single Whether to return a single value. Default false. |
|
1111 * @return mixed Original meta value if the meta key isn't revisioned, the object doesn't exist, |
|
1112 * the post type is a revision or the post ID doesn't match the object ID. |
|
1113 * Otherwise, the revisioned meta value is returned for the preview. |
|
1114 */ |
|
1115 function _wp_preview_meta_filter( $value, $object_id, $meta_key, $single ) { |
|
1116 |
|
1117 $post = get_post(); |
|
1118 if ( |
|
1119 empty( $post ) || |
|
1120 $post->ID !== $object_id || |
|
1121 ! in_array( $meta_key, wp_post_revision_meta_keys( $post->post_type ), true ) || |
|
1122 'revision' === $post->post_type |
|
1123 ) { |
|
1124 return $value; |
|
1125 } |
|
1126 |
|
1127 $preview = wp_get_post_autosave( $post->ID ); |
|
1128 if ( false === $preview ) { |
|
1129 return $value; |
|
1130 } |
|
1131 |
|
1132 return get_post_meta( $preview->ID, $meta_key, $single ); |
|
1133 } |