PageRenderTime 85ms CodeModel.GetById 40ms app.highlight 23ms RepoModel.GetById 17ms app.codeStats 0ms

/wp-admin/includes/revision.php

https://bitbucket.org/acipriani/madeinapulia.com
PHP | 378 lines | 244 code | 37 blank | 97 comment | 39 complexity | 6b8ccd8d31b47d8c367bc69afd38d127 MD5 | raw file
  1<?php
  2/**
  3 * WordPress Administration Revisions API
  4 *
  5 * @package WordPress
  6 * @subpackage Administration
  7 */
  8
  9/**
 10 * Get the revision UI diff.
 11 *
 12 * @since 3.6.0
 13 *
 14 * @param object|int $post         The post object. Also accepts a post ID.
 15 * @param int        $compare_from The revision ID to compare from.
 16 * @param int        $compare_to   The revision ID to come to.
 17 *
 18 * @return array|bool Associative array of a post's revisioned fields and their diffs.
 19 *                    Or, false on failure.
 20 */
 21function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) {
 22	if ( ! $post = get_post( $post ) )
 23		return false;
 24
 25	if ( $compare_from ) {
 26		if ( ! $compare_from = get_post( $compare_from ) )
 27			return false;
 28	} else {
 29		// If we're dealing with the first revision...
 30		$compare_from = false;
 31	}
 32
 33	if ( ! $compare_to = get_post( $compare_to ) )
 34		return false;
 35
 36	// If comparing revisions, make sure we're dealing with the right post parent.
 37	// The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves.
 38	if ( $compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID )
 39		return false;
 40	if ( $compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID )
 41		return false;
 42
 43	if ( $compare_from && strtotime( $compare_from->post_date_gmt ) > strtotime( $compare_to->post_date_gmt ) ) {
 44		$temp = $compare_from;
 45		$compare_from = $compare_to;
 46		$compare_to = $temp;
 47	}
 48
 49	// Add default title if title field is empty
 50	if ( $compare_from && empty( $compare_from->post_title ) )
 51		$compare_from->post_title = __( '(no title)' );
 52	if ( empty( $compare_to->post_title ) )
 53		$compare_to->post_title = __( '(no title)' );
 54
 55	$return = array();
 56
 57	foreach ( _wp_post_revision_fields() as $field => $name ) {
 58		/**
 59		 * Contextually filter a post revision field.
 60		 *
 61		 * The dynamic portion of the hook name, `$field`, corresponds to each of the post
 62		 * fields of the revision object being iterated over in a foreach statement.
 63		 *
 64		 * @since 3.6.0
 65		 *
 66		 * @param string  $compare_from->$field The current revision field to compare to or from.
 67		 * @param string  $field                The current revision field.
 68		 * @param WP_Post $compare_from         The revision post object to compare to or from.
 69		 * @param string  null                  The context of whether the current revision is the old
 70		 *                                      or the new one. Values are 'to' or 'from'.
 71		 */
 72		$content_from = $compare_from ? apply_filters( "_wp_post_revision_field_$field", $compare_from->$field, $field, $compare_from, 'from' ) : '';
 73
 74		/** This filter is documented in wp-admin/includes/revision.php */
 75		$content_to = apply_filters( "_wp_post_revision_field_$field", $compare_to->$field, $field, $compare_to, 'to' );
 76
 77		$args = array(
 78			'show_split_view' => true
 79		);
 80
 81		/**
 82		 * Filter revisions text diff options.
 83		 *
 84		 * Filter the options passed to {@see wp_text_diff()} when viewing a post revision.
 85		 *
 86		 * @since 4.1.0
 87		 *
 88		 * @param array   $args {
 89		 *     Associative array of options to pass to {@see wp_text_diff()}.
 90		 *
 91		 *     @type bool $show_split_view True for split view (two columns), false for
 92		 *                                 un-split view (single column). Default true.
 93		 * }
 94		 * @param string  $field        The current revision field.
 95		 * @param WP_Post $compare_from The revision post to compare from.
 96		 * @param WP_Post $compare_to   The revision post to compare to.
 97		 */
 98		$args = apply_filters( 'revision_text_diff_options', $args, $field, $compare_from, $compare_to );
 99
100		$diff = wp_text_diff( $content_from, $content_to, $args );
101
102		if ( ! $diff && 'post_title' === $field ) {
103			// It's a better user experience to still show the Title, even if it didn't change.
104			// No, you didn't see this.
105			$diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>';
106			$diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td><td></td><td>' . esc_html( $compare_to->post_title ) . '</td>';
107			$diff .= '</tr></tbody>';
108			$diff .= '</table>';
109		}
110
111		if ( $diff ) {
112			$return[] = array(
113				'id' => $field,
114				'name' => $name,
115				'diff' => $diff,
116			);
117		}
118	}
119
120	/**
121	 * Filter the fields displayed in the post revision diff UI.
122	 *
123	 * @since 4.1.0
124	 *
125	 * @param array   $return       Revision UI fields. Each item is an array of id, name and diff.
126	 * @param WP_Post $compare_from The revision post to compare from.
127	 * @param WP_Post $compare_to   The revision post to compare to.
128	 */
129	return apply_filters( 'wp_get_revision_ui_diff', $return, $compare_from, $compare_to );
130
131}
132
133/**
134 * Prepare revisions for JavaScript.
135 *
136 * @since 3.6.0
137 *
138 * @param object|int $post                 The post object. Also accepts a post ID.
139 * @param int        $selected_revision_id The selected revision ID.
140 * @param int        $from                 Optional. The revision ID to compare from.
141 *
142 * @return array An associative array of revision data and related settings.
143 */
144function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) {
145	$post = get_post( $post );
146	$authors = array();
147	$now_gmt = time();
148
149	$revisions = wp_get_post_revisions( $post->ID, array( 'order' => 'ASC', 'check_enabled' => false ) );
150	// If revisions are disabled, we only want autosaves and the current post.
151	if ( ! wp_revisions_enabled( $post ) ) {
152		foreach ( $revisions as $revision_id => $revision ) {
153			if ( ! wp_is_post_autosave( $revision ) )
154				unset( $revisions[ $revision_id ] );
155		}
156		$revisions = array( $post->ID => $post ) + $revisions;
157	}
158
159	$show_avatars = get_option( 'show_avatars' );
160
161	cache_users( wp_list_pluck( $revisions, 'post_author' ) );
162
163	$can_restore = current_user_can( 'edit_post', $post->ID );
164	$current_id = false;
165
166	foreach ( $revisions as $revision ) {
167		$modified = strtotime( $revision->post_modified );
168		$modified_gmt = strtotime( $revision->post_modified_gmt );
169		if ( $can_restore ) {
170			$restore_link = str_replace( '&amp;', '&', wp_nonce_url(
171				add_query_arg(
172					array( 'revision' => $revision->ID,
173						'action' => 'restore' ),
174						admin_url( 'revision.php' )
175				),
176				"restore-post_{$revision->ID}"
177			) );
178		}
179
180		if ( ! isset( $authors[ $revision->post_author ] ) ) {
181			$authors[ $revision->post_author ] = array(
182				'id' => (int) $revision->post_author,
183				'avatar' => $show_avatars ? get_avatar( $revision->post_author, 32 ) : '',
184				'name' => get_the_author_meta( 'display_name', $revision->post_author ),
185			);
186		}
187
188		$autosave = (bool) wp_is_post_autosave( $revision );
189		$current = ! $autosave && $revision->post_modified_gmt === $post->post_modified_gmt;
190		if ( $current && ! empty( $current_id ) ) {
191			// If multiple revisions have the same post_modified_gmt, highest ID is current.
192			if ( $current_id < $revision->ID ) {
193				$revisions[ $current_id ]['current'] = false;
194				$current_id = $revision->ID;
195			} else {
196				$current = false;
197			}
198		} elseif ( $current ) {
199			$current_id = $revision->ID;
200		}
201
202		$revisions[ $revision->ID ] = array(
203			'id'         => $revision->ID,
204			'title'      => get_the_title( $post->ID ),
205			'author'     => $authors[ $revision->post_author ],
206			'date'       => date_i18n( __( 'M j, Y @ G:i' ), $modified ),
207			'dateShort'  => date_i18n( _x( 'j M @ G:i', 'revision date short format' ), $modified ),
208			'timeAgo'    => sprintf( __( '%s ago' ), human_time_diff( $modified_gmt, $now_gmt ) ),
209			'autosave'   => $autosave,
210			'current'    => $current,
211			'restoreUrl' => $can_restore ? $restore_link : false,
212		);
213	}
214
215	/**
216	 * If we only have one revision, the initial revision is missing; This happens
217	 * when we have an autsosave and the user has clicked 'View the Autosave'
218	 */
219	if ( 1 === sizeof( $revisions ) ) {
220		$revisions[ $post->ID ] = array(
221			'id'         => $post->ID,
222			'title'      => get_the_title( $post->ID ),
223			'author'     => $authors[ $post->post_author ],
224			'date'       => date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->modified ) ),
225			'dateShort'  => date_i18n( _x( 'j M @ G:i', 'revision date short format' ), strtotime( $post->modified ) ),
226			'timeAgo'    => sprintf( __( '%s ago' ), human_time_diff( strtotime( $post->post_modified_gmt ), $now_gmt ) ),
227			'autosave'   => false,
228			'current'    => true,
229			'restoreUrl' => false,
230		);
231		$current_id = $post->ID;
232	}
233
234	/*
235	 * If a post has been saved since the last revision (no revisioned fields
236	 * were changed), we may not have a "current" revision. Mark the latest
237	 * revision as "current".
238	 */
239	if ( empty( $current_id ) ) {
240		if ( $revisions[ $revision->ID ]['autosave'] ) {
241			$revision = end( $revisions );
242			while ( $revision['autosave'] ) {
243				$revision = prev( $revisions );
244			}
245			$current_id = $revision['id'];
246		} else {
247			$current_id = $revision->ID;
248		}
249		$revisions[ $current_id ]['current'] = true;
250	}
251
252	// Now, grab the initial diff.
253	$compare_two_mode = is_numeric( $from );
254	if ( ! $compare_two_mode ) {
255		$found = array_search( $selected_revision_id, array_keys( $revisions ) );
256		if ( $found ) {
257			$from = array_keys( array_slice( $revisions, $found - 1, 1, true ) );
258			$from = reset( $from );
259		} else {
260			$from = 0;
261		}
262	}
263
264	$from = absint( $from );
265
266	$diffs = array( array(
267		'id' => $from . ':' . $selected_revision_id,
268		'fields' => wp_get_revision_ui_diff( $post->ID, $from, $selected_revision_id ),
269	));
270
271	return array(
272		'postId'           => $post->ID,
273		'nonce'            => wp_create_nonce( 'revisions-ajax-nonce' ),
274		'revisionData'     => array_values( $revisions ),
275		'to'               => $selected_revision_id,
276		'from'             => $from,
277		'diffData'         => $diffs,
278		'baseUrl'          => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ),
279		'compareTwoMode'   => absint( $compare_two_mode ), // Apparently booleans are not allowed
280		'revisionIds'      => array_keys( $revisions ),
281	);
282}
283
284/**
285 * Print JavaScript templates required for the revisions experience.
286 *
287 * @since 4.1.0
288 *
289 * @global WP_Post $post The global `$post` object.
290 */
291function wp_print_revision_templates() {
292	global $post;
293	?><script id="tmpl-revisions-frame" type="text/html">
294		<div class="revisions-control-frame"></div>
295		<div class="revisions-diff-frame"></div>
296	</script>
297
298	<script id="tmpl-revisions-buttons" type="text/html">
299		<div class="revisions-previous">
300			<input class="button" type="button" value="<?php echo esc_attr_x( 'Previous', 'Button label for a previous revision' ); ?>" />
301		</div>
302
303		<div class="revisions-next">
304			<input class="button" type="button" value="<?php echo esc_attr_x( 'Next', 'Button label for a next revision' ); ?>" />
305		</div>
306	</script>
307
308	<script id="tmpl-revisions-checkbox" type="text/html">
309		<div class="revision-toggle-compare-mode">
310			<label>
311				<input type="checkbox" class="compare-two-revisions"
312				<#
313				if ( 'undefined' !== typeof data && data.model.attributes.compareTwoMode ) {
314					#> checked="checked"<#
315				}
316				#>
317				/>
318				<?php esc_attr_e( 'Compare any two revisions' ); ?>
319			</label>
320		</div>
321	</script>
322
323	<script id="tmpl-revisions-meta" type="text/html">
324		<# if ( ! _.isUndefined( data.attributes ) ) { #>
325			<div class="diff-title">
326				<# if ( 'from' === data.type ) { #>
327					<strong><?php _ex( 'From:', 'Followed by post revision info' ); ?></strong>
328				<# } else if ( 'to' === data.type ) { #>
329					<strong><?php _ex( 'To:', 'Followed by post revision info' ); ?></strong>
330				<# } #>
331				<div class="author-card<# if ( data.attributes.autosave ) { #> autosave<# } #>">
332					{{{ data.attributes.author.avatar }}}
333					<div class="author-info">
334					<# if ( data.attributes.autosave ) { #>
335						<span class="byline"><?php printf( __( 'Autosave by %s' ),
336							'<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
337					<# } else if ( data.attributes.current ) { #>
338						<span class="byline"><?php printf( __( 'Current Revision by %s' ),
339							'<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
340					<# } else { #>
341						<span class="byline"><?php printf( __( 'Revision by %s' ),
342							'<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
343					<# } #>
344						<span class="time-ago">{{ data.attributes.timeAgo }}</span>
345						<span class="date">({{ data.attributes.dateShort }})</span>
346					</div>
347				<# if ( 'to' === data.type && data.attributes.restoreUrl ) { #>
348					<input  <?php if ( wp_check_post_lock( $post->ID ) ) { ?>
349						disabled="disabled"
350					<?php } else { ?>
351						<# if ( data.attributes.current ) { #>
352							disabled="disabled"
353						<# } #>
354					<?php } ?>
355					<# if ( data.attributes.autosave ) { #>
356						type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Autosave' ); ?>" />
357					<# } else { #>
358						type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Revision' ); ?>" />
359					<# } #>
360				<# } #>
361			</div>
362		<# if ( 'tooltip' === data.type ) { #>
363			<div class="revisions-tooltip-arrow"><span></span></div>
364		<# } #>
365	<# } #>
366	</script>
367
368	<script id="tmpl-revisions-diff" type="text/html">
369		<div class="loading-indicator"><span class="spinner"></span></div>
370		<div class="diff-error"><?php _e( 'Sorry, something went wrong. The requested comparison could not be loaded.' ); ?></div>
371		<div class="diff">
372		<# _.each( data.fields, function( field ) { #>
373			<h3>{{ field.name }}</h3>
374			{{{ field.diff }}}
375		<# }); #>
376		</div>
377	</script><?php
378}