register($postmeta_key, $display_func); } class cf_revisions { private static $_instance; protected $postmeta_keys = array(); public function __construct() { # save & restore add_action('save_post', array($this, 'save_post_revision'), 10, 2); add_action('wp_restore_post_revision', array($this, 'restore_post_revision'), 10, 2); if (is_admin()) { # revision display global $pagenow; if ($pagenow == 'revision.php') { add_filter('_wp_post_revision_fields', array($this, 'post_revision_fields'), 10, 1); add_filter('_wp_post_revision_field_postmeta', array($this, 'post_revision_field'), 1, 2); } } } public function register($postmeta_key, $display_func = '') { if (!in_array($postmeta_key, $this->postmeta_keys, true)) { $this->postmeta_keys[] = compact('postmeta_key', 'display_func'); } return true; } /** * This is a paranoid check. There will be no object to register the * actions and filters if nobody adds any postmeta to be handled * * @return bool */ public function have_keys() { return (bool) count($this->postmeta_keys); } /** * The opposite of WordPress stripslashes_deep, since wp_slash * only works on arrays of strings. **/ public function slash_deep($value) { if (is_array($value)) { $value = array_map(array($this, 'slash_deep'), $value); } else if (is_object($value)) { $vars = get_object_vars($value); foreach ($vars as $key => $data) { $value->{$key} = $this->slash_deep($data); } } else if (is_string($value)) { $value = wp_slash($value); } return $value; } /** * Save the revision data * * @param int $post_id * @param object $post * @return void */ public function save_post_revision($post_id, $post) { if ($post->post_type != 'revision' || !$this->have_keys()) { return false; } foreach ($this->postmeta_keys as $postmeta_type) { $postmeta_key = $postmeta_type['postmeta_key']; if ($postmeta_values = get_post_meta($post->post_parent, $postmeta_key)) { foreach ($postmeta_values as $postmeta_value) { add_metadata('post', $post_id, $this->slash_deep($postmeta_key), $this->slash_deep($postmeta_value)); } $this->log('Added postmeta for: '.$postmeta_key.' to revision: '.$post_id.' from post: '.$post->post_parent); } } } /** * Revert the revision data * * @param int $post_id * @param int $revision_id * @return void */ public function restore_post_revision($post_id, $revision_id) { if (!$this->have_keys()) { return false; } foreach ($this->postmeta_keys as $postmeta_type) { $postmeta_key = $postmeta_type['postmeta_key']; delete_metadata('post', $post_id, $this->slash_deep($postmeta_key)); // get_metadata does not unslash if ($postmeta_values = get_metadata('post', $revision_id, $postmeta_key)) { foreach ($postmeta_values as $postmeta_value) { $this->log('Setting postmeta: '.$postmeta_key.' for post: '.$post_id); add_metadata('post', $post_id, $this->slash_deep($postmeta_key), $this->slash_deep($postmeta_value), true); } $this->log('Restored post_id: '.$post_id.' metadata from: '.$postmeta_key); } } } public function post_revision_fields($fields) { $fields['postmeta'] = __('Post Meta'); return $fields; } public function post_revision_field($field_id, $field) { if ($field != 'postmeta' || !$this->have_keys()) { return; } remove_filter('_wp_post_revision_field_postmeta', 'htmlspecialchars', 10, 2); $html = '