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
|
|
|
* @since 2.6.0 |
13
|
|
|
* @since 4.5.0 A `WP_Post` object can now be passed to the `$post` parameter. |
14
|
|
|
* @since 4.5.0 The optional `$autosave` parameter was deprecated and renamed to `$deprecated`. |
15
|
|
|
* @access private |
16
|
|
|
* |
17
|
|
|
* @staticvar array $fields |
18
|
|
|
* |
19
|
|
|
* @param array|WP_Post $post Optional. A post array or a WP_Post object being processed |
20
|
|
|
* for insertion as a post revision. Default empty array. |
21
|
|
|
* @param bool $deprecated Not used. |
22
|
|
|
* @return array Array of fields that can be versioned. |
23
|
|
|
*/ |
24
|
|
|
function _wp_post_revision_fields( $post = array(), $deprecated = false ) { |
25
|
|
|
static $fields = null; |
26
|
|
|
|
27
|
|
|
if ( ! is_array( $post ) ) { |
28
|
|
|
$post = get_post( $post, ARRAY_A ); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
if ( is_null( $fields ) ) { |
32
|
|
|
// Allow these to be versioned |
33
|
|
|
$fields = array( |
34
|
|
|
'post_title' => __( 'Title' ), |
35
|
|
|
'post_content' => __( 'Content' ), |
36
|
|
|
'post_excerpt' => __( 'Excerpt' ), |
37
|
|
|
); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Filters the list of fields saved in post revisions. |
42
|
|
|
* |
43
|
|
|
* Included by default: 'post_title', 'post_content' and 'post_excerpt'. |
44
|
|
|
* |
45
|
|
|
* Disallowed fields: 'ID', 'post_name', 'post_parent', 'post_date', |
46
|
|
|
* 'post_date_gmt', 'post_status', 'post_type', 'comment_count', |
47
|
|
|
* and 'post_author'. |
48
|
|
|
* |
49
|
|
|
* @since 2.6.0 |
50
|
|
|
* @since 4.5.0 The `$post` parameter was added. |
51
|
|
|
* |
52
|
|
|
* @param array $fields List of fields to revision. Contains 'post_title', |
53
|
|
|
* 'post_content', and 'post_excerpt' by default. |
54
|
|
|
* @param array $post A post array being processed for insertion as a post revision. |
55
|
|
|
*/ |
56
|
|
|
$fields = apply_filters( '_wp_post_revision_fields', $fields, $post ); |
57
|
|
|
|
58
|
|
|
// WP uses these internally either in versioning or elsewhere - they cannot be versioned |
59
|
|
|
foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect ) { |
60
|
|
|
unset( $fields[ $protect ] ); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
|
64
|
|
|
return $fields; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Returns a post array ready to be inserted into the posts table as a post revision. |
69
|
|
|
* |
70
|
|
|
* @since 4.5.0 |
71
|
|
|
* @access private |
72
|
|
|
* |
73
|
|
|
* @param array|WP_Post $post Optional. A post array or a WP_Post object to be processed |
74
|
|
|
* for insertion as a post revision. Default empty array. |
75
|
|
|
* @param bool $autosave Optional. Is the revision an autosave? Default false. |
76
|
|
|
* @return array Post array ready to be inserted as a post revision. |
77
|
|
|
*/ |
78
|
|
|
function _wp_post_revision_data( $post = array(), $autosave = false ) { |
79
|
|
|
if ( ! is_array( $post ) ) { |
80
|
|
|
$post = get_post( $post, ARRAY_A ); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
$fields = _wp_post_revision_fields( $post ); |
|
|
|
|
84
|
|
|
|
85
|
|
|
$revision_data = array(); |
86
|
|
|
|
87
|
|
|
foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field ) { |
88
|
|
|
$revision_data[ $field ] = $post[ $field ]; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
$revision_data['post_parent'] = $post['ID']; |
92
|
|
|
$revision_data['post_status'] = 'inherit'; |
93
|
|
|
$revision_data['post_type'] = 'revision'; |
94
|
|
|
$revision_data['post_name'] = $autosave ? "$post[ID]-autosave-v1" : "$post[ID]-revision-v1"; // "1" is the revisioning system version |
95
|
|
|
$revision_data['post_date'] = isset( $post['post_modified'] ) ? $post['post_modified'] : ''; |
96
|
|
|
$revision_data['post_date_gmt'] = isset( $post['post_modified_gmt'] ) ? $post['post_modified_gmt'] : ''; |
97
|
|
|
|
98
|
|
|
return $revision_data; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Creates a revision for the current version of a post. |
103
|
|
|
* |
104
|
|
|
* Typically used immediately after a post update, as every update is a revision, |
105
|
|
|
* and the most recent revision always matches the current post. |
106
|
|
|
* |
107
|
|
|
* @since 2.6.0 |
108
|
|
|
* |
109
|
|
|
* @param int $post_id The ID of the post to save as a revision. |
110
|
|
|
* @return int|WP_Error|void Void or 0 if error, new revision ID, if success. |
111
|
|
|
*/ |
112
|
|
|
function wp_save_post_revision( $post_id ) { |
113
|
|
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) |
114
|
|
|
return; |
115
|
|
|
|
116
|
|
|
if ( ! $post = get_post( $post_id ) ) |
117
|
|
|
return; |
118
|
|
|
|
119
|
|
|
if ( ! post_type_supports( $post->post_type, 'revisions' ) ) |
120
|
|
|
return; |
121
|
|
|
|
122
|
|
|
if ( 'auto-draft' == $post->post_status ) |
123
|
|
|
return; |
124
|
|
|
|
125
|
|
|
if ( ! wp_revisions_enabled( $post ) ) |
|
|
|
|
126
|
|
|
return; |
127
|
|
|
|
128
|
|
|
// Compare the proposed update with the last stored revision verifying that |
129
|
|
|
// they are different, unless a plugin tells us to always save regardless. |
130
|
|
|
// If no previous revisions, save one |
131
|
|
|
if ( $revisions = wp_get_post_revisions( $post_id ) ) { |
132
|
|
|
// grab the last revision, but not an autosave |
133
|
|
|
foreach ( $revisions as $revision ) { |
134
|
|
|
if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) { |
135
|
|
|
$last_revision = $revision; |
136
|
|
|
break; |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Filters whether the post has changed since the last revision. |
142
|
|
|
* |
143
|
|
|
* By default a revision is saved only if one of the revisioned fields has changed. |
144
|
|
|
* This filter can override that so a revision is saved even if nothing has changed. |
145
|
|
|
* |
146
|
|
|
* @since 3.6.0 |
147
|
|
|
* |
148
|
|
|
* @param bool $check_for_changes Whether to check for changes before saving a new revision. |
149
|
|
|
* Default true. |
150
|
|
|
* @param WP_Post $last_revision The last revision post object. |
151
|
|
|
* @param WP_Post $post The post object. |
152
|
|
|
* |
153
|
|
|
*/ |
154
|
|
|
if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', $check_for_changes = true, $last_revision, $post ) ) { |
155
|
|
|
$post_has_changed = false; |
156
|
|
|
|
157
|
|
|
foreach ( array_keys( _wp_post_revision_fields( $post ) ) as $field ) { |
158
|
|
|
if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) { |
159
|
|
|
$post_has_changed = true; |
160
|
|
|
break; |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Filters whether a post has changed. |
166
|
|
|
* |
167
|
|
|
* By default a revision is saved only if one of the revisioned fields has changed. |
168
|
|
|
* This filter allows for additional checks to determine if there were changes. |
169
|
|
|
* |
170
|
|
|
* @since 4.1.0 |
171
|
|
|
* |
172
|
|
|
* @param bool $post_has_changed Whether the post has changed. |
173
|
|
|
* @param WP_Post $last_revision The last revision post object. |
174
|
|
|
* @param WP_Post $post The post object. |
175
|
|
|
* |
176
|
|
|
*/ |
177
|
|
|
$post_has_changed = (bool) apply_filters( 'wp_save_post_revision_post_has_changed', $post_has_changed, $last_revision, $post ); |
178
|
|
|
|
179
|
|
|
//don't save revision if post unchanged |
180
|
|
|
if ( ! $post_has_changed ) { |
181
|
|
|
return; |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
$return = _wp_put_post_revision( $post ); |
187
|
|
|
|
188
|
|
|
// If a limit for the number of revisions to keep has been set, |
189
|
|
|
// delete the oldest ones. |
190
|
|
|
$revisions_to_keep = wp_revisions_to_keep( $post ); |
|
|
|
|
191
|
|
|
|
192
|
|
|
if ( $revisions_to_keep < 0 ) |
193
|
|
|
return $return; |
194
|
|
|
|
195
|
|
|
$revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) ); |
196
|
|
|
|
197
|
|
|
$delete = count($revisions) - $revisions_to_keep; |
198
|
|
|
|
199
|
|
|
if ( $delete < 1 ) |
200
|
|
|
return $return; |
201
|
|
|
|
202
|
|
|
$revisions = array_slice( $revisions, 0, $delete ); |
203
|
|
|
|
204
|
|
|
for ( $i = 0; isset( $revisions[$i] ); $i++ ) { |
205
|
|
|
if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) ) |
206
|
|
|
continue; |
207
|
|
|
|
208
|
|
|
wp_delete_post_revision( $revisions[ $i ]->ID ); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
return $return; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Retrieve the autosaved data of the specified post. |
216
|
|
|
* |
217
|
|
|
* Returns a post object containing the information that was autosaved for the |
218
|
|
|
* specified post. If the optional $user_id is passed, returns the autosave for that user |
219
|
|
|
* otherwise returns the latest autosave. |
220
|
|
|
* |
221
|
|
|
* @since 2.6.0 |
222
|
|
|
* |
223
|
|
|
* @param int $post_id The post ID. |
224
|
|
|
* @param int $user_id Optional The post author ID. |
225
|
|
|
* @return WP_Post|false The autosaved data or false on failure or when no autosave exists. |
226
|
|
|
*/ |
227
|
|
|
function wp_get_post_autosave( $post_id, $user_id = 0 ) { |
228
|
|
|
$revisions = wp_get_post_revisions( $post_id, array( 'check_enabled' => false ) ); |
229
|
|
|
|
230
|
|
|
foreach ( $revisions as $revision ) { |
231
|
|
|
if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) { |
232
|
|
|
if ( $user_id && $user_id != $revision->post_author ) |
233
|
|
|
continue; |
234
|
|
|
|
235
|
|
|
return $revision; |
236
|
|
|
} |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
return false; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Determines if the specified post is a revision. |
244
|
|
|
* |
245
|
|
|
* @since 2.6.0 |
246
|
|
|
* |
247
|
|
|
* @param int|WP_Post $post Post ID or post object. |
248
|
|
|
* @return false|int False if not a revision, ID of revision's parent otherwise. |
249
|
|
|
*/ |
250
|
|
|
function wp_is_post_revision( $post ) { |
251
|
|
|
if ( !$post = wp_get_post_revision( $post ) ) |
252
|
|
|
return false; |
253
|
|
|
|
254
|
|
|
return (int) $post->post_parent; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Determines if the specified post is an autosave. |
259
|
|
|
* |
260
|
|
|
* @since 2.6.0 |
261
|
|
|
* |
262
|
|
|
* @param int|WP_Post $post Post ID or post object. |
263
|
|
|
* @return false|int False if not a revision, ID of autosave's parent otherwise |
264
|
|
|
*/ |
265
|
|
|
function wp_is_post_autosave( $post ) { |
266
|
|
|
if ( !$post = wp_get_post_revision( $post ) ) |
267
|
|
|
return false; |
268
|
|
|
|
269
|
|
|
if ( false !== strpos( $post->post_name, "{$post->post_parent}-autosave" ) ) |
270
|
|
|
return (int) $post->post_parent; |
271
|
|
|
|
272
|
|
|
return false; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Inserts post data into the posts table as a post revision. |
277
|
|
|
* |
278
|
|
|
* @since 2.6.0 |
279
|
|
|
* @access private |
280
|
|
|
* |
281
|
|
|
* @param int|WP_Post|array|null $post Post ID, post object OR post array. |
282
|
|
|
* @param bool $autosave Optional. Is the revision an autosave? |
283
|
|
|
* @return int|WP_Error WP_Error or 0 if error, new revision ID if success. |
284
|
|
|
*/ |
285
|
|
|
function _wp_put_post_revision( $post = null, $autosave = false ) { |
286
|
|
|
if ( is_object($post) ) |
287
|
|
|
$post = get_object_vars( $post ); |
288
|
|
|
elseif ( !is_array($post) ) |
289
|
|
|
$post = get_post($post, ARRAY_A); |
290
|
|
|
|
291
|
|
|
if ( ! $post || empty($post['ID']) ) |
292
|
|
|
return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) ); |
293
|
|
|
|
294
|
|
|
if ( isset($post['post_type']) && 'revision' == $post['post_type'] ) |
295
|
|
|
return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); |
296
|
|
|
|
297
|
|
|
$post = _wp_post_revision_data( $post, $autosave ); |
298
|
|
|
$post = wp_slash($post); //since data is from db |
299
|
|
|
|
300
|
|
|
$revision_id = wp_insert_post( $post ); |
|
|
|
|
301
|
|
|
if ( is_wp_error($revision_id) ) |
302
|
|
|
return $revision_id; |
303
|
|
|
|
304
|
|
|
if ( $revision_id ) { |
305
|
|
|
/** |
306
|
|
|
* Fires once a revision has been saved. |
307
|
|
|
* |
308
|
|
|
* @since 2.6.0 |
309
|
|
|
* |
310
|
|
|
* @param int $revision_id Post revision ID. |
311
|
|
|
*/ |
312
|
|
|
do_action( '_wp_put_post_revision', $revision_id ); |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
return $revision_id; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* Gets a post revision. |
320
|
|
|
* |
321
|
|
|
* @since 2.6.0 |
322
|
|
|
* |
323
|
|
|
* @param int|WP_Post $post The post ID or object. |
324
|
|
|
* @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. |
325
|
|
|
* @param string $filter Optional sanitation filter. See sanitize_post(). |
326
|
|
|
* @return WP_Post|array|null Null if error or post object if success. |
327
|
|
|
*/ |
328
|
|
|
function wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') { |
329
|
|
|
if ( !$revision = get_post( $post, OBJECT, $filter ) ) |
330
|
|
|
return $revision; |
331
|
|
|
if ( 'revision' !== $revision->post_type ) |
332
|
|
|
return null; |
333
|
|
|
|
334
|
|
|
if ( $output == OBJECT ) { |
335
|
|
|
return $revision; |
336
|
|
|
} elseif ( $output == ARRAY_A ) { |
337
|
|
|
$_revision = get_object_vars($revision); |
338
|
|
|
return $_revision; |
339
|
|
|
} elseif ( $output == ARRAY_N ) { |
340
|
|
|
$_revision = array_values(get_object_vars($revision)); |
341
|
|
|
return $_revision; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
return $revision; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* Restores a post to the specified revision. |
349
|
|
|
* |
350
|
|
|
* Can restore a past revision using all fields of the post revision, or only selected fields. |
351
|
|
|
* |
352
|
|
|
* @since 2.6.0 |
353
|
|
|
* |
354
|
|
|
* @param int|WP_Post $revision_id Revision ID or revision object. |
355
|
|
|
* @param array $fields Optional. What fields to restore from. Defaults to all. |
356
|
|
|
* @return int|false|null Null if error, false if no fields to restore, (int) post ID if success. |
357
|
|
|
*/ |
358
|
|
|
function wp_restore_post_revision( $revision_id, $fields = null ) { |
359
|
|
|
if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) ) |
360
|
|
|
return $revision; |
361
|
|
|
|
362
|
|
|
if ( !is_array( $fields ) ) |
363
|
|
|
$fields = array_keys( _wp_post_revision_fields( $revision ) ); |
364
|
|
|
|
365
|
|
|
$update = array(); |
366
|
|
|
foreach ( array_intersect( array_keys( $revision ), $fields ) as $field ) { |
367
|
|
|
$update[$field] = $revision[$field]; |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
if ( !$update ) |
371
|
|
|
return false; |
372
|
|
|
|
373
|
|
|
$update['ID'] = $revision['post_parent']; |
374
|
|
|
|
375
|
|
|
$update = wp_slash( $update ); //since data is from db |
376
|
|
|
|
377
|
|
|
$post_id = wp_update_post( $update ); |
|
|
|
|
378
|
|
|
if ( ! $post_id || is_wp_error( $post_id ) ) |
379
|
|
|
return $post_id; |
380
|
|
|
|
381
|
|
|
// Update last edit user |
382
|
|
|
update_post_meta( $post_id, '_edit_last', get_current_user_id() ); |
|
|
|
|
383
|
|
|
|
384
|
|
|
/** |
385
|
|
|
* Fires after a post revision has been restored. |
386
|
|
|
* |
387
|
|
|
* @since 2.6.0 |
388
|
|
|
* |
389
|
|
|
* @param int $post_id Post ID. |
390
|
|
|
* @param int $revision_id Post revision ID. |
391
|
|
|
*/ |
392
|
|
|
do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] ); |
393
|
|
|
|
394
|
|
|
return $post_id; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* Deletes a revision. |
399
|
|
|
* |
400
|
|
|
* Deletes the row from the posts table corresponding to the specified revision. |
401
|
|
|
* |
402
|
|
|
* @since 2.6.0 |
403
|
|
|
* |
404
|
|
|
* @param int|WP_Post $revision_id Revision ID or revision object. |
405
|
|
|
* @return array|false|WP_Post|WP_Error|null Null or WP_Error if error, deleted post if success. |
406
|
|
|
*/ |
407
|
|
|
function wp_delete_post_revision( $revision_id ) { |
408
|
|
|
if ( ! $revision = wp_get_post_revision( $revision_id ) ) { |
409
|
|
|
return $revision; |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
$delete = wp_delete_post( $revision->ID ); |
413
|
|
|
if ( $delete ) { |
414
|
|
|
/** |
415
|
|
|
* Fires once a post revision has been deleted. |
416
|
|
|
* |
417
|
|
|
* @since 2.6.0 |
418
|
|
|
* |
419
|
|
|
* @param int $revision_id Post revision ID. |
420
|
|
|
* @param object|array $revision Post revision object or array. |
421
|
|
|
*/ |
422
|
|
|
do_action( 'wp_delete_post_revision', $revision->ID, $revision ); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
return $delete; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* Returns all revisions of specified post. |
430
|
|
|
* |
431
|
|
|
* @since 2.6.0 |
432
|
|
|
* |
433
|
|
|
* @see get_children() |
434
|
|
|
* |
435
|
|
|
* @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global `$post`. |
436
|
|
|
* @param array|null $args Optional. Arguments for retrieving post revisions. Default null. |
437
|
|
|
* @return array An array of revisions, or an empty array if none. |
438
|
|
|
*/ |
439
|
|
|
function wp_get_post_revisions( $post_id = 0, $args = null ) { |
440
|
|
|
$post = get_post( $post_id ); |
441
|
|
|
if ( ! $post || empty( $post->ID ) ) |
442
|
|
|
return array(); |
443
|
|
|
|
444
|
|
|
$defaults = array( 'order' => 'DESC', 'orderby' => 'date ID', 'check_enabled' => true ); |
445
|
|
|
$args = wp_parse_args( $args, $defaults ); |
|
|
|
|
446
|
|
|
|
447
|
|
|
if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) ) |
|
|
|
|
448
|
|
|
return array(); |
449
|
|
|
|
450
|
|
|
$args = array_merge( $args, array( 'post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit' ) ); |
451
|
|
|
|
452
|
|
|
if ( ! $revisions = get_children( $args ) ) |
453
|
|
|
return array(); |
454
|
|
|
|
455
|
|
|
return $revisions; |
456
|
|
|
} |
457
|
|
|
|
458
|
|
|
/** |
459
|
|
|
* Determine if revisions are enabled for a given post. |
460
|
|
|
* |
461
|
|
|
* @since 3.6.0 |
462
|
|
|
* |
463
|
|
|
* @param WP_Post $post The post object. |
464
|
|
|
* @return bool True if number of revisions to keep isn't zero, false otherwise. |
465
|
|
|
*/ |
466
|
|
|
function wp_revisions_enabled( $post ) { |
467
|
|
|
return wp_revisions_to_keep( $post ) !== 0; |
468
|
|
|
} |
469
|
|
|
|
470
|
|
|
/** |
471
|
|
|
* Determine how many revisions to retain for a given post. |
472
|
|
|
* |
473
|
|
|
* By default, an infinite number of revisions are kept. |
474
|
|
|
* |
475
|
|
|
* The constant WP_POST_REVISIONS can be set in wp-config to specify the limit |
476
|
|
|
* of revisions to keep. |
477
|
|
|
* |
478
|
|
|
* @since 3.6.0 |
479
|
|
|
* |
480
|
|
|
* @param WP_Post $post The post object. |
481
|
|
|
* @return int The number of revisions to keep. |
482
|
|
|
*/ |
483
|
|
|
function wp_revisions_to_keep( $post ) { |
484
|
|
|
$num = WP_POST_REVISIONS; |
485
|
|
|
|
486
|
|
|
if ( true === $num ) |
487
|
|
|
$num = -1; |
488
|
|
|
else |
489
|
|
|
$num = intval( $num ); |
490
|
|
|
|
491
|
|
|
if ( ! post_type_supports( $post->post_type, 'revisions' ) ) |
492
|
|
|
$num = 0; |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* Filters the number of revisions to save for the given post. |
496
|
|
|
* |
497
|
|
|
* Overrides the value of WP_POST_REVISIONS. |
498
|
|
|
* |
499
|
|
|
* @since 3.6.0 |
500
|
|
|
* |
501
|
|
|
* @param int $num Number of revisions to store. |
502
|
|
|
* @param WP_Post $post Post object. |
503
|
|
|
*/ |
504
|
|
|
return (int) apply_filters( 'wp_revisions_to_keep', $num, $post ); |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
/** |
508
|
|
|
* Sets up the post object for preview based on the post autosave. |
509
|
|
|
* |
510
|
|
|
* @since 2.7.0 |
511
|
|
|
* @access private |
512
|
|
|
* |
513
|
|
|
* @param WP_Post $post |
514
|
|
|
* @return WP_Post|false |
515
|
|
|
*/ |
516
|
|
|
function _set_preview( $post ) { |
517
|
|
|
if ( ! is_object( $post ) ) { |
518
|
|
|
return $post; |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
$preview = wp_get_post_autosave( $post->ID ); |
522
|
|
|
if ( ! is_object( $preview ) ) { |
523
|
|
|
return $post; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
$preview = sanitize_post( $preview ); |
527
|
|
|
|
528
|
|
|
$post->post_content = $preview->post_content; |
529
|
|
|
$post->post_title = $preview->post_title; |
530
|
|
|
$post->post_excerpt = $preview->post_excerpt; |
531
|
|
|
|
532
|
|
|
add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 ); |
533
|
|
|
add_filter( 'get_post_metadata', '_wp_preview_post_thumbnail_filter', 10, 3 ); |
534
|
|
|
|
535
|
|
|
return $post; |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* Filters the latest content for preview from the post autosave. |
540
|
|
|
* |
541
|
|
|
* @since 2.7.0 |
542
|
|
|
* @access private |
543
|
|
|
*/ |
544
|
|
|
function _show_post_preview() { |
545
|
|
|
if ( isset($_GET['preview_id']) && isset($_GET['preview_nonce']) ) { |
546
|
|
|
$id = (int) $_GET['preview_id']; |
547
|
|
|
|
548
|
|
|
if ( false === wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) ) |
549
|
|
|
wp_die( __('Sorry, you are not allowed to preview drafts.') ); |
550
|
|
|
|
551
|
|
|
add_filter('the_preview', '_set_preview'); |
552
|
|
|
} |
553
|
|
|
} |
554
|
|
|
|
555
|
|
|
/** |
556
|
|
|
* Filters terms lookup to set the post format. |
557
|
|
|
* |
558
|
|
|
* @since 3.6.0 |
559
|
|
|
* @access private |
560
|
|
|
* |
561
|
|
|
* @param array $terms |
562
|
|
|
* @param int $post_id |
563
|
|
|
* @param string $taxonomy |
564
|
|
|
* @return array |
565
|
|
|
*/ |
566
|
|
|
function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) { |
567
|
|
|
if ( ! $post = get_post() ) |
568
|
|
|
return $terms; |
569
|
|
|
|
570
|
|
View Code Duplication |
if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id || 'post_format' != $taxonomy || 'revision' == $post->post_type ) |
571
|
|
|
return $terms; |
572
|
|
|
|
573
|
|
|
if ( 'standard' == $_REQUEST['post_format'] ) |
574
|
|
|
$terms = array(); |
575
|
|
|
elseif ( $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ) ) |
576
|
|
|
$terms = array( $term ); // Can only have one post format |
577
|
|
|
|
578
|
|
|
return $terms; |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
/** |
582
|
|
|
* Filters post thumbnail lookup to set the post thumbnail. |
583
|
|
|
* |
584
|
|
|
* @since 4.6.0 |
585
|
|
|
* @access private |
586
|
|
|
* |
587
|
|
|
* @param null|array|string $value The value to return - a single metadata value, or an array of values. |
588
|
|
|
* @param int $post_id Post ID. |
589
|
|
|
* @param string $meta_key Meta key. |
590
|
|
|
* @return null|array The default return value or the post thumbnail meta array. |
591
|
|
|
*/ |
592
|
|
|
function _wp_preview_post_thumbnail_filter( $value, $post_id, $meta_key ) { |
593
|
|
|
if ( ! $post = get_post() ) { |
594
|
|
|
return $value; |
595
|
|
|
} |
596
|
|
|
|
597
|
|
View Code Duplication |
if ( empty( $_REQUEST['_thumbnail_id'] ) || $post->ID != $post_id || '_thumbnail_id' != $meta_key || 'revision' == $post->post_type ) { |
598
|
|
|
return $value; |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
$thumbnail_id = intval( $_REQUEST['_thumbnail_id'] ); |
602
|
|
|
if ( $thumbnail_id <= 0 ) { |
603
|
|
|
return ''; |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
return strval( $thumbnail_id ); |
607
|
|
|
} |
608
|
|
|
|
609
|
|
|
/** |
610
|
|
|
* Gets the post revision version. |
611
|
|
|
* |
612
|
|
|
* @since 3.6.0 |
613
|
|
|
* @access private |
614
|
|
|
* |
615
|
|
|
* @param WP_Post $revision |
616
|
|
|
* @return int|false |
617
|
|
|
*/ |
618
|
|
|
function _wp_get_post_revision_version( $revision ) { |
619
|
|
|
if ( is_object( $revision ) ) |
620
|
|
|
$revision = get_object_vars( $revision ); |
621
|
|
|
elseif ( !is_array( $revision ) ) |
622
|
|
|
return false; |
623
|
|
|
|
624
|
|
|
if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) ) |
625
|
|
|
return (int) $matches[1]; |
626
|
|
|
|
627
|
|
|
return 0; |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
/** |
631
|
|
|
* Upgrade the revisions author, add the current post as a revision and set the revisions version to 1 |
632
|
|
|
* |
633
|
|
|
* @since 3.6.0 |
634
|
|
|
* @access private |
635
|
|
|
* |
636
|
|
|
* @global wpdb $wpdb WordPress database abstraction object. |
637
|
|
|
* |
638
|
|
|
* @param WP_Post $post Post object |
639
|
|
|
* @param array $revisions Current revisions of the post |
640
|
|
|
* @return bool true if the revisions were upgraded, false if problems |
641
|
|
|
*/ |
642
|
|
|
function _wp_upgrade_revisions_of_post( $post, $revisions ) { |
643
|
|
|
global $wpdb; |
644
|
|
|
|
645
|
|
|
// Add post option exclusively |
646
|
|
|
$lock = "revision-upgrade-{$post->ID}"; |
647
|
|
|
$now = time(); |
648
|
|
|
$result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) ); |
649
|
|
|
if ( ! $result ) { |
650
|
|
|
// If we couldn't get a lock, see how old the previous lock is |
651
|
|
|
$locked = get_option( $lock ); |
652
|
|
|
if ( ! $locked ) { |
653
|
|
|
// Can't write to the lock, and can't read the lock. |
654
|
|
|
// Something broken has happened |
655
|
|
|
return false; |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
if ( $locked > $now - 3600 ) { |
659
|
|
|
// Lock is not too old: some other process may be upgrading this post. Bail. |
660
|
|
|
return false; |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
// Lock is too old - update it (below) and continue |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
// If we could get a lock, re-"add" the option to fire all the correct filters. |
667
|
|
|
update_option( $lock, $now ); |
668
|
|
|
|
669
|
|
|
reset( $revisions ); |
670
|
|
|
$add_last = true; |
671
|
|
|
|
672
|
|
|
do { |
673
|
|
|
$this_revision = current( $revisions ); |
674
|
|
|
$prev_revision = next( $revisions ); |
675
|
|
|
|
676
|
|
|
$this_revision_version = _wp_get_post_revision_version( $this_revision ); |
677
|
|
|
|
678
|
|
|
// Something terrible happened |
679
|
|
|
if ( false === $this_revision_version ) |
680
|
|
|
continue; |
681
|
|
|
|
682
|
|
|
// 1 is the latest revision version, so we're already up to date. |
683
|
|
|
// No need to add a copy of the post as latest revision. |
684
|
|
|
if ( 0 < $this_revision_version ) { |
685
|
|
|
$add_last = false; |
686
|
|
|
continue; |
687
|
|
|
} |
688
|
|
|
|
689
|
|
|
// Always update the revision version |
690
|
|
|
$update = array( |
691
|
|
|
'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ), |
692
|
|
|
); |
693
|
|
|
|
694
|
|
|
// If this revision is the oldest revision of the post, i.e. no $prev_revision, |
695
|
|
|
// the correct post_author is probably $post->post_author, but that's only a good guess. |
696
|
|
|
// Update the revision version only and Leave the author as-is. |
697
|
|
|
if ( $prev_revision ) { |
698
|
|
|
$prev_revision_version = _wp_get_post_revision_version( $prev_revision ); |
699
|
|
|
|
700
|
|
|
// If the previous revision is already up to date, it no longer has the information we need :( |
701
|
|
|
if ( $prev_revision_version < 1 ) |
702
|
|
|
$update['post_author'] = $prev_revision->post_author; |
703
|
|
|
} |
704
|
|
|
|
705
|
|
|
// Upgrade this revision |
706
|
|
|
$result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) ); |
707
|
|
|
|
708
|
|
|
if ( $result ) |
709
|
|
|
wp_cache_delete( $this_revision->ID, 'posts' ); |
710
|
|
|
|
711
|
|
|
} while ( $prev_revision ); |
712
|
|
|
|
713
|
|
|
delete_option( $lock ); |
714
|
|
|
|
715
|
|
|
// Add a copy of the post as latest revision. |
716
|
|
|
if ( $add_last ) |
717
|
|
|
wp_save_post_revision( $post->ID ); |
718
|
|
|
|
719
|
|
|
return true; |
720
|
|
|
} |
721
|
|
|
|
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.