wp/wp-admin/includes/revision.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
    56 
    56 
    57 	foreach ( _wp_post_revision_fields() as $field => $name ) {
    57 	foreach ( _wp_post_revision_fields() as $field => $name ) {
    58 		/**
    58 		/**
    59 		 * Contextually filter a post revision field.
    59 		 * Contextually filter a post revision field.
    60 		 *
    60 		 *
    61 		 * The dynamic portion of the hook name, $field, corresponds to each of the post
    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.
    62 		 * fields of the revision object being iterated over in a foreach statement.
    63 		 *
    63 		 *
    64 		 * @since 3.6.0
    64 		 * @since 3.6.0
    65 		 *
    65 		 *
    66 		 * @param string  $compare_from->$field The current revision field to compare to or from.
    66 		 * @param string  $compare_from->$field The current revision field to compare to or from.
    67 		 * @param string  $field                The current revision field.
    67 		 * @param string  $field                The current revision field.
    68 		 * @param WP_Post $compare_from         The revision post object to compare to or from.
    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 or the new one. Values are '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'.
    70 		 */
    71 		 */
    71 		$content_from = $compare_from ? apply_filters( "_wp_post_revision_field_$field", $compare_from->$field, $field, $compare_from, 'from' ) : '';
    72 		$content_from = $compare_from ? apply_filters( "_wp_post_revision_field_$field", $compare_from->$field, $field, $compare_from, 'from' ) : '';
    72 
    73 
    73 		/** This filter is documented in wp-admin/includes/revision.php */
    74 		/** This filter is documented in wp-admin/includes/revision.php */
    74 		$content_to = apply_filters( "_wp_post_revision_field_$field", $compare_to->$field, $field, $compare_to, 'to' );
    75 		$content_to = apply_filters( "_wp_post_revision_field_$field", $compare_to->$field, $field, $compare_to, 'to' );
    75 
    76 
    76 		$diff = wp_text_diff( $content_from, $content_to, array( 'show_split_view' => true ) );
    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 );
    77 
   101 
    78 		if ( ! $diff && 'post_title' === $field ) {
   102 		if ( ! $diff && 'post_title' === $field ) {
    79 			// It's a better user experience to still show the Title, even if it didn't change.
   103 			// It's a better user experience to still show the Title, even if it didn't change.
    80 			// No, you didn't see this.
   104 			// No, you didn't see this.
    81 			$diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>';
   105 			$diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>';
    90 				'name' => $name,
   114 				'name' => $name,
    91 				'diff' => $diff,
   115 				'diff' => $diff,
    92 			);
   116 			);
    93 		}
   117 		}
    94 	}
   118 	}
    95 	return $return;
   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 
    96 }
   131 }
    97 
   132 
    98 /**
   133 /**
    99  * Prepare revisions for JavaScript.
   134  * Prepare revisions for JavaScript.
   100  *
   135  *
   106  *
   141  *
   107  * @return array An associative array of revision data and related settings.
   142  * @return array An associative array of revision data and related settings.
   108  */
   143  */
   109 function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) {
   144 function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) {
   110 	$post = get_post( $post );
   145 	$post = get_post( $post );
   111 	$revisions = $authors = array();
   146 	$authors = array();
   112 	$now_gmt = time();
   147 	$now_gmt = time();
   113 
   148 
   114 	$revisions = wp_get_post_revisions( $post->ID, array( 'order' => 'ASC', 'check_enabled' => false ) );
   149 	$revisions = wp_get_post_revisions( $post->ID, array( 'order' => 'ASC', 'check_enabled' => false ) );
   115 	// If revisions are disabled, we only want autosaves and the current post.
   150 	// If revisions are disabled, we only want autosaves and the current post.
   116 	if ( ! wp_revisions_enabled( $post ) ) {
   151 	if ( ! wp_revisions_enabled( $post ) ) {
   124 	$show_avatars = get_option( 'show_avatars' );
   159 	$show_avatars = get_option( 'show_avatars' );
   125 
   160 
   126 	cache_users( wp_list_pluck( $revisions, 'post_author' ) );
   161 	cache_users( wp_list_pluck( $revisions, 'post_author' ) );
   127 
   162 
   128 	$can_restore = current_user_can( 'edit_post', $post->ID );
   163 	$can_restore = current_user_can( 'edit_post', $post->ID );
       
   164 	$current_id = false;
   129 
   165 
   130 	foreach ( $revisions as $revision ) {
   166 	foreach ( $revisions as $revision ) {
   131 		$modified = strtotime( $revision->post_modified );
   167 		$modified = strtotime( $revision->post_modified );
   132 		$modified_gmt = strtotime( $revision->post_modified_gmt );
   168 		$modified_gmt = strtotime( $revision->post_modified_gmt );
   133 		if ( $can_restore ) {
   169 		if ( $can_restore ) {
   165 
   201 
   166 		$revisions[ $revision->ID ] = array(
   202 		$revisions[ $revision->ID ] = array(
   167 			'id'         => $revision->ID,
   203 			'id'         => $revision->ID,
   168 			'title'      => get_the_title( $post->ID ),
   204 			'title'      => get_the_title( $post->ID ),
   169 			'author'     => $authors[ $revision->post_author ],
   205 			'author'     => $authors[ $revision->post_author ],
   170 			'date'       => date_i18n( __( 'M j, Y @ G:i' ), $modified ),
   206 			'date'       => date_i18n( __( 'M j, Y @ H:i' ), $modified ),
   171 			'dateShort'  => date_i18n( _x( 'j M @ G:i', 'revision date short format' ), $modified ),
   207 			'dateShort'  => date_i18n( _x( 'j M @ H:i', 'revision date short format' ), $modified ),
   172 			'timeAgo'    => sprintf( __( '%s ago' ), human_time_diff( $modified_gmt, $now_gmt ) ),
   208 			'timeAgo'    => sprintf( __( '%s ago' ), human_time_diff( $modified_gmt, $now_gmt ) ),
   173 			'autosave'   => $autosave,
   209 			'autosave'   => $autosave,
   174 			'current'    => $current,
   210 			'current'    => $current,
   175 			'restoreUrl' => $can_restore ? $restore_link : false,
   211 			'restoreUrl' => $can_restore ? $restore_link : false,
   176 		);
   212 		);
   177 	}
   213 	}
   178 
   214 
   179 	// If a post has been saved since the last revision (no revisioned fields were changed)
   215 	/**
   180 	// we may not have a "current" revision. Mark the latest revision as "current".
   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 @ H:i' ), strtotime( $post->post_modified ) ),
       
   225 			'dateShort'  => date_i18n( _x( 'j M @ H:i', 'revision date short format' ), strtotime( $post->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 	 */
   181 	if ( empty( $current_id ) ) {
   239 	if ( empty( $current_id ) ) {
   182 		if ( $revisions[ $revision->ID ]['autosave'] ) {
   240 		if ( $revisions[ $revision->ID ]['autosave'] ) {
   183 			$revision = end( $revisions );
   241 			$revision = end( $revisions );
   184 			while ( $revision['autosave'] ) {
   242 			while ( $revision['autosave'] ) {
   185 				$revision = prev( $revisions );
   243 				$revision = prev( $revisions );
   189 			$current_id = $revision->ID;
   247 			$current_id = $revision->ID;
   190 		}
   248 		}
   191 		$revisions[ $current_id ]['current'] = true;
   249 		$revisions[ $current_id ]['current'] = true;
   192 	}
   250 	}
   193 
   251 
   194 	// Now, grab the initial diff
   252 	// Now, grab the initial diff.
   195 	$compare_two_mode = is_numeric( $from );
   253 	$compare_two_mode = is_numeric( $from );
   196 	if ( ! $compare_two_mode ) {
   254 	if ( ! $compare_two_mode ) {
   197 		$found = array_search( $selected_revision_id, array_keys( $revisions ) );
   255 		$found = array_search( $selected_revision_id, array_keys( $revisions ) );
   198 		if ( $found ) {
   256 		if ( $found ) {
   199 			$from = array_keys( array_slice( $revisions, $found - 1, 1, true ) );
   257 			$from = array_keys( array_slice( $revisions, $found - 1, 1, true ) );
   220 		'baseUrl'          => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ),
   278 		'baseUrl'          => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ),
   221 		'compareTwoMode'   => absint( $compare_two_mode ), // Apparently booleans are not allowed
   279 		'compareTwoMode'   => absint( $compare_two_mode ), // Apparently booleans are not allowed
   222 		'revisionIds'      => array_keys( $revisions ),
   280 		'revisionIds'      => array_keys( $revisions ),
   223 	);
   281 	);
   224 }
   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  */
       
   291 function 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 }