/** * Get the revision UI diff. * * @since 3.6.0 * * @param object $post The post object. * @param int $compare_from The revision id to compare from. * @param int $compare_to The revision id to come to. * * @return array|bool Associative array of a post's revisioned fields and their diffs. * Or, false on failure. */ function wp_get_revision_ui_diff($post, $compare_from, $compare_to) { if (!($post = get_post($post))) { return false; } if ($compare_from) { if (!($compare_from = get_post($compare_from))) { return false; } } else { // If we're dealing with the first revision... $compare_from = false; } if (!($compare_to = get_post($compare_to))) { return false; } // If comparing revisions, make sure we're dealing with the right post parent. // The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves. if ($compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID) { return false; } if ($compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID) { return false; } if ($compare_from && strtotime($compare_from->post_date_gmt) > strtotime($compare_to->post_date_gmt)) { $temp = $compare_from; $compare_from = $compare_to; $compare_to = $temp; } // Add default title if title field is empty if ($compare_from && empty($compare_from->post_title)) { $compare_from->post_title = __('(no title)'); } if (empty($compare_to->post_title)) { $compare_to->post_title = __('(no title)'); } $return = array(); foreach (_wp_post_revision_fields() as $field => $name) { $content_from = $compare_from ? apply_filters("_wp_post_revision_field_{$field}", $compare_from->{$field}, $field, $compare_from, 'from') : ''; $content_to = apply_filters("_wp_post_revision_field_{$field}", $compare_to->{$field}, $field, $compare_to, 'to'); $diff = wp_text_diff($content_from, $content_to, array('show_split_view' => true)); if (!$diff && 'post_title' === $field) { // It's a better user experience to still show the Title, even if it didn't change. // No, you didn't see this. $diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>'; $diff .= '<td>' . esc_html($compare_from->post_title) . '</td><td></td><td>' . esc_html($compare_to->post_title) . '</td>'; $diff .= '</tr></tbody>'; $diff .= '</table>'; } if ($diff) { $return[] = array('id' => $field, 'name' => $name, 'diff' => $diff); } } return $return; }
public function diff() { // make sure the keys are set on $left and $right so we don't get any undefined errors $field_keys = array_fill_keys($this->fields_to_add, null); $left = array_merge($field_keys, (array) $this->left); $right = array_merge($field_keys, (array) $this->right); $identical = true; $rev_fields = array(); foreach (_wp_post_revision_fields() as $field => $field_title) { $left_content = apply_filters("_wp_post_revision_field_{$field}", $left[$field], $field); $right_content = apply_filters("_wp_post_revision_field_{$field}", $right[$field], $field); if (!($content = wp_text_diff($left_content, $right_content))) { continue; } // There is no difference between left and right $identical = false; $rev_fields[] = array('field' => $field, 'title' => $field_title, 'content' => $content); } return $identical ? false : $rev_fields; }
function theme($content) { global $post; $revision_id = isset($_REQUEST['revision']) ? absint($_REQUEST['revision']) : 0; $left = isset($_REQUEST['left']) ? absint($_REQUEST['left']) : 0; $right = isset($_REQUEST['right']) ? absint($_REQUEST['right']) : 0; $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'view'; $new_content = ''; if ($action != 'edit') { $top = ""; $btop = ""; $btop .= '<div class="incsub_wiki incsub_wiki_single">'; $btop .= '<div class="incsub_wiki_tabs incsub_wiki_tabs_top">' . $this->tabs() . '<div class="incsub_wiki_clear"></div></div>'; switch ($action) { case 'discussion': break; case 'edit': set_include_path(get_include_path() . PATH_SEPARATOR . ABSPATH . 'wp-admin'); $post_type_object = get_post_type_object($post->post_type); $p = $post; if (empty($post->ID)) { wp_die(__('You attempted to edit an item that doesn’t exist. Perhaps it was deleted?')); } if (!current_user_can($post_type_object->cap->edit_post, $post_id)) { wp_die(__('You are not allowed to edit this item.')); } if ('trash' == $post->post_status) { wp_die(__('You can’t edit this item because it is in the Trash. Please restore it and try again.')); } if (null == $post_type_object) { wp_die(__('Unknown post type.')); } $post_type = $post->post_type; if ($last = $this->check_post_lock($post->ID)) { add_action('admin_notices', '_admin_notice_post_locked'); } else { $this->set_post_lock($post->ID); wp_enqueue_script('autosave'); } $title = $post_type_object->labels->edit_item; $post = $this->post_to_edit($post_id); $new_content = ''; break; case 'restore': if (!($revision = wp_get_post_revision($revision_id))) { break; } if (!current_user_can('edit_post', $revision->post_parent)) { break; } if (!($post = get_post($revision->post_parent))) { break; } // Revisions disabled and we're not looking at an autosave if ((!WP_POST_REVISIONS || !post_type_supports($post->post_type, 'revisions')) && !wp_is_post_autosave($revision)) { $redirect = get_permalink() . '?action=edit'; break; } check_admin_referer("restore-post_{$post->ID}|{$revision->ID}"); wp_restore_post_revision($revision->ID); $redirect = add_query_arg(array('message' => 5, 'revision' => $revision->ID), get_permalink() . '?action=edit'); break; case 'diff': if (!($left_revision = get_post($left))) { break; } if (!($right_revision = get_post($right))) { break; } // If we're comparing a revision to itself, redirect to the 'view' page for that revision or the edit page for that post if ($left_revision->ID == $right_revision->ID) { $redirect = get_edit_post_link($left_revision->ID); include ABSPATH . 'wp-admin/js/revisions-js.php'; break; } // Don't allow reverse diffs? if (strtotime($right_revision->post_modified_gmt) < strtotime($left_revision->post_modified_gmt)) { $redirect = add_query_arg(array('left' => $right, 'right' => $left)); break; } if ($left_revision->ID == $right_revision->post_parent) { // right is a revision of left $post =& $left_revision; } elseif ($left_revision->post_parent == $right_revision->ID) { // left is a revision of right $post =& $right_revision; } elseif ($left_revision->post_parent == $right_revision->post_parent) { // both are revisions of common parent $post = get_post($left_revision->post_parent); } else { break; } // Don't diff two unrelated revisions if (!WP_POST_REVISIONS || !post_type_supports($post->post_type, 'revisions')) { // Revisions disabled if (!wp_is_post_autosave($left_revision) && !wp_is_post_autosave($right_revision) || $post->ID !== $left_revision->ID && $post->ID !== $right_revision->ID) { $redirect = get_permalink() . '?action=edit'; break; } } if ($left_revision->ID == $right_revision->ID || !wp_get_post_revision($left_revision->ID) && !wp_get_post_revision($right_revision->ID)) { break; } $post_title = '<a href="' . get_permalink() . '?action=edit' . '">' . get_the_title() . '</a>'; $h2 = sprintf(__('Compare Revisions of “%1$s”'), $post_title); $title = __('Revisions'); $left = $left_revision->ID; $right = $right_revision->ID; case 'history': $args = array('format' => 'form-table', 'parent' => false, 'right' => $right, 'left' => $left); if (!WP_POST_REVISIONS || !post_type_supports($post->post_type, 'revisions')) { $args['type'] = 'autosave'; } if (!isset($h2)) { $post_title = '<a href="' . get_permalink() . '?action=edit' . '">' . get_the_title() . '</a>'; $revisions = wp_get_post_revisions($post->ID); $revision = array_shift($revisions); $revision_title = wp_post_revision_title($revision, false); $h2 = sprintf(__('Revision for “%1$s” created on %2$s'), $post_title, $revision_title); } $new_content .= '<h3 class="long-header">' . $h2 . '</h3>'; $new_content .= '<table class="form-table ie-fixed">'; $new_content .= '<col class="th" />'; if ('diff' == $action) { $new_content .= '<tr id="revision">'; $new_content .= '<th scope="row"></th>'; $new_content .= '<th scope="col" class="th-full">'; $new_content .= '<span class="alignleft">' . sprintf(__('Older: %s', $this->translation_domain), wp_post_revision_title($left_revision, false)) . '</span>'; $new_content .= '<span class="alignright">' . sprintf(__('Newer: %s', $this->translation_domain), wp_post_revision_title($right_revision, false)) . '</span>'; $new_content .= '</th>'; $new_content .= '</tr>'; } // use get_post_to_edit filters? $identical = true; foreach (_wp_post_revision_fields() as $field => $field_title) { if ('diff' == $action) { $left_content = apply_filters("_wp_post_revision_field_{$field}", $left_revision->{$field}, $field); $right_content = apply_filters("_wp_post_revision_field_{$field}", $right_revision->{$field}, $field); if (!($rcontent = wp_text_diff($left_content, $right_content))) { continue; } // There is no difference between left and right $identical = false; } else { add_filter("_wp_post_revision_field_{$field}", 'htmlspecialchars'); $rcontent = apply_filters("_wp_post_revision_field_{$field}", $revision->{$field}, $field); } $new_content .= '<tr id="revision-field-<?php echo $field; ?>">'; $new_content .= '<th scope="row">' . esc_html($field_title) . '</th>'; $new_content .= '<td><div class="pre">' . $rcontent . '</div></td>'; $new_content .= '</tr>'; } if ('diff' == $action && $identical) { $new_content .= '<tr><td colspan="2"><div class="updated"><p>' . __('These revisions are identical.', $this->translation_domain) . '</p></div></td></tr>'; } $new_content .= '</table>'; $new_content .= '<br class="clear" />'; $new_content .= '<div class="incsub_wiki_revisions">' . $this->list_post_revisions($post, $args) . '</div>'; $redirect = false; break; default: $crumbs = array(); foreach ($post->ancestors as $parent_pid) { $parent_post = get_post($parent_pid); $crumbs[] = '<a href="' . get_permalink($parent_pid) . '" class="incsub_wiki_crumbs">' . $parent_post->post_title . '</a>'; } $crumbs[] = '<span class="incsub_wiki_crumbs">' . $post->post_title . '</span>'; sort($crumbs); $top .= join(get_option("incsub_meta_seperator", " > "), $crumbs); $children = get_children('post_parent=' . $post->ID . '&post_type=incsub_wiki'); $crumbs = array(); foreach ($children as $child) { $crumbs[] = '<a href="' . get_permalink($child->ID) . '" class="incsub_wiki_crumbs">' . $child->post_title . '</a>'; } $bottom = "<h3>" . __('Sub Wikis', $this->translation_domain) . "</h3> <ul><li>"; $bottom .= join("</li><li>", $crumbs); if (count($crumbs) == 0) { $bottom = ""; } else { $bottom .= "</li></ul>"; } $revisions = wp_get_post_revisions($post->ID); if (current_user_can('edit_wiki')) { $bottom .= '<div class="incsub_wiki-meta">'; if (is_array($revisions) && count($revisions) > 0) { $revision = array_shift($revisions); } $bottom .= '</div>'; } $notification_meta = get_post_custom($post->ID, array('incsub_wiki_email_notification' => 'enabled')); if ($notification_meta['incsub_wiki_email_notification'][0] == 'enabled' && !$this->is_subscribed()) { if (is_user_logged_in()) { $bottom .= '<div class="incsub_wiki-subscribe"><a href="' . wp_nonce_url(add_query_arg(array('post_id' => $post->ID, 'subscribe' => 1)), "wiki-subscribe-wiki_{$post->ID}") . '">' . __('Notify me of changes', $this->translation_domain) . '</a></div>'; } else { if (!empty($_COOKIE['incsub_wiki_email'])) { $user_email = $_COOKIE['incsub_wiki_email']; } else { $user_email = ""; } $bottom .= '<div class="incsub_wiki-subscribe">' . '<form action="" method="post">' . '<label>' . __('E-mail', $this->translation_domain) . ': <input type="text" name="email" id="email" value="' . $user_email . '" /></label> ' . '<input type="hidden" name="post_id" id="post_id" value="' . $post->ID . '" />' . '<input type="submit" name="subscribe" id="subscribe" value="' . __('Notify me of changes', $this->translation_domain) . '" />' . '<input type="hidden" name="_wpnonce" id="_wpnonce" value="' . wp_create_nonce("wiki-subscribe-wiki_{$post->ID}") . '" />' . '</form>' . '</div>'; } } $new_content = $btop . '<div class="incsub_wiki_top">' . $top . '</div>' . $new_content; $new_content .= '<div class="incsub_wiki_content">' . $content . '</div>'; $new_content .= '<div class="incsub_wiki_bottom">' . $bottom . '</div>'; $redirect = false; } $new_content .= '</div>'; } if (!comments_open()) { $new_content .= '<style type="text/css">' . '#comments { display: none; }' . '</style>'; } else { $new_content .= '<style type="text/css">' . '.hentry { margin-bottom: 5px; }' . '</style>'; } // Empty post_type means either malformed object found, or no valid parent was found. if (isset($redirect) && !$redirect && empty($post->post_type)) { $redirect = 'edit.php'; } if (!empty($redirect)) { echo '<script type="text/javascript">' . 'window.location = "' . $redirect . '";' . '</script>'; exit; } return $new_content; }
/** * find newer version of post, or return null if there is no newer autosave version * * @param $pid * @return mixed|null */ public function get_autosave_version_if_newer($pid) { // Detect if there exists an autosave newer than the post and if that autosave is different than the post $autosave = wp_get_post_autosave($pid); $post = get_post($pid); $newer_revision = null; if ($autosave && $post && mysql2date('U', $autosave->post_modified_gmt, false) >= mysql2date('U', $post->post_modified_gmt, false)) { foreach (_wp_post_revision_fields() as $autosave_field => $_autosave_field) { if (normalize_whitespace($autosave->{$autosave_field}) != normalize_whitespace($post->{$autosave_field})) { if ($autosave_field === 'post_content') { $newer_revision = $autosave->{$autosave_field}; } } } unset($autosave_field, $_autosave_field); } return $newer_revision; }
/** * Creates autosave data for the specified post from $_POST data. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 * * @param mixed $post_data Associative array containing the post data or int post ID. * @return mixed The autosave revision ID. WP_Error or 0 on error. */ function wp_create_post_autosave($post_data) { if (is_numeric($post_data)) { $post_id = $post_data; $post_data = $_POST; } else { $post_id = (int) $post_data['post_ID']; } $post_data = _wp_translate_postdata(true, $post_data); if (is_wp_error($post_data)) { return $post_data; } $post_author = get_current_user_id(); // Store one autosave per author. If there is already an autosave, overwrite it. if ($old_autosave = wp_get_post_autosave($post_id, $post_author)) { $new_autosave = _wp_post_revision_data($post_data, true); $new_autosave['ID'] = $old_autosave->ID; $new_autosave['post_author'] = $post_author; // If the new autosave has the same content as the post, delete the autosave. $post = get_post($post_id); $autosave_is_different = false; foreach (array_intersect(array_keys($new_autosave), array_keys(_wp_post_revision_fields($post))) as $field) { if (normalize_whitespace($new_autosave[$field]) != normalize_whitespace($post->{$field})) { $autosave_is_different = true; break; } } if (!$autosave_is_different) { wp_delete_post_revision($old_autosave->ID); return 0; } /** * Fires before an autosave is stored. * * @since 4.1.0 * * @param array $new_autosave Post array - the autosave that is about to be saved. */ do_action('wp_creating_autosave', $new_autosave); return wp_update_post($new_autosave); } // _wp_put_post_revision() expects unescaped. $post_data = wp_unslash($post_data); // Otherwise create the new autosave as a special post revision return _wp_put_post_revision($post_data, true); }
$form_extra = ''; if ('auto-draft' == $post->post_status) { if ('edit' == $action) { $post->post_title = ''; } $autosave = false; $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />"; } else { $autosave = wp_get_post_autosave($post_ID); } $form_action = 'editpost'; $nonce_action = 'update-post_' . $post_ID; $form_extra .= "<input type='hidden' id='post_ID' name='post_ID' value='" . esc_attr($post_ID) . "' />"; // Detect if there exists an autosave newer than the post and if that autosave is different than the post if ($autosave && mysql2date('U', $autosave->post_modified_gmt, false) > mysql2date('U', $post->post_modified_gmt, false)) { foreach (_wp_post_revision_fields($post) as $autosave_field => $_autosave_field) { if (normalize_whitespace($autosave->{$autosave_field}) != normalize_whitespace($post->{$autosave_field})) { $notice = sprintf(__('There is an autosave of this post that is more recent than the version below. <a href="%s">View the autosave</a>'), get_edit_post_link($autosave->ID)); break; } } // If this autosave isn't different from the current post, begone. if (!$notice) { wp_delete_post_revision($autosave->ID); } unset($autosave_field, $_autosave_field); } $post_type_object = get_post_type_object($post_type); // All meta boxes should be defined and added before the first do_meta_boxes() call (or potentially during the do_meta_boxes action). require_once ABSPATH . 'wp-admin/includes/meta-boxes.php'; $publish_callback_args = null;
function wp_ajax_revisions_data() { check_ajax_referer('revisions-ajax-nonce', 'nonce'); $compare_to = !empty($_GET['compare_to']) ? absint($_GET['compare_to']) : 0; $show_autosaves = !empty($_GET['show_autosaves']); $show_split_view = !empty($_GET['show_split_view']); $post_id = !empty($_GET['post_id']) ? absint($_GET['post_id']) : 0; $right_handle_at = !empty($_GET['right_handle_at']) ? (int) $_GET['right_handle_at'] : 0; $left_handle_at = !empty($_GET['left_handle_at']) ? (int) $_GET['left_handle_at'] : 0; $single_revision_id = !empty($_GET['single_revision_id']) ? absint($_GET['single_revision_id']) : 0; $compare_two_mode = (bool) $post_id; $all_the_revisions = array(); if (!$post_id) { $post_id = $compare_to; } if (!current_user_can('read_post', $post_id)) { continue; } if (!($revisions = wp_get_post_revisions($post_id))) { return; } $left_revision = get_post($compare_to); // single model fetch mode // return the diff of a single revision comparison if ($single_revision_id) { $right_revision = get_post($single_revision_id); if (!$compare_to) { $left_revision = get_post($post_id); } // make sure the right revision is the most recent, except on oldest revision if ($compare_to && $right_revision->post_date < $left_revision->post_date) { $temp = $left_revision; $left_revision = $right_revision; $right_revision = $temp; } $lines_added = $lines_deleted = 0; $content = ''; // compare from left to right, passed from application foreach (_wp_post_revision_fields() as $field => $field_value) { $left_content = apply_filters("_wp_post_revision_field_{$field}", $left_revision->{$field}, $field, $left_revision, 'left'); $right_content = apply_filters("_wp_post_revision_field_{$field}", $right_revision->{$field}, $field, $right_revision, 'right'); add_filter("_wp_post_revision_field_{$field}", 'htmlspecialchars'); $args = array(); if ($show_split_view) { $args = array('show_split_view' => true); } // compare_to == 0 means first revision, so compare to a blank field to show whats changed $diff = wp_text_diff_with_count(0 == $compare_to ? '' : $left_content, $right_content, $args); if (isset($diff['html'])) { $content .= sprintf('<div class="diff-label">%s</div>', $field_value); $content .= $diff['html']; } if (isset($diff['lines_added'])) { $lines_added = $lines_added + $diff['lines_added']; } if (isset($diff['lines_deleted'])) { $lines_deleted = $lines_deleted + $diff['lines_deleted']; } } $content = '' == $content ? __('No difference') : $content; $all_the_revisions = array('diff' => $content, 'linesDeleted' => $lines_deleted, 'linesAdded' => $lines_added); echo json_encode($all_the_revisions); exit; } // end single model fetch $count = -1; // reverse the list to start with oldest revision $revisions = array_reverse($revisions); $previous_revision_id = 0; /* translators: revision date format, see http://php.net/date */ $datef = _x('j F, Y @ G:i:s', 'revision date format'); foreach ($revisions as $revision) { if (!$show_autosaves && wp_is_post_autosave($revision)) { continue; } $revision_from_date_author = ''; $is_current_revision = false; $count++; /** * return blank data for diffs to the left of the left handle (for right handel model) * or to the right of the right handle (for left handel model) * and visa versa in RTL mode */ if (!is_rtl()) { if (0 != $left_handle_at && $count < $left_handle_at || 0 != $right_handle_at && $count > $right_handle_at - 2) { $all_the_revisions[] = array('ID' => $revision->ID); continue; } } else { // is_rtl if (0 != $left_handle_at && $count > $left_handle_at - 1 || 0 != $left_handle_at && $count < $right_handle_at) { $all_the_revisions[] = array('ID' => $revision->ID); continue; } } if ($compare_two_mode) { $compare_to_gravatar = get_avatar($left_revision->post_author, 24); $compare_to_author = get_the_author_meta('display_name', $left_revision->post_author); $compare_to_date = date_i18n($datef, strtotime($left_revision->post_modified)); $revision_from_date_author = sprintf(_x('%1$s %2$s, %3$s ago (%4$s)', 'post revision title'), $compare_to_gravatar, $compare_to_author, human_time_diff(strtotime($left_revision->post_modified), current_time('timestamp')), $compare_to_date); } $gravatar = get_avatar($revision->post_author, 24); $author = get_the_author_meta('display_name', $revision->post_author); $date = date_i18n($datef, strtotime($revision->post_modified)); $revision_date_author = sprintf(_x('%1$s %2$s, %3$s ago (%4$s)', 'post revision title'), $gravatar, $author, human_time_diff(strtotime($revision->post_modified), current_time('timestamp')), $date); /* translators: 1: date */ $autosavef = _x('%1$s [Autosave]', 'post revision title extra'); /* translators: 1: date */ $currentf = _x('%1$s [Current Revision]', 'post revision title extra'); if (!($post = get_post($post_id))) { continue; } if ($left_revision->post_modified === $post->post_modified) { $revision_from_date_author = sprintf($currentf, $revision_from_date_author); } elseif (wp_is_post_autosave($left_revision)) { $revision_from_date_author = sprintf($autosavef, $revision_from_date_author); } if ($revision->post_modified === $post->post_modified) { $revision_date_author = sprintf($currentf, $revision_date_author); $is_current_revision = true; } elseif (wp_is_post_autosave($revision)) { $revision_date_author = sprintf($autosavef, $revision_date_author); } /* translators: revision date short format, see http://php.net/date */ $date_short_format = _x('j M @ G:i', 'revision date short format'); $date_short = date_i18n($date_short_format, strtotime($revision->post_modified)); $revision_date_author_short = sprintf('%s <strong>%s</strong><br />%s', $gravatar, $author, $date_short); $restore_link = wp_nonce_url(add_query_arg(array('revision' => $revision->ID, 'action' => 'restore'), admin_url('revision.php')), "restore-post_{$revision->ID}"); // if this is a left handled calculation swap data if (0 != $right_handle_at) { $tmp = $revision_from_date_author; $revision_from_date_author = $revision_date_author; $revision_date_author = $tmp; } if ($compare_two_mode || -1 !== $previous_revision_id) { $all_the_revisions[] = array('ID' => $revision->ID, 'titleTo' => $revision_date_author, 'titleFrom' => $revision_from_date_author, 'titleTooltip' => $revision_date_author_short, 'restoreLink' => urldecode($restore_link), 'previousID' => $previous_revision_id, 'isCurrent' => $is_current_revision); } $previous_revision_id = $revision->ID; } // in RTL + single handle mode, reverse the revision direction if (is_rtl() && $compare_two_mode) { $all_the_revisions = array_reverse($all_the_revisions); } echo json_encode($all_the_revisions); exit; }
/** * Creates autosave data for the specified post from $_POST data. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 * * @uses _wp_translate_postdata() * @uses _wp_post_revision_fields() */ function wp_create_post_autosave($post_id) { $translated = _wp_translate_postdata(true); if (is_wp_error($translated)) { return $translated; } // Only store one autosave. If there is already an autosave, overwrite it. if ($old_autosave = wp_get_post_autosave($post_id)) { $new_autosave = _wp_post_revision_fields($_POST, true); $new_autosave['ID'] = $old_autosave->ID; return wp_update_post($new_autosave); } // Otherwise create the new autosave as a special post revision return _wp_put_post_revision($_POST, true); }
/** * Determines whether left and right revisions are identical. * * This is cribbed nearly wholesale from wp-admin/revision.php. In the future I would like * to clean it up to be less WordPressy and more pluginish. * * @package BuddyPress Docs * @since 1.1 */ function setup_is_identical() { $this->revisions_are_identical = true; foreach (_wp_post_revision_fields() as $field => $field_title) { if ('diff' == bp_docs_history_action()) { $left_content = apply_filters("_wp_post_revision_field_{$field}", $this->left_revision->{$field}, $field); $right_content = apply_filters("_wp_post_revision_field_{$field}", $this->right_revision->{$field}, $field); if (!($content = wp_text_diff($left_content, $right_content))) { continue; } // There is no difference between left and right $this->revisions_are_identical = false; } else { if (isset($this->revision) && is_object($this->revision) && isset($this->revision->{$field})) { add_filter("_wp_post_revision_field_{$field}", 'htmlspecialchars'); $content = apply_filters("_wp_post_revision_field_{$field}", $this->revision->{$field}, $field); } } } }
static function compare_revisions_iframe() { //add_action('admin_init', 'register_admin_colors', 1); set_current_screen('revision-edit'); $left = isset($_GET['left']) ? absint($_GET['left']) : false; $right = isset($_GET['right']) ? absint($_GET['right']) : false; if (!($left_revision = get_post($left))) { return; } if (!($right_revision = get_post($right))) { return; } if (!current_user_can('read_post', $left_revision->ID) || !current_user_can('read_post', $right_revision->ID)) { return; } // Don't allow reverse diffs? if (strtotime($right_revision->post_modified_gmt) < strtotime($left_revision->post_modified_gmt)) { //$redirect = add_query_arg( array( 'left' => $right, 'right' => $left ) ); // Switch-a-roo $temp_revision = $left_revision; $left_revision = $right_revision; $right_revision = $temp_revision; unset($temp_revision); } global $post; if ($left_revision->ID == $right_revision->post_parent) { // right is a revision of left $post = $left_revision; } elseif ($left_revision->post_parent == $right_revision->ID) { // left is a revision of right $post = $right_revision; } elseif ($left_revision->post_parent == $right_revision->post_parent) { // both are revisions of common parent $post = get_post($left_revision->post_parent); } else { wp_die(__('Sorry, But you cant compare unrelated Revisions.', 'revision-control')); } // Don't diff two unrelated revisions if ($left_revision->ID == $right_revision->ID || !wp_get_post_revision($left_revision->ID) && !wp_get_post_revision($right_revision->ID)) { wp_die(__('Sorry, But you cant compare a Revision to itself.', 'revision-control')); } $title = sprintf(__('Compare Revisions of “%1$s”', 'revision-control'), get_the_title()); $left = $left_revision->ID; $right = $right_revision->ID; $GLOBALS['hook_suffix'] = 'revision-control'; wp_enqueue_style('revision-control'); iframe_header(); ?> <div class="wrap"> <h2 class="long-header center"><?php echo $title; ?> </h2> <table class="form-table ie-fixed"> <col class="th" /> <tr id="revision"> <th scope="col" class="th-full"> <?php printf(__('Older: %s', 'revision-control'), wp_post_revision_title($left_revision, false)); ?> <span class="alignright"><?php printf(__('Newer: %s', 'revision-control'), wp_post_revision_title($right_revision, false)); ?> </span> </th> </tr> <?php $fields = _wp_post_revision_fields(); foreach (get_object_taxonomies($post->post_type) as $taxonomy) { $t = get_taxonomy($taxonomy); $fields[$taxonomy] = $t->label; $left_terms = $right_terms = array(); foreach (wp_get_object_terms($left_revision->ID, $taxonomy) as $term) { $left_terms[] = $term->name; } foreach (wp_get_object_terms($right_revision->ID, $taxonomy) as $term) { $right_terms[] = $term->name; } $left_revision->{$taxonomy} = (empty($left_terms) ? '' : "* ") . join("\n* ", $left_terms); $right_revision->{$taxonomy} = (empty($right_terms) ? '' : "* ") . join("\n* ", $right_terms); } $fields['postmeta'] = __('Post Meta', 'revision-control'); $left_revision->postmeta = $right_revision->postmeta = array(); foreach ((array) has_meta($right_revision->ID) as $meta) { if ('_' == $meta['meta_key'][0]) { continue; } $right_revision->postmeta[] = $meta['meta_key'] . ': ' . $meta['meta_value']; $left_val = get_post_meta('post', $left_revision->ID, $meta['meta_key'], true); if (!empty($left_val)) { $left_revision->postmeta[] = $meta['meta_key'] . ': ' . $left_val; } } $right_revision->postmeta = implode("\n", $right_revision->postmeta); $left_revision->postmeta = implode("\n", $left_revision->postmeta); $identical = true; foreach ($fields as $field => $field_title) { if (!($content = wp_text_diff($left_revision->{$field}, $right_revision->{$field}))) { continue; } // There is no difference between left and right $identical = false; ?> <tr> <th scope="row"><strong><?php echo esc_html($field_title); ?> </strong></th> </tr> <tr id="revision-field-<?php echo $field; ?> "> <td><div class="pre"><?php echo $content; ?> </div></td> </tr> <?php } if ($identical) { ?> <tr><td><div class="updated"><p><?php _e('These Revisions are identical.', 'revision-control'); ?> </p></div></td></tr><?php } ?> </table> <p><?php _e('<em>Please Note:</em> at present, Although Taxonomies <em>(Tags / Categories / Custom Taxonomies)</em> are stored with the revisions, Restoring a Revision will <strong>not</strong> restore the taxonomies at present.', 'revision-control'); ?> </p> <br class="clear" /> <?php iframe_footer(); }
function post_updated($post_id, $post_after, $post_before) { $options = $this->get_options(); // Transitioning from an Auto Draft to Published shouldn't result in a notification. if ($post_before->post_status === 'auto-draft' && $post_after->post_status === 'publish') { return; } // If we're purely saving a draft, and don't have the draft option enabled, skip. If we're transitioning one way or the other, send a notification. if (0 == $options['drafts'] && in_array($post_before->post_status, array('draft', 'auto-draft')) && 'draft' == $post_after->post_status) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (!in_array($post_before->post_type, $options['post_types'])) { return; } $this->left_post = $post_before; $this->right_post = $post_after; // If this is a new post, set an empty title for $this->left_post so that it appears in the diff. $child_posts = wp_get_post_revisions($post_id, array('numberposts' => 1)); if (count($child_posts) == 0) { $this->left_post->post_title = ''; } if (!$this->left_post || !$this->right_post) { return; } $html_diffs = array(); $text_diffs = array(); $identical = true; foreach (_wp_post_revision_fields() as $field => $field_title) { $left = apply_filters("_wp_post_revision_field_{$field}", $this->left_post->{$field}, $field); $right = apply_filters("_wp_post_revision_field_{$field}", $this->right_post->{$field}, $field); if (!($diff = $this->wp_text_diff($left, $right))) { continue; } $html_diffs[$field_title] = $diff; $left = normalize_whitespace($left); $right = normalize_whitespace($right); $left_lines = explode("\n", $left); $right_lines = explode("\n", $right); require_once dirname(__FILE__) . '/unified.php'; $text_diff = new Text_Diff($left_lines, $right_lines); $renderer = new Text_Diff_Renderer_unified(); $text_diffs[$field_title] = $renderer->render($text_diff); $identical = false; } if ($identical) { $this->left_post = null; $this->right_post = null; return; } // Grab the meta data $the_author = get_the_author_meta('display_name', get_current_user_id()); // The revision $the_title = get_the_title($this->right_post->ID); // New title (may be same as old title) $the_date = gmdate('j F, Y \\a\\t G:i \\U\\T\\C', strtotime($this->right_post->post_modified_gmt . '+0000')); // Modified time $the_permalink = esc_url(get_permalink($this->right_post->ID)); $the_edit_link = esc_url(get_edit_post_link($this->right_post->ID)); // Send email $charset = apply_filters('wp_mail_charset', get_option('blog_charset')); $blogname = html_entity_decode(get_option('blogname'), ENT_QUOTES, $charset); $title = html_entity_decode($the_title, ENT_QUOTES, $charset); add_action('phpmailer_init', array($this, 'phpmailer_init')); $user_emails = array(); foreach ($options['users'] as $user_id) { if (function_exists('is_multisite') && is_multisite()) { if (is_user_member_of_blog($user_id, get_current_blog_id())) { $user_emails[] = get_user_option('user_email', $user_id); } } else { if ($user_email = get_user_option('user_email', $user_id)) { $user_emails[] = $user_email; } } } $emails = array_unique(array_merge($options['emails'], $user_emails)); if (!count($emails) && apply_filters('email_post_changes_admin_email_fallback', true)) { $emails[] = get_option('admin_email'); } $emails = apply_filters('email_post_changes_emails', $emails, $this->left_post->ID, $this->right_post->ID); foreach ($emails as $email) { do_action('email_post_changes_before_email_generation', $email); $left_title = __('Revision'); $right_title = sprintf(__('Current %s'), $post_type = ucfirst($this->right_post->post_type)); $head_sprintf = __('%s made the following changes to the %s %s on %s'); // HTML $html_diff_head = '<h2>' . sprintf(__('%s changed'), $post_type) . "</h2>\n"; $html_diff_head .= '<p>' . sprintf($head_sprintf, esc_html($the_author), sprintf(_x('“%s” [%s]', '1 = link, 2 = "edit"'), "<a href='{$the_permalink}'>" . esc_html($the_title) . '</a>', "<a href='{$the_edit_link}'>" . __('edit') . '</a>'), $this->right_post->post_type, $the_date) . "</p>\n\n"; $html_diff_head .= "<table style='width: 100%; border-collapse: collapse; border: none;'><tr>\n"; $html_diff_head .= "<td style='width: 50%; padding: 0; margin: 0;'>" . esc_html($left_title) . ' @ ' . esc_html($this->left_post->post_date_gmt) . "</td>\n"; $html_diff_head .= "<td style='width: 50%; padding: 0; margin: 0;'>" . esc_html($right_title) . ' @ ' . esc_html($this->right_post->post_modified_gmt) . "</td>\n"; $html_diff_head .= "</tr></table>\n\n"; $html_diff = ''; foreach ($html_diffs as $field_title => $diff) { $html_diff .= '<h3>' . esc_html($field_title) . "</h3>\n"; $html_diff .= "{$diff}\n\n"; } $html_diff = rtrim($html_diff); // Replace classes with inline style $html_diff = str_replace("class='diff'", 'style="width: 100%; border-collapse: collapse; border: none; white-space: pre-wrap; word-wrap: break-word; font-family: Consolas,Monaco,Courier,monospace;"', $html_diff); $html_diff = preg_replace('#<col[^>]+/?>#i', '', $html_diff); $html_diff = str_replace("class='diff-deletedline'", 'style="padding: 5px; width: 50%; background-color: #fdd;"', $html_diff); $html_diff = str_replace("class='diff-addedline'", 'style="padding: 5px; width: 50%; background-color: #dfd;"', $html_diff); $html_diff = str_replace("class='diff-context'", 'style="padding: 5px; width: 50%;"', $html_diff); $html_diff = str_replace('<td>', '<td style="padding: 5px;">', $html_diff); $html_diff = str_replace('<del>', '<del style="text-decoration: none; background-color: #f99;">', $html_diff); $html_diff = str_replace('<ins>', '<ins style="text-decoration: none; background-color: #9f9;">', $html_diff); $html_diff = str_replace(array('</td>', '</tr>', '</tbody>'), array("</td>\n", "</tr>\n", "</tbody>\n"), $html_diff); $html_diff = $html_diff_head . $html_diff; // Refactor some of the meta data for TEXT $length = max(strlen($left_title), strlen($right_title)); $left_title = str_pad($left_title, $length + 2); $right_title = str_pad($right_title, $length + 2); // TEXT $text_diff = sprintf($head_sprintf, $the_author, '"' . $the_title . '"', $this->right_post->post_type, $the_date) . "\n"; $text_diff .= "URL: {$the_permalink}\n"; $text_diff .= "Edit: {$the_edit_link}\n\n"; foreach ($text_diffs as $field_title => $diff) { $text_diff .= "{$field_title}\n"; $text_diff .= "===================================================================\n"; $text_diff .= "--- {$left_title}\t({$this->left_post->post_date_gmt})\n"; $text_diff .= "+++ {$right_title}\t({$this->right_post->post_modified_gmt})\n"; $text_diff .= "{$diff}\n\n"; } $this->text_diff = $text_diff = rtrim($text_diff); wp_mail($email, sprintf(__('[%s] %s changed: %s'), $blogname, $post_type, $title), $html_diff); do_action('email_post_changes_after_email_sent', $email); } remove_action('phpmailer_init', array($this, 'phpmailer_init')); do_action('email_post_changes_email_sent'); }
function compare_revisions_iframe() { if (function_exists('register_admin_colors')) { add_action('admin_init', 'register_admin_colors', 1); } else { // Hard coded translation strings here as the translations are not required, just the name and stlesheet. wp_admin_css_color('classic', 'Blue', admin_url("css/colors-classic.css"), array('#073447', '#21759B', '#EAF3FA', '#BBD8E7')); wp_admin_css_color('fresh', 'Gray', admin_url("css/colors-fresh.css"), array('#464646', '#6D6D6D', '#F1F1F1', '#DFDFDF')); } $left = isset($_GET['left']) ? absint($_GET['left']) : false; $right = isset($_GET['right']) ? absint($_GET['right']) : false; if (!($left_revision = get_post($left))) { break; } if (!($right_revision = get_post($right))) { break; } if (!current_user_can('read_post', $left_revision->ID) || !current_user_can('read_post', $right_revision->ID)) { break; } // Don't allow reverse diffs? if (strtotime($right_revision->post_modified_gmt) < strtotime($left_revision->post_modified_gmt)) { //$redirect = add_query_arg( array( 'left' => $right, 'right' => $left ) ); // Switch-a-roo $temp_revision = $left_revision; $left_revision = $right_revision; $right_revision = $temp_revision; unset($temp_revision); } global $post; if ($left_revision->ID == $right_revision->post_parent) { // right is a revision of left $post = $left_revision; } elseif ($left_revision->post_parent == $right_revision->ID) { // left is a revision of right $post = $right_revision; } elseif ($left_revision->post_parent == $right_revision->post_parent) { // both are revisions of common parent $post = get_post($left_revision->post_parent); } else { wp_die(__('Sorry, But you cant compare unrelated Revisions.', 'revision-control')); } // Don't diff two unrelated revisions if ($left_revision->ID == $right_revision->ID || !wp_get_post_revision($left_revision->ID) && !wp_get_post_revision($right_revision->ID)) { wp_die(__('Sorry, But you cant compare a Revision to itself.', 'revision-control')); } $title = sprintf(__('Compare Revisions of “%1$s”', 'revision-control'), get_the_title()); $left = $left_revision->ID; $right = $right_revision->ID; iframe_header(); ?> <div class="wrap"> <h2 class="long-header center"><?php echo $title; ?> </h2> <table class="form-table ie-fixed"> <col class="th" /> <tr id="revision"> <th scope="col" class="th-full"> <?php printf(__('Older: %s', 'revision-control'), wp_post_revision_title($left_revision, false)); ?> <span class="alignright"><?php printf(__('Newer: %s', 'revision-control'), wp_post_revision_title($right_revision, false)); ?> </span> </th> </tr> <?php $fields = _wp_post_revision_fields(); foreach (get_object_taxonomies($post->post_type) as $taxonomy) { $t = get_taxonomy($taxonomy); $fields[$taxonomy] = $t->label; $left_terms = $right_terms = array(); foreach (wp_get_object_terms($left_revision->ID, $taxonomy) as $term) { $left_terms[] = $term->name; } foreach (wp_get_object_terms($right_revision->ID, $taxonomy) as $term) { $right_terms[] = $term->name; } $left_revision->{$taxonomy} = (empty($left_terms) ? '' : "* ") . join("\n* ", $left_terms); $right_revision->{$taxonomy} = (empty($right_terms) ? '' : "* ") . join("\n* ", $right_terms); } $identical = true; foreach ($fields as $field => $field_title) { if (!($content = wp_text_diff($left_revision->{$field}, $right_revision->{$field}))) { continue; } // There is no difference between left and right $identical = false; ?> <tr> <th scope="row"><strong><?php echo esc_html($field_title); ?> </strong></th> </tr> <tr id="revision-field-<?php echo $field; ?> "> <td><div class="pre"><?php echo $content; ?> </div></td> </tr> <?php } if ($identical) { ?> <tr><td><div class="updated"><p><?php _e('These Revisions are identical.', 'revision-control'); ?> </p></div></td></tr><?php } ?> </table> <p><?php _e('<em>Please Note:</em> at present, Although Taxonomies <em>(Tags / Categories / Custom Taxonomies)</em> are stored with the revisions, Restoring a Revision will <strong>not</strong> restore the taxonomies at present.', 'revision-control'); ?> </p> <br class="clear" /> <?php iframe_footer(); }
/** * wiki_page_edit_notification * @global <type> $wpdb * @param <type> $pageID * @return NULL */ function page_edit_notification($pageID) { global $wpdb; // First, make sure this *is* a Wiki page -CWJ $p = get_post($pageID); if ($p->post_type == 'wiki') { $revisions = get_children(array('post_type' => 'revision', 'post_parent' => $pageID, 'orderby' => 'post_modified_gmt', 'order' => 'DESC')); $wpw_options = get_option('wpw_options'); if ($wpw_options['email_admins'] == 1) { $emails = $this->getAllAdmins(); $pageTitle = $p->post_title; $pagelink = get_permalink($pageID); $subject = "[" . get_bloginfo('title') . "] Wiki Change: " . $pageTitle; $message = '<p>' . sprintf(__("A Wiki Page has been modified on %s."), get_option('home'), $pageTitle) . '</p>'; $message .= "\n\r"; $message .= '<p>' . sprintf(__("The page title is %s"), $pageTitle) . '</p>'; $message .= "\n\r"; $message .= '<p>' . __('To visit this page, ') . '<a href="' . $pagelink . '">' . __('click here') . '</a></p>'; $left_revision = reset($revisions); $right_revision = $p; ob_start(); ?> <style type="text/css"> table.diff .diff-deletedline { background-color: #FFDDDD; } table.diff .diff-deletedline del { background-color: #FF9999; } table.diff .diff-addedline { background-color: #DDFFDD; } table.diff diff.addedline ins { background-color: #99FF99; } </style> <table> <?php $identical = true; foreach (_wp_post_revision_fields() as $field => $field_title) { $left_content = apply_filters("_wp_post_revision_field_{$field}", $left_revision->{$field}, $field); $right_content = apply_filters("_wp_post_revision_field_{$field}", $right_revision->{$field}, $field); if (!($content = wp_text_diff($left_content, $right_content))) { continue; } // There is no diff between left and right $identical = false; ?> <tr id="revision-field-<?php echo $field; ?> "> <th scope="row"><?php echo esc_html($field_title); ?> </th> <td><div class="pre"><?php echo $content; ?> </div></td> </tr> <?php } if ($identical) { ?> <tr><td colspan="2"><div class="updated"><p><?php _e('These revisions are identical.'); ?> </p></div></td></tr> <?php } ?> </table> <?php $message .= ob_get_clean(); foreach ($emails as $email) { add_filter('wp_mail_content_type', array($this, 'allow_html_mail')); wp_mail($email, $subject, $message); remove_filter('wp_mail_content_type', array($this, 'allow_html_mail')); } } } }
public function front_end_editor_shortcodes($attr) { global $wp, $current_screen, $wp_meta_boxes, $post; $is_bac = $this->is_bac(); $output = ''; /** * Start Checking the Conditional needed to render editor * Define Variable needed for use in whole function * * */ if (!is_user_logged_in()) { if ($is_bac === true) { wp_safe_redirect(bon_accounts()->my_account_url()); } else { if (is_woocommerce_activated()) { wp_safe_redirect(get_permalink(wc_get_page_id('myaccount'))); } } } else { if (!$this->is_edit()) { return; } $object_id = $this->get_post_to_edit(); if (!$object_id) { bon_error_notice()->add('invalid_post', __('You attempted to edit an item that doesn’t exist. Perhaps it was deleted?'), 'error'); return; } $post_object = get_post($this->get_post_to_edit()); setup_postdata($GLOBALS['post'] =& $post_object); $current_post_type = get_post_type($object_id); if (!$post_object) { bon_error_notice()->add('invalid_post', __('You attempted to edit an item that doesn’t exist. Perhaps it was deleted?'), 'error'); return; } if (!current_user_can('edit_post', $object_id)) { bon_error_notice()->add('permission_denied', __('You are not allowed to edit this item.'), 'error'); return; } if (!post_type_supports($post_object->post_type, 'front-end-editor')) { bon_error_notice()->add('unsupported_posttype', __('The post type assigned is not supporting front end post', 'bon'), 'error'); } $form_extra = ''; $notice = false; if ($post_object->post_status === 'auto-draft') { $post_object->post_title = ''; $post_object->comment_status = get_option('default_comment_status'); $post_object->ping_status = get_option('default_ping_status'); $autosave = false; $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />"; } else { $autosave = wp_get_post_autosave($object_id); } $form_action = 'editpost'; $nonce_action = 'update-post_' . $object_id; $form_extra .= "<input type='hidden' id='post_ID' name='post_ID' value='" . esc_attr($object_id) . "' />"; $content_css = array(trailingslashit(get_stylesheet_directory_uri()) . 'assets/css/editor-styles.css', trailingslashit(includes_url()) . 'css/dashicons.min.css', trailingslashit(includes_url()) . 'js/mediaelement/mediaelementplayer.min.css', trailingslashit(includes_url()) . 'js/mediaelement/wp-mediaelement.css', trailingslashit(includes_url()) . 'js/tinymce/skins/wordpress/wp-content.css', trailingslashit(includes_url()) . 'css/editor.min.css'); $content_css = join(',', array_map('esc_url', array_unique($content_css))); $args = array('post_ID' => $object_id, 'post_type' => $current_post_type, 'user_ID' => get_current_user_id(), 'post' => $post_object, 'post_type_object' => get_post_type_object($current_post_type), 'autosave' => $autosave, 'form_extra' => $form_extra, 'form_action' => $form_action, 'nonce_action' => $nonce_action, 'editor_settings' => array('dfw' => true, 'drag_drop_upload' => true, 'tabfocus_elements' => 'insert-media-button, save-post', 'editor_height' => 360, 'tinymce' => array('resize' => false, 'add_unload_trigger' => false, 'content_css' => $content_css))); ob_start(); bon_get_template('posts/editor.php', $args); $args['editor'] = ob_get_clean(); unset($args['editor_settings']); set_current_screen($current_post_type); $current_screen->set_parentage('edit.php?post_type=' . $current_post_type); if (!wp_check_post_lock($object_id)) { $args['active_post_lock'] = wp_set_post_lock($object_id); } $messages = $this->get_wp_messages($post_object); $message = false; if (isset($_GET['message'])) { $_GET['message'] = absint($_GET['message']); if (isset($messages[$current_post_type][$_GET['message']])) { $message = $messages[$current_post_type][$_GET['message']]; } elseif (!isset($messages[$current_post_type]) && isset($messages['post'][$_GET['message']])) { $message = $messages['post'][$_GET['message']]; } } // Detect if there exists an autosave newer than the post and if that autosave is different than the post if ($autosave && mysql2date('U', $autosave->post_modified_gmt, false) > mysql2date('U', $post_object->post_modified_gmt, false)) { foreach (_wp_post_revision_fields() as $autosave_field => $_autosave_field) { if (normalize_whitespace($autosave->{$autosave_field}) != normalize_whitespace($post_object->{$autosave_field})) { bon_error_notice()->add('autosave_exists', sprintf(__('There is an autosave of this post that is more recent than the version below. <a href="%s">View the autosave</a>'), get_edit_post_link($autosave->ID)), 'notice'); break; } } // If this autosave isn't different from the current post, begone. if (!$notice) { wp_delete_post_revision($autosave->ID); } unset($autosave_field, $_autosave_field); } bon_get_template('posts/post.php', $args); unset($GLOBALS['current_screen']); wp_reset_postdata(); } }
function get_autosave_notice() { global $post; if ('auto-draft' == $post->post_status) { $autosave = false; } else { $autosave = wp_get_post_autosave($post->ID); } // Detect if there exists an autosave newer than the post and if that autosave is different than the post if ($autosave && mysql2date('U', $autosave->post_modified_gmt, false) > mysql2date('U', $post->post_modified_gmt, false)) { foreach (_wp_post_revision_fields() as $autosave_field => $_autosave_field) { if (normalize_whitespace($autosave->{$autosave_field}) !== normalize_whitespace($post->{$autosave_field})) { return sprintf(__('There is an autosave of this post that is more recent than the version below. <a href="%s">View the autosave</a>'), get_edit_post_link($autosave->ID)); } } // If this autosave isn't different from the current post, begone. wp_delete_post_revision($autosave->ID); } return false; }
<th scope="col" class="th-full"> <span class="alignleft"><?php printf(__('Older: %s'), wp_post_revision_title($left_revision)); ?> </span> <span class="alignright"><?php printf(__('Newer: %s'), wp_post_revision_title($right_revision)); ?> </span> </th> </tr> <?php } // use get_post_to_edit filters? $identical = true; foreach (_wp_post_revision_fields() as $field => $field_title) { if ('diff' == $action) { $left_content = apply_filters("_wp_post_revision_field_{$field}", $left_revision->{$field}, $field); $right_content = apply_filters("_wp_post_revision_field_{$field}", $right_revision->{$field}, $field); if (!($content = wp_text_diff($left_content, $right_content))) { continue; } // There is no difference between left and right $identical = false; } else { add_filter("_wp_post_revision_field_{$field}", 'htmlspecialchars'); $content = apply_filters("_wp_post_revision_field_{$field}", $revision->{$field}, $field); } ?> <tr id="revision-field-<?php
/** * Creates autosave data for the specified post from $_POST data. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 * * @uses _wp_translate_postdata() * @uses _wp_post_revision_fields() * * @return unknown */ function wp_create_post_autosave($post_id) { $translated = _wp_translate_postdata(true); if (is_wp_error($translated)) { return $translated; } $post_author = get_current_user_id(); // Store one autosave per author. If there is already an autosave, overwrite it. if ($old_autosave = wp_get_post_autosave($post_id, $post_author)) { $new_autosave = _wp_post_revision_fields($_POST, true); $new_autosave['ID'] = $old_autosave->ID; $new_autosave['post_author'] = $post_author; // Auto-save revisioned meta fields. foreach (_wp_post_revision_meta_keys() as $meta_key) { if (isset($_POST[$meta_key]) && get_post_meta($new_autosave['ID'], $meta_key, true) != $_POST[$meta_key]) { // Use the underlying delete_metadata and add_metadata vs delete_post_meta // and add_post_meta to make sure we're working with the actual revision meta. delete_metadata('post', $new_autosave['ID'], $meta_key); if (!empty($_POST[$meta_key])) { add_metadata('post', $new_autosave['ID'], $meta_key, $_POST[$meta_key]); } } } // Save the post format if different if (isset($_POST['post_format']) && get_post_meta($new_autosave['ID'], '_revision_post_format', true) != $_POST['post_format']) { delete_metadata('post', $new_autosave['ID'], '_revision_post_format'); if (!empty($_POST['post_format'])) { add_metadata('post', $new_autosave['ID'], '_revision_post_format', $_POST['post_format']); } } return wp_update_post($new_autosave); } // _wp_put_post_revision() expects unescaped. $_POST = wp_unslash($_POST); // Otherwise create the new autosave as a special post revision return _wp_put_post_revision($_POST, true); }
/** * Get the revision UI diff. * * @since 3.6.0 * * @param object|int $post The post object. Also accepts a post ID. * @param int $compare_from The revision ID to compare from. * @param int $compare_to The revision ID to come to. * * @return array|bool Associative array of a post's revisioned fields and their diffs. * Or, false on failure. */ function wp_get_revision_ui_diff($post, $compare_from, $compare_to) { if (!($post = get_post($post))) { return false; } if ($compare_from) { if (!($compare_from = get_post($compare_from))) { return false; } } else { // If we're dealing with the first revision... $compare_from = false; } if (!($compare_to = get_post($compare_to))) { return false; } // If comparing revisions, make sure we're dealing with the right post parent. // The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves. if ($compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID) { return false; } if ($compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID) { return false; } if ($compare_from && strtotime($compare_from->post_date_gmt) > strtotime($compare_to->post_date_gmt)) { $temp = $compare_from; $compare_from = $compare_to; $compare_to = $temp; } // Add default title if title field is empty if ($compare_from && empty($compare_from->post_title)) { $compare_from->post_title = __('(no title)'); } if (empty($compare_to->post_title)) { $compare_to->post_title = __('(no title)'); } $return = array(); foreach (_wp_post_revision_fields() as $field => $name) { /** * Contextually filter a post revision field. * * The dynamic portion of the hook name, `$field`, corresponds to each of the post * fields of the revision object being iterated over in a foreach statement. * * @since 3.6.0 * * @param string $compare_from->$field The current revision field to compare to or from. * @param string $field The current revision field. * @param WP_Post $compare_from The revision post object to compare to or from. * @param string null The context of whether the current revision is the old * or the new one. Values are 'to' or 'from'. */ $content_from = $compare_from ? apply_filters("_wp_post_revision_field_{$field}", $compare_from->{$field}, $field, $compare_from, 'from') : ''; /** This filter is documented in wp-admin/includes/revision.php */ $content_to = apply_filters("_wp_post_revision_field_{$field}", $compare_to->{$field}, $field, $compare_to, 'to'); $args = array('show_split_view' => true); /** * Filter revisions text diff options. * * Filter the options passed to {@see wp_text_diff()} when viewing a post revision. * * @since 4.1.0 * * @param array $args { * Associative array of options to pass to {@see wp_text_diff()}. * * @type bool $show_split_view True for split view (two columns), false for * un-split view (single column). Default true. * } * @param string $field The current revision field. * @param WP_Post $compare_from The revision post to compare from. * @param WP_Post $compare_to The revision post to compare to. */ $args = apply_filters('revision_text_diff_options', $args, $field, $compare_from, $compare_to); $diff = wp_text_diff($content_from, $content_to, $args); if (!$diff && 'post_title' === $field) { // It's a better user experience to still show the Title, even if it didn't change. // No, you didn't see this. $diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>'; $diff .= '<td>' . esc_html($compare_from->post_title) . '</td><td></td><td>' . esc_html($compare_to->post_title) . '</td>'; $diff .= '</tr></tbody>'; $diff .= '</table>'; } if ($diff) { $return[] = array('id' => $field, 'name' => $name, 'diff' => $diff); } } /** * Filter the fields displayed in the post revision diff UI. * * @since 4.1.0 * * @param array $return Revision UI fields. Each item is an array of id, name and diff. * @param WP_Post $compare_from The revision post to compare from. * @param WP_Post $compare_to The revision post to compare to. */ return apply_filters('wp_get_revision_ui_diff', $return, $compare_from, $compare_to); }
/** * Restores a post to the specified revision. * * Can restore a past revision using all fields of the post revision, or only selected fields. * * @since 2.6.0 * * @uses wp_get_post_revision() * @uses wp_update_post() * @uses do_action() Calls 'wp_restore_post_revision' on post ID and revision ID if wp_update_post() * is successful. * * @param int|object $revision_id Revision ID or revision object. * @param array $fields Optional. What fields to restore from. Defaults to all. * @return mixed Null if error, false if no fields to restore, (int) post ID if success. */ function wp_restore_post_revision($revision_id, $fields = null) { if (!($revision = wp_get_post_revision($revision_id, ARRAY_A))) { return $revision; } if (!is_array($fields)) { $fields = array_keys(_wp_post_revision_fields()); } $update = array(); foreach (array_intersect(array_keys($revision), $fields) as $field) { $update[$field] = $revision[$field]; } if (!$update) { return false; } $update['ID'] = $revision['post_parent']; $update = wp_slash($update); //since data is from db // Restore revisioned meta fields. foreach (_wp_post_revision_meta_keys() as $meta_key) { $meta_value = get_post_meta($revision['ID'], $meta_key, true); if (empty($meta_value)) { $meta_value = ''; } // Add slashes to data pulled from the db update_post_meta($update['ID'], $meta_key, wp_slash($meta_value)); } // Restore post format set_post_format($update['ID'], get_post_meta($revision['ID'], '_revision_post_format', true)); $post_id = wp_update_post($update); if (!$post_id || is_wp_error($post_id)) { return $post_id; } // Add restore from details $restore_details = array('restored_revision_id' => $revision_id, 'restored_by_user' => get_current_user_id(), 'restored_time' => time()); update_post_meta($post_id, '_post_restored_from', $restore_details); // Update last edit user update_post_meta($post_id, '_edit_last', get_current_user_id()); do_action('wp_restore_post_revision', $post_id, $revision['ID']); return $post_id; }
/** * Creates autosave data for the specified post from $_POST data. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 * * @uses _wp_translate_postdata() * @uses _wp_post_revision_fields() * * @return unknown */ function wp_create_post_autosave($post_id) { $translated = _wp_translate_postdata(true); if (is_wp_error($translated)) { return $translated; } // Only store one autosave. If there is already an autosave, overwrite it. if ($old_autosave = wp_get_post_autosave($post_id)) { $new_autosave = _wp_post_revision_fields($_POST, true); $new_autosave['ID'] = $old_autosave->ID; $new_autosave['post_author'] = get_current_user_id(); return wp_update_post($new_autosave); } // _wp_put_post_revision() expects unescaped. $_POST = stripslashes_deep($_POST); // Otherwise create the new autosave as a special post revision return _wp_put_post_revision($_POST, true); }
/** * @ticket 26042 */ function test_wp_get_post_revisions_should_order_by_ID_when_post_date_matches() { global $wpdb; $post = $this->factory->post->create_and_get(array('post_title' => 'some-post', 'post_type' => 'post', 'post_content' => 'some_content')); $post = (array) $post; $post_revision_fields = _wp_post_revision_fields($post); $post_revision_fields = wp_slash($post_revision_fields); $revision_ids = array(); $date = date('Y-m-d H:i:s', time() - 10); for ($j = 1; $j < 3; $j++) { // Manually modify dates to ensure they're the same. $post_revision_fields['post_date'] = $date; $post_revision_fields['post_date_gmt'] = $date; $revision_id = wp_insert_post($post_revision_fields); $revision_ids[] = $revision_id; } rsort($revision_ids); $revisions = wp_get_post_revisions($post['ID']); $this->assertEquals($revision_ids, array_values(wp_list_pluck($revisions, 'ID'))); }
/** * Creates autosave data for the specified post from $_POST data. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 * * @uses _wp_translate_postdata() * @uses _wp_post_revision_fields() * * @return unknown */ function wp_create_post_autosave($post_id) { $translated = _wp_translate_postdata(true); if (is_wp_error($translated)) { return $translated; } $post_author = get_current_user_id(); // Store one autosave per author. If there is already an autosave, overwrite it. if ($old_autosave = wp_get_post_autosave($post_id, $post_author)) { $new_autosave = _wp_post_revision_fields($_POST, true); $new_autosave['ID'] = $old_autosave->ID; $new_autosave['post_author'] = $post_author; // If the new autosave is the same content as the post, delete the old autosave. $post = get_post($post_id); $autosave_is_different = false; foreach (array_keys(_wp_post_revision_fields()) as $field) { if (normalize_whitespace($new_autosave[$field]) != normalize_whitespace($post->{$field})) { $autosave_is_different = true; break; } } if (!$autosave_is_different) { wp_delete_post_revision($old_autosave->ID); return; } return wp_update_post($new_autosave); } // _wp_put_post_revision() expects unescaped. $post_data = wp_unslash($_POST); // Otherwise create the new autosave as a special post revision return _wp_put_post_revision($post_data, true); }
/** * wp_restore_post_revision() - Restores a post to the specified revision * * Can restore a past using all fields of the post revision, or only selected fields. * * @package WordPress * @subpackage Post Revisions * @since 2.6 * * @uses wp_get_post_revision() * @uses wp_update_post() * * @param int|object $revision_id revision ID or revision object * @param array $fields optional What fields to restore from. Defaults to all. * @return mixed null if error, false if no fields to restore, (int) post ID if success */ function wp_restore_post_revision( $revision_id, $fields = null ) { if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) ) return $revision; if ( !is_array( $fields ) ) $fields = array_keys( _wp_post_revision_fields() ); $update = array(); foreach( array_intersect( array_keys( $revision ), $fields ) as $field ) $update[$field] = $revision[$field]; if ( !$update ) return false; $update['ID'] = $revision['post_parent']; $post_id = wp_update_post( $update ); if ( is_wp_error( $post_id ) ) return $post_id; if ( $post_id ) do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] ); return $post_id; }
/** * Restores a post to the specified revision. * * Can restore a past revision using all fields of the post revision, or only selected fields. * * @since 2.6.0 * * @param int|WP_Post $revision_id Revision ID or revision object. * @param array $fields Optional. What fields to restore from. Defaults to all. * @return int|false|null Null if error, false if no fields to restore, (int) post ID if success. */ function wp_restore_post_revision($revision_id, $fields = null) { if (!($revision = wp_get_post_revision($revision_id, ARRAY_A))) { return $revision; } if (!is_array($fields)) { $fields = array_keys(_wp_post_revision_fields()); } $update = array(); foreach (array_intersect(array_keys($revision), $fields) as $field) { $update[$field] = $revision[$field]; } if (!$update) { return false; } $update['ID'] = $revision['post_parent']; $update = wp_slash($update); //since data is from db $post_id = wp_update_post($update); if (!$post_id || is_wp_error($post_id)) { return $post_id; } // Add restore from details $restore_details = array('restored_revision_id' => $revision_id, 'restored_by_user' => get_current_user_id(), 'restored_time' => time()); update_post_meta($post_id, '_post_restored_from', $restore_details); // Update last edit user update_post_meta($post_id, '_edit_last', get_current_user_id()); /** * Fires after a post revision has been restored. * * @since 2.6.0 * * @param int $post_id Post ID. * @param int $revision_id Post revision ID. */ do_action('wp_restore_post_revision', $post_id, $revision['ID']); return $post_id; }
public function meta_modal() { global $post, $post_type, $post_type_object, $current_screen, $wp_meta_modal_sections; $post_ID = $post->ID; set_current_screen($post_type); if (!wp_check_post_lock($post->ID)) { $active_post_lock = wp_set_post_lock($post->ID); } $messages = array(); $messages['post'] = array(0 => '', 1 => sprintf(__('Post updated. <a href="%s">View post</a>', 'wplms-front-end'), esc_url(get_permalink($post_ID))), 2 => __('Custom field updated.'), 3 => __('Custom field deleted.'), 4 => __('Post updated.'), 5 => isset($_GET['revision']) ? sprintf(__('Post restored to revision from %s', 'wplms-front-end'), wp_post_revision_title((int) $_GET['revision'], false)) : false, 6 => sprintf(__('Post published. <a href="%s">View post</a>', 'wplms-front-end'), esc_url(get_permalink($post_ID))), 7 => __('Post saved.'), 8 => sprintf(__('Post submitted. <a target="_blank" href="%s">Preview post</a>', 'wplms-front-end'), esc_url(add_query_arg('preview', 'true', get_permalink($post_ID)))), 9 => sprintf(__('Post scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview post</a>', 'wplms-front-end'), date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)), esc_url(get_permalink($post_ID))), 10 => sprintf(__('Post draft updated. <a target="_blank" href="%s">Preview post</a>', 'wplms-front-end'), esc_url(add_query_arg('preview', 'true', get_permalink($post_ID))))); $messages['page'] = array(0 => '', 1 => sprintf(__('Page updated. <a href="%s">View page</a>', 'wplms-front-end'), esc_url(get_permalink($post_ID))), 2 => __('Custom field updated.'), 3 => __('Custom field deleted.'), 4 => __('Page updated.'), 5 => isset($_GET['revision']) ? sprintf(__('Page restored to revision from %s'), 'wplms-front-end', wp_post_revision_title((int) $_GET['revision'], false)) : false, 6 => sprintf(__('Page published. <a href="%s">View page</a>', 'wplms-front-end'), esc_url(get_permalink($post_ID))), 7 => __('Page saved.'), 8 => sprintf(__('Page submitted. <a target="_blank" href="%s">Preview page</a>', 'wplms-front-end'), esc_url(add_query_arg('preview', 'true', get_permalink($post_ID)))), 9 => sprintf(__('Page scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview page</a>', 'wplms-front-end'), date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)), esc_url(get_permalink($post_ID))), 10 => sprintf(__('Page draft updated. <a target="_blank" href="%s">Preview page</a>', 'wplms-front-end'), esc_url(add_query_arg('preview', 'true', get_permalink($post_ID))))); $messages['attachment'] = array_fill(1, 10, __('Media attachment updated.', 'wplms-front-end')); // Hack, for now. $messages = apply_filters('post_updated_messages', $messages); $message = false; if (isset($_GET['message'])) { $_GET['message'] = absint($_GET['message']); if (isset($messages[$post_type][$_GET['message']])) { $message = $messages[$post_type][$_GET['message']]; } elseif (!isset($messages[$post_type]) && isset($messages['post'][$_GET['message']])) { $message = $messages['post'][$_GET['message']]; } } $notice = false; $form_extra = ''; if ('auto-draft' == $post->post_status) { if ('edit' == $action) { $post->post_title = ''; } $autosave = false; $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />"; } else { $autosave = wp_get_post_autosave($post_ID); } $form_action = 'editpost'; $nonce_action = 'update-post_' . $post_ID; // Detect if there exists an autosave newer than the post and if that autosave is different than the post if ($autosave && mysql2date('U', $autosave->post_modified_gmt, false) > mysql2date('U', $post->post_modified_gmt, false)) { foreach (_wp_post_revision_fields() as $autosave_field => $_autosave_field) { if (normalize_whitespace($autosave->{$autosave_field}) != normalize_whitespace($post->{$autosave_field})) { $notice = sprintf(__('There is an autosave of this post that is more recent than the version below. <a href="%s">View the autosave</a>', 'wplms-front-end'), get_edit_post_link($autosave->ID)); break; } } // If this autosave isn't different from the current post, begone. if (!$notice) { wp_delete_post_revision($autosave->ID); } unset($autosave_field, $_autosave_field); } $post_type_object = get_post_type_object($post_type); $this->add_meta_modal_section('submitdiv', __('Publish'), array($this, 'meta_section_publish'), 10, 10); if (post_type_supports($post_type, 'revisions') && 'auto-draft' !== $post->post_status) { $revisions = wp_get_post_revisions($post->ID); $count = count($revisions); if ($count > 1) { $this->add_meta_modal_section('revisionsdiv', __('Revisions', 'wplms-front-end') . ' (' . $count . ')', 'post_revisions_meta_box', 30, 50); } } if (current_theme_supports('post-formats') && post_type_supports($post_type, 'post-formats')) { $this->add_meta_modal_section('formatdiv', _x('Format', 'post format', 'wplms-front-end'), 'post_format_meta_box', 20, 10); } foreach (get_object_taxonomies($post) as $tax_name) { $taxonomy = get_taxonomy($tax_name); if (!$taxonomy->show_ui || false === $taxonomy->meta_box_cb) { continue; } $label = $taxonomy->labels->name; if (!is_taxonomy_hierarchical($tax_name)) { $tax_meta_box_id = 'tagsdiv-' . $tax_name; } else { $tax_meta_box_id = $tax_name . 'div'; } $this->add_meta_modal_section($tax_meta_box_id, $label, $taxonomy->meta_box_cb, 20, 20, array('taxonomy' => $tax_name)); } if (post_type_supports($post_type, 'page-attributes')) { $this->add_meta_modal_section('pageparentdiv', 'page' == $post_type ? __('Page Attributes', 'wplms-front-end') : __('Attributes', 'wplms-front-end'), 'page_attributes_meta_box', 10, 10); } if (post_type_supports($post_type, 'excerpt')) { $this->add_meta_modal_section('postexcerpt', __('Excerpt', 'wplms-front-end'), 'post_excerpt_meta_box', 30, 10); } if (post_type_supports($post_type, 'trackbacks')) { $this->add_meta_modal_section('trackbacksdiv', __('Send Trackbacks', 'wplms-front-end'), 'post_trackback_meta_box', 30, 20); } if (post_type_supports($post_type, 'custom-fields')) { $this->add_meta_modal_section('postcustom', __('Custom Fields', 'wplms-front-end'), 'post_custom_meta_box', 30, 30); } if (post_type_supports($post_type, 'comments')) { $this->add_meta_modal_section('commentstatusdiv', __('Discussion', 'wplms-front-end'), 'post_comment_status_meta_box', 30, 40); } require_once 'meta-modal-template.php'; unset($GLOBALS['current_screen']); }
/** * Restores a post to the specified revision. * * Can restore a past revision using all fields of the post revision, or only selected fields. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 * * @uses wp_get_post_revision() * @uses wp_update_post() * @uses do_action() Calls 'wp_restore_post_revision' on post ID and revision ID if wp_update_post() * is successful. * * @param int|object $revision_id Revision ID or revision object. * @param array $fields Optional. What fields to restore from. Defaults to all. * @return mixed Null if error, false if no fields to restore, (int) post ID if success. */ function wp_restore_post_revision($revision_id, $fields = null) { if (!($revision = wp_get_post_revision($revision_id, ARRAY_A))) { return $revision; } if (!is_array($fields)) { $fields = array_keys(_wp_post_revision_fields()); } $update = array(); foreach (array_intersect(array_keys($revision), $fields) as $field) { $update[$field] = $revision[$field]; } if (!$update) { return false; } $update['ID'] = $revision['post_parent']; $update = add_magic_quotes($update); //since data is from db $post_id = wp_update_post($update); if (is_wp_error($post_id)) { return $post_id; } if ($post_id) { do_action('wp_restore_post_revision', $post_id, $revision['ID']); } return $post_id; }
/** * Get the revision UI diff. * * @since 3.6.0 * * @param object|int $post The post object. Also accepts a post ID. * @param int $compare_from The revision ID to compare from. * @param int $compare_to The revision ID to come to. * * @return array|bool Associative array of a post's revisioned fields and their diffs. * Or, false on failure. */ function wp_get_revision_ui_diff($post, $compare_from, $compare_to) { if (!($post = get_post($post))) { return false; } if ($compare_from) { if (!($compare_from = get_post($compare_from))) { return false; } } else { // If we're dealing with the first revision... $compare_from = false; } if (!($compare_to = get_post($compare_to))) { return false; } // If comparing revisions, make sure we're dealing with the right post parent. // The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves. if ($compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID) { return false; } if ($compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID) { return false; } if ($compare_from && strtotime($compare_from->post_date_gmt) > strtotime($compare_to->post_date_gmt)) { $temp = $compare_from; $compare_from = $compare_to; $compare_to = $temp; } // Add default title if title field is empty if ($compare_from && empty($compare_from->post_title)) { $compare_from->post_title = __('(no title)'); } if (empty($compare_to->post_title)) { $compare_to->post_title = __('(no title)'); } $return = array(); foreach (_wp_post_revision_fields() as $field => $name) { /** * Contextually filter a post revision field. * * The dynamic portion of the hook name, $field, corresponds to each of the post * fields of the revision object being iterated over in a foreach statement. * * @since 3.6.0 * * @param string $compare_from->$field The current revision field to compare to or from. * @param string $field The current revision field. * @param WP_Post $compare_from The revision post object to compare to or from. * @param string null The context of whether the current revision is the old or the new one. Values are 'to' or 'from'. */ $content_from = $compare_from ? apply_filters("_wp_post_revision_field_{$field}", $compare_from->{$field}, $field, $compare_from, 'from') : ''; /** This filter is documented in wp-admin/includes/revision.php */ $content_to = apply_filters("_wp_post_revision_field_{$field}", $compare_to->{$field}, $field, $compare_to, 'to'); $diff = wp_text_diff($content_from, $content_to, array('show_split_view' => true)); if (!$diff && 'post_title' === $field) { // It's a better user experience to still show the Title, even if it didn't change. // No, you didn't see this. $diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>'; $diff .= '<td>' . esc_html($compare_from->post_title) . '</td><td></td><td>' . esc_html($compare_to->post_title) . '</td>'; $diff .= '</tr></tbody>'; $diff .= '</table>'; } if ($diff) { $return[] = array('id' => $field, 'name' => $name, 'diff' => $diff); } } return $return; }