/** * Ajax handler for getting revision diffs. * * @since 3.6.0 */ function wp_ajax_get_revision_diffs() { require ABSPATH . 'wp-admin/includes/revision.php'; if (!($post = get_post((int) $_REQUEST['post_id']))) { wp_send_json_error(); } if (!current_user_can('read_post', $post->ID)) { wp_send_json_error(); } // Really just pre-loading the cache here. if (!($revisions = wp_get_post_revisions($post->ID, array('check_enabled' => false)))) { wp_send_json_error(); } $return = array(); @set_time_limit(0); foreach ($_REQUEST['compare'] as $compare_key) { list($compare_from, $compare_to) = explode(':', $compare_key); // from:to $return[] = array('id' => $compare_key, 'fields' => wp_get_revision_ui_diff($post, $compare_from, $compare_to)); } wp_send_json_success($return); }
/** * Prepare revisions for JavaScript. * * @since 3.6.0 * * @param object $post The post object. * @param int $selected_revision_id The selected revision id. * @param int $from (optional) The revision id to compare from. * * @return array An associative array of revision data and related settings. */ function wp_prepare_revisions_for_js($post, $selected_revision_id, $from = null) { $post = get_post($post); $revisions = $authors = array(); $now_gmt = time(); $revisions = wp_get_post_revisions($post->ID, array('order' => 'ASC', 'check_enabled' => false)); // If revisions are disabled, we only want autosaves and the current post. if (!wp_revisions_enabled($post)) { foreach ($revisions as $revision_id => $revision) { if (!wp_is_post_autosave($revision)) { unset($revisions[$revision_id]); } } $revisions = array($post->ID => $post) + $revisions; } $show_avatars = get_option('show_avatars'); cache_users(wp_list_pluck($revisions, 'post_author')); $can_restore = current_user_can('edit_post', $post->ID); foreach ($revisions as $revision) { $modified = strtotime($revision->post_modified); $modified_gmt = strtotime($revision->post_modified_gmt); if ($can_restore) { $restore_link = str_replace('&', '&', wp_nonce_url(add_query_arg(array('revision' => $revision->ID, 'action' => 'restore'), admin_url('revision.php')), "restore-post_{$revision->ID}")); } if (!isset($authors[$revision->post_author])) { $authors[$revision->post_author] = array('id' => (int) $revision->post_author, 'avatar' => $show_avatars ? get_avatar($revision->post_author, 32) : '', 'name' => get_the_author_meta('display_name', $revision->post_author)); } $autosave = (bool) wp_is_post_autosave($revision); $current = !$autosave && $revision->post_modified_gmt === $post->post_modified_gmt; if ($current && !empty($current_id)) { // If multiple revisions have the same post_modified_gmt, highest ID is current. if ($current_id < $revision->ID) { $revisions[$current_id]['current'] = false; $current_id = $revision->ID; } else { $current = false; } } elseif ($current) { $current_id = $revision->ID; } $revisions[$revision->ID] = array('id' => $revision->ID, 'title' => get_the_title($post->ID), 'author' => $authors[$revision->post_author], 'date' => date_i18n(__('M j, Y @ G:i'), $modified), 'dateShort' => date_i18n(_x('j M @ G:i', 'revision date short format'), $modified), 'timeAgo' => sprintf(__('%s ago'), human_time_diff($modified_gmt, $now_gmt)), 'autosave' => $autosave, 'current' => $current, 'restoreUrl' => $can_restore ? $restore_link : false); } // If a post has been saved since the last revision (no revisioned fields were changed) // we may not have a "current" revision. Mark the latest revision as "current". if (empty($current_id)) { if ($revisions[$revision->ID]['autosave']) { $revision = end($revisions); while ($revision['autosave']) { $revision = prev($revisions); } $current_id = $revision['id']; } else { $current_id = $revision->ID; } $revisions[$current_id]['current'] = true; } // Now, grab the initial diff $compare_two_mode = is_numeric($from); if (!$compare_two_mode) { $found = array_search($selected_revision_id, array_keys($revisions)); if ($found) { $from = array_keys(array_slice($revisions, $found - 1, 1, true)); $from = reset($from); } else { $from = 0; } } $from = absint($from); $diffs = array(array('id' => $from . ':' . $selected_revision_id, 'fields' => wp_get_revision_ui_diff($post->ID, $from, $selected_revision_id))); return array('postId' => $post->ID, 'nonce' => wp_create_nonce('revisions-ajax-nonce'), 'revisionData' => array_values($revisions), 'to' => $selected_revision_id, 'from' => $from, 'diffData' => $diffs, 'baseUrl' => parse_url(admin_url('revision.php'), PHP_URL_PATH), 'compareTwoMode' => absint($compare_two_mode), 'revisionIds' => array_keys($revisions)); }
/** * Prepare revisions for JavaScript. * * @since 3.6.0 * * @param object|int $post The post object. Also accepts a post ID. * @param int $selected_revision_id The selected revision ID. * @param int $from Optional. The revision ID to compare from. * * @return array An associative array of revision data and related settings. */ function wp_prepare_revisions_for_js($post, $selected_revision_id, $from = null) { $post = get_post($post); $authors = array(); $now_gmt = time(); $revisions = wp_get_post_revisions($post->ID, array('order' => 'ASC', 'check_enabled' => false)); // If revisions are disabled, we only want autosaves and the current post. if (!wp_revisions_enabled($post)) { foreach ($revisions as $revision_id => $revision) { if (!wp_is_post_autosave($revision)) { unset($revisions[$revision_id]); } } $revisions = array($post->ID => $post) + $revisions; } $show_avatars = get_option('show_avatars'); cache_users(wp_list_pluck($revisions, 'post_author')); $can_restore = current_user_can('edit_post', $post->ID); $current_id = false; foreach ($revisions as $revision) { $modified = strtotime($revision->post_modified); $modified_gmt = strtotime($revision->post_modified_gmt); if ($can_restore) { $restore_link = str_replace('&', '&', wp_nonce_url(add_query_arg(array('revision' => $revision->ID, 'action' => 'restore'), admin_url('revision.php')), "restore-post_{$revision->ID}")); } if (!isset($authors[$revision->post_author])) { $authors[$revision->post_author] = array('id' => (int) $revision->post_author, 'avatar' => $show_avatars ? get_avatar($revision->post_author, 32) : '', 'name' => get_the_author_meta('display_name', $revision->post_author)); } $autosave = (bool) wp_is_post_autosave($revision); $current = !$autosave && $revision->post_modified_gmt === $post->post_modified_gmt; if ($current && !empty($current_id)) { // If multiple revisions have the same post_modified_gmt, highest ID is current. if ($current_id < $revision->ID) { $revisions[$current_id]['current'] = false; $current_id = $revision->ID; } else { $current = false; } } elseif ($current) { $current_id = $revision->ID; } $revisions_data = array('id' => $revision->ID, 'title' => get_the_title($post->ID), 'author' => $authors[$revision->post_author], 'date' => date_i18n(__('M j, Y @ H:i'), $modified), 'dateShort' => date_i18n(_x('j M @ H:i', 'revision date short format'), $modified), 'timeAgo' => sprintf(__('%s ago'), human_time_diff($modified_gmt, $now_gmt)), 'autosave' => $autosave, 'current' => $current, 'restoreUrl' => $can_restore ? $restore_link : false); /** * Filter the array of revisions used on the revisions screen. * * @since 4.4.0 * * @param array $revisions_data { * The bootstrapped data for the revisions screen. * * @type int $id Revision ID. * @type string $title Title for the revision's parent WP_Post object. * @type int $author Revision post author ID. * @type string $date Date the revision was modified. * @type string $dateShort Short-form version of the date the revision was modified. * @type string $timeAgo GMT-aware amount of time ago the revision was modified. * @type bool $autosave Whether the revision is an autosave. * @type bool $current Whether the revision is both not an autosave and the post * modified date matches the revision modified date (GMT-aware). * @type bool|false $restoreUrl URL if the revision can be restored, false otherwise. * } * @param WP_Post $revision The revision's WP_Post object. * @param WP_Post $post The revision's parent WP_Post object. */ $revisions[$revision->ID] = apply_filters('wp_prepare_revision_for_js', $revisions_data, $revision, $post); } /** * If we only have one revision, the initial revision is missing; This happens * when we have an autsosave and the user has clicked 'View the Autosave' */ if (1 === sizeof($revisions)) { $revisions[$post->ID] = array('id' => $post->ID, 'title' => get_the_title($post->ID), 'author' => $authors[$post->post_author], 'date' => date_i18n(__('M j, Y @ H:i'), strtotime($post->post_modified)), 'dateShort' => date_i18n(_x('j M @ H:i', 'revision date short format'), strtotime($post->post_modified)), 'timeAgo' => sprintf(__('%s ago'), human_time_diff(strtotime($post->post_modified_gmt), $now_gmt)), 'autosave' => false, 'current' => true, 'restoreUrl' => false); $current_id = $post->ID; } /* * If a post has been saved since the last revision (no revisioned fields * were changed), we may not have a "current" revision. Mark the latest * revision as "current". */ if (empty($current_id)) { if ($revisions[$revision->ID]['autosave']) { $revision = end($revisions); while ($revision['autosave']) { $revision = prev($revisions); } $current_id = $revision['id']; } else { $current_id = $revision->ID; } $revisions[$current_id]['current'] = true; } // Now, grab the initial diff. $compare_two_mode = is_numeric($from); if (!$compare_two_mode) { $found = array_search($selected_revision_id, array_keys($revisions)); if ($found) { $from = array_keys(array_slice($revisions, $found - 1, 1, true)); $from = reset($from); } else { $from = 0; } } $from = absint($from); $diffs = array(array('id' => $from . ':' . $selected_revision_id, 'fields' => wp_get_revision_ui_diff($post->ID, $from, $selected_revision_id))); return array('postId' => $post->ID, 'nonce' => wp_create_nonce('revisions-ajax-nonce'), 'revisionData' => array_values($revisions), 'to' => $selected_revision_id, 'from' => $from, 'diffData' => $diffs, 'baseUrl' => parse_url(admin_url('revision.php'), PHP_URL_PATH), 'compareTwoMode' => absint($compare_two_mode), 'revisionIds' => array_keys($revisions)); }