18 * |
18 * |
19 * @return array|bool Associative array of a post's revisioned fields and their diffs. |
19 * @return array|bool Associative array of a post's revisioned fields and their diffs. |
20 * Or, false on failure. |
20 * Or, false on failure. |
21 */ |
21 */ |
22 function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) { |
22 function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) { |
23 if ( ! $post = get_post( $post ) ) |
23 if ( ! $post = get_post( $post ) ) { |
24 return false; |
24 return false; |
|
25 } |
25 |
26 |
26 if ( $compare_from ) { |
27 if ( $compare_from ) { |
27 if ( ! $compare_from = get_post( $compare_from ) ) |
28 if ( ! $compare_from = get_post( $compare_from ) ) { |
28 return false; |
29 return false; |
|
30 } |
29 } else { |
31 } else { |
30 // If we're dealing with the first revision... |
32 // If we're dealing with the first revision... |
31 $compare_from = false; |
33 $compare_from = false; |
32 } |
34 } |
33 |
35 |
34 if ( ! $compare_to = get_post( $compare_to ) ) |
36 if ( ! $compare_to = get_post( $compare_to ) ) { |
35 return false; |
37 return false; |
|
38 } |
36 |
39 |
37 // If comparing revisions, make sure we're dealing with the right post parent. |
40 // If comparing revisions, make sure we're dealing with the right post parent. |
38 // The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves. |
41 // The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves. |
39 if ( $compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID ) |
42 if ( $compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID ) { |
40 return false; |
43 return false; |
41 if ( $compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID ) |
44 } |
|
45 if ( $compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID ) { |
42 return false; |
46 return false; |
|
47 } |
43 |
48 |
44 if ( $compare_from && strtotime( $compare_from->post_date_gmt ) > strtotime( $compare_to->post_date_gmt ) ) { |
49 if ( $compare_from && strtotime( $compare_from->post_date_gmt ) > strtotime( $compare_to->post_date_gmt ) ) { |
45 $temp = $compare_from; |
50 $temp = $compare_from; |
46 $compare_from = $compare_to; |
51 $compare_from = $compare_to; |
47 $compare_to = $temp; |
52 $compare_to = $temp; |
48 } |
53 } |
49 |
54 |
50 // Add default title if title field is empty |
55 // Add default title if title field is empty |
51 if ( $compare_from && empty( $compare_from->post_title ) ) |
56 if ( $compare_from && empty( $compare_from->post_title ) ) { |
52 $compare_from->post_title = __( '(no title)' ); |
57 $compare_from->post_title = __( '(no title)' ); |
53 if ( empty( $compare_to->post_title ) ) |
58 } |
|
59 if ( empty( $compare_to->post_title ) ) { |
54 $compare_to->post_title = __( '(no title)' ); |
60 $compare_to->post_title = __( '(no title)' ); |
|
61 } |
55 |
62 |
56 $return = array(); |
63 $return = array(); |
57 |
64 |
58 foreach ( _wp_post_revision_fields( $post ) as $field => $name ) { |
65 foreach ( _wp_post_revision_fields( $post ) as $field => $name ) { |
59 /** |
66 /** |
102 |
109 |
103 if ( ! $diff && 'post_title' === $field ) { |
110 if ( ! $diff && 'post_title' === $field ) { |
104 // It's a better user experience to still show the Title, even if it didn't change. |
111 // It's a better user experience to still show the Title, even if it didn't change. |
105 // No, you didn't see this. |
112 // No, you didn't see this. |
106 $diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>'; |
113 $diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>'; |
107 $diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td><td></td><td>' . esc_html( $compare_to->post_title ) . '</td>'; |
114 |
|
115 // In split screen mode, show the title before/after side by side. |
|
116 if ( true === $args['show_split_view'] ) { |
|
117 $diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td><td></td><td>' . esc_html( $compare_to->post_title ) . '</td>'; |
|
118 } else { |
|
119 $diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td>'; |
|
120 |
|
121 // In single column mode, only show the title once if unchanged. |
|
122 if ( $compare_from->post_title !== $compare_to->post_title ) { |
|
123 $diff .= '</tr><tr><td>' . esc_html( $compare_to->post_title ) . '</td>'; |
|
124 } |
|
125 } |
|
126 |
108 $diff .= '</tr></tbody>'; |
127 $diff .= '</tr></tbody>'; |
109 $diff .= '</table>'; |
128 $diff .= '</table>'; |
110 } |
129 } |
111 |
130 |
112 if ( $diff ) { |
131 if ( $diff ) { |
113 $return[] = array( |
132 $return[] = array( |
114 'id' => $field, |
133 'id' => $field, |
115 'name' => $name, |
134 'name' => $name, |
116 'diff' => $diff, |
135 'diff' => $diff, |
117 ); |
136 ); |
118 } |
137 } |
119 } |
138 } |
141 * @param int $from Optional. The revision ID to compare from. |
160 * @param int $from Optional. The revision ID to compare from. |
142 * |
161 * |
143 * @return array An associative array of revision data and related settings. |
162 * @return array An associative array of revision data and related settings. |
144 */ |
163 */ |
145 function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) { |
164 function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) { |
146 $post = get_post( $post ); |
165 $post = get_post( $post ); |
147 $authors = array(); |
166 $authors = array(); |
148 $now_gmt = time(); |
167 $now_gmt = time(); |
149 |
168 |
150 $revisions = wp_get_post_revisions( $post->ID, array( 'order' => 'ASC', 'check_enabled' => false ) ); |
169 $revisions = wp_get_post_revisions( |
|
170 $post->ID, |
|
171 array( |
|
172 'order' => 'ASC', |
|
173 'check_enabled' => false, |
|
174 ) |
|
175 ); |
151 // If revisions are disabled, we only want autosaves and the current post. |
176 // If revisions are disabled, we only want autosaves and the current post. |
152 if ( ! wp_revisions_enabled( $post ) ) { |
177 if ( ! wp_revisions_enabled( $post ) ) { |
153 foreach ( $revisions as $revision_id => $revision ) { |
178 foreach ( $revisions as $revision_id => $revision ) { |
154 if ( ! wp_is_post_autosave( $revision ) ) |
179 if ( ! wp_is_post_autosave( $revision ) ) { |
155 unset( $revisions[ $revision_id ] ); |
180 unset( $revisions[ $revision_id ] ); |
|
181 } |
156 } |
182 } |
157 $revisions = array( $post->ID => $post ) + $revisions; |
183 $revisions = array( $post->ID => $post ) + $revisions; |
158 } |
184 } |
159 |
185 |
160 $show_avatars = get_option( 'show_avatars' ); |
186 $show_avatars = get_option( 'show_avatars' ); |
161 |
187 |
162 cache_users( wp_list_pluck( $revisions, 'post_author' ) ); |
188 cache_users( wp_list_pluck( $revisions, 'post_author' ) ); |
163 |
189 |
164 $can_restore = current_user_can( 'edit_post', $post->ID ); |
190 $can_restore = current_user_can( 'edit_post', $post->ID ); |
165 $current_id = false; |
191 $current_id = false; |
166 |
192 |
167 foreach ( $revisions as $revision ) { |
193 foreach ( $revisions as $revision ) { |
168 $modified = strtotime( $revision->post_modified ); |
194 $modified = strtotime( $revision->post_modified ); |
169 $modified_gmt = strtotime( $revision->post_modified_gmt . ' +0000' ); |
195 $modified_gmt = strtotime( $revision->post_modified_gmt . ' +0000' ); |
170 if ( $can_restore ) { |
196 if ( $can_restore ) { |
171 $restore_link = str_replace( '&', '&', wp_nonce_url( |
197 $restore_link = str_replace( |
172 add_query_arg( |
198 '&', |
173 array( 'revision' => $revision->ID, |
199 '&', |
174 'action' => 'restore' ), |
200 wp_nonce_url( |
|
201 add_query_arg( |
|
202 array( |
|
203 'revision' => $revision->ID, |
|
204 'action' => 'restore', |
|
205 ), |
175 admin_url( 'revision.php' ) |
206 admin_url( 'revision.php' ) |
176 ), |
207 ), |
177 "restore-post_{$revision->ID}" |
208 "restore-post_{$revision->ID}" |
178 ) ); |
209 ) |
|
210 ); |
179 } |
211 } |
180 |
212 |
181 if ( ! isset( $authors[ $revision->post_author ] ) ) { |
213 if ( ! isset( $authors[ $revision->post_author ] ) ) { |
182 $authors[ $revision->post_author ] = array( |
214 $authors[ $revision->post_author ] = array( |
183 'id' => (int) $revision->post_author, |
215 'id' => (int) $revision->post_author, |
184 'avatar' => $show_avatars ? get_avatar( $revision->post_author, 32 ) : '', |
216 'avatar' => $show_avatars ? get_avatar( $revision->post_author, 32 ) : '', |
185 'name' => get_the_author_meta( 'display_name', $revision->post_author ), |
217 'name' => get_the_author_meta( 'display_name', $revision->post_author ), |
186 ); |
218 ); |
187 } |
219 } |
188 |
220 |
189 $autosave = (bool) wp_is_post_autosave( $revision ); |
221 $autosave = (bool) wp_is_post_autosave( $revision ); |
190 $current = ! $autosave && $revision->post_modified_gmt === $post->post_modified_gmt; |
222 $current = ! $autosave && $revision->post_modified_gmt === $post->post_modified_gmt; |
191 if ( $current && ! empty( $current_id ) ) { |
223 if ( $current && ! empty( $current_id ) ) { |
192 // If multiple revisions have the same post_modified_gmt, highest ID is current. |
224 // If multiple revisions have the same post_modified_gmt, highest ID is current. |
193 if ( $current_id < $revision->ID ) { |
225 if ( $current_id < $revision->ID ) { |
194 $revisions[ $current_id ]['current'] = false; |
226 $revisions[ $current_id ]['current'] = false; |
195 $current_id = $revision->ID; |
227 $current_id = $revision->ID; |
196 } else { |
228 } else { |
197 $current = false; |
229 $current = false; |
198 } |
230 } |
199 } elseif ( $current ) { |
231 } elseif ( $current ) { |
200 $current_id = $revision->ID; |
232 $current_id = $revision->ID; |
286 } |
318 } |
287 } |
319 } |
288 |
320 |
289 $from = absint( $from ); |
321 $from = absint( $from ); |
290 |
322 |
291 $diffs = array( array( |
323 $diffs = array( |
292 'id' => $from . ':' . $selected_revision_id, |
324 array( |
293 'fields' => wp_get_revision_ui_diff( $post->ID, $from, $selected_revision_id ), |
325 'id' => $from . ':' . $selected_revision_id, |
294 )); |
326 'fields' => wp_get_revision_ui_diff( $post->ID, $from, $selected_revision_id ), |
|
327 ), |
|
328 ); |
295 |
329 |
296 return array( |
330 return array( |
297 'postId' => $post->ID, |
331 'postId' => $post->ID, |
298 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ), |
332 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ), |
299 'revisionData' => array_values( $revisions ), |
333 'revisionData' => array_values( $revisions ), |
300 'to' => $selected_revision_id, |
334 'to' => $selected_revision_id, |
301 'from' => $from, |
335 'from' => $from, |
302 'diffData' => $diffs, |
336 'diffData' => $diffs, |
303 'baseUrl' => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ), |
337 'baseUrl' => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ), |
304 'compareTwoMode' => absint( $compare_two_mode ), // Apparently booleans are not allowed |
338 'compareTwoMode' => absint( $compare_two_mode ), // Apparently booleans are not allowed |
305 'revisionIds' => array_keys( $revisions ), |
339 'revisionIds' => array_keys( $revisions ), |
306 ); |
340 ); |
307 } |
341 } |
308 |
342 |
309 /** |
343 /** |
310 * Print JavaScript templates required for the revisions experience. |
344 * Print JavaScript templates required for the revisions experience. |
355 <# } #> |
389 <# } #> |
356 <div class="author-card<# if ( data.attributes.autosave ) { #> autosave<# } #>"> |
390 <div class="author-card<# if ( data.attributes.autosave ) { #> autosave<# } #>"> |
357 {{{ data.attributes.author.avatar }}} |
391 {{{ data.attributes.author.avatar }}} |
358 <div class="author-info"> |
392 <div class="author-info"> |
359 <# if ( data.attributes.autosave ) { #> |
393 <# if ( data.attributes.autosave ) { #> |
360 <span class="byline"><?php printf( __( 'Autosave by %s' ), |
394 <span class="byline"> |
361 '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span> |
395 <?php |
|
396 printf( |
|
397 __( 'Autosave by %s' ), |
|
398 '<span class="author-name">{{ data.attributes.author.name }}</span>' |
|
399 ); |
|
400 ?> |
|
401 </span> |
362 <# } else if ( data.attributes.current ) { #> |
402 <# } else if ( data.attributes.current ) { #> |
363 <span class="byline"><?php printf( __( 'Current Revision by %s' ), |
403 <span class="byline"> |
364 '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span> |
404 <?php |
|
405 printf( |
|
406 __( 'Current Revision by %s' ), |
|
407 '<span class="author-name">{{ data.attributes.author.name }}</span>' |
|
408 ); |
|
409 ?> |
|
410 </span> |
365 <# } else { #> |
411 <# } else { #> |
366 <span class="byline"><?php printf( __( 'Revision by %s' ), |
412 <span class="byline"> |
367 '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span> |
413 <?php |
|
414 printf( |
|
415 __( 'Revision by %s' ), |
|
416 '<span class="author-name">{{ data.attributes.author.name }}</span>' |
|
417 ); |
|
418 ?> |
|
419 </span> |
368 <# } #> |
420 <# } #> |
369 <span class="time-ago">{{ data.attributes.timeAgo }}</span> |
421 <span class="time-ago">{{ data.attributes.timeAgo }}</span> |
370 <span class="date">({{ data.attributes.dateShort }})</span> |
422 <span class="date">({{ data.attributes.dateShort }})</span> |
371 </div> |
423 </div> |
372 <# if ( 'to' === data.type && data.attributes.restoreUrl ) { #> |
424 <# if ( 'to' === data.type && data.attributes.restoreUrl ) { #> |