Last active
August 29, 2015 14:07
-
-
Save mattheu/3720c50a506f067e408a to your computer and use it in GitHub Desktop.
Register Revisions for Meta and Taxonomies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Plugin Name: HM Post Meta Revisions | |
Description: Register Revisions for meta keys. | |
Version: 1.0 | |
Author: Matthew Haines-Young (building on code from John Blackbourn) | |
*/ | |
class HM_Post_Meta_Revisions { | |
protected static $instance; | |
private $fields = array(); | |
private $taxonomies = array(); | |
function __construct() { | |
add_action( 'save_post', array( $this, 'save_revision_meta' ), 10 ); | |
add_action( 'save_post', array( $this, 'save_revision_taxonomies' ), 10 ); | |
add_action( 'wp_restore_post_revision', array( $this, 'restore_revision_meta' ), 10, 2 ); | |
add_action( 'wp_restore_post_revision', array( $this, 'restore_revision_taxonomies' ), 10, 2 ); | |
// Filter the post revision fields. | |
add_filter( '_wp_post_revision_fields', array( $this, 'post_revision_fields' ) ); | |
// Always do a revision on save. | |
// @todo This could be a bit cleverer and check for changes in meta/taxonomies. | |
add_action( 'wp_save_post_revision_check_for_changes', '__return_false' ); | |
} | |
/** | |
* Creates or returns an instance of this class. | |
* | |
* @return HM_Post_Meta_Revisions A single instance of this class. | |
*/ | |
public static function get_instance() { | |
if ( null == self::$instance ) { | |
self::$instance = new self; | |
} | |
return self::$instance; | |
} | |
/** | |
* Register revisions for meta key. | |
* Enable post revisions for a given key. | |
* | |
* @param string $id meta key | |
* @param string $label label. Used in revisions UI. | |
* @param string|closure $format_callback UI Format callback. Format raw meta value to be used in revisions UI. | |
* @return null | |
*/ | |
function register_revisions_for_meta_key( $meta_key, $label, $format_callback = null ) { | |
$this->fields[ $meta_key ] = $label; | |
if ( $format_callback ) { | |
add_filter( "_wp_post_revision_field_$meta_key", $format_callback, 10, 3 ); | |
} | |
} | |
/** | |
* Register revisions for taxonomy. | |
* | |
* @param string $id meta key | |
* @param string $label label. Used in revisions UI. | |
* @param string|closure $format_callback UI Format callback. Format raw meta value to be used in revisions UI. | |
* @return null | |
*/ | |
function register_revisions_for_taxonomy( $taxonomy, $format_callback = null ) { | |
$taxonomy_object = get_taxonomy( $taxonomy ); | |
$this->taxonomies[ $taxonomy_object->name ] = $taxonomy_object->label; | |
if ( $format_callback ) { | |
add_filter( "_wp_post_revision_field_$taxonomy", $format_callback, 10, 3 ); | |
} else { | |
add_filter( "_wp_post_revision_field_$taxonomy", array( $this, 'taxonomy_format_callback' ), 10, 3 ); | |
} | |
} | |
/** | |
* Filter the post revision fields to add the new meta/tax revisions. | |
* | |
* @param array $fields array key => label. | |
* @return array | |
*/ | |
function post_revision_fields( $fields ) { | |
return array_merge( $fields, $this->fields, $this->taxonomies ); | |
} | |
/** | |
* Restore metadata. | |
* This should be hooked in on wp_restore_post_revision | |
* | |
* @param int $post_id | |
* @param int $revision_id | |
* @return null | |
*/ | |
function restore_revision_meta( $post_id, $revision_id ) { | |
foreach ( array_keys( $this->fields ) as $meta_key ) { | |
// Delete all existing meta for this key. | |
delete_post_meta( $post_id, $meta_key ); | |
// Copy meta from revision to parent. | |
$values = get_metadata( 'post', $revision_id, $meta_key, false ); | |
foreach ( $values as $value ) { | |
add_post_meta( $post_id, $meta_key, $value ); | |
} | |
} | |
} | |
/** | |
* Save metadata revision. (hooked in on save_post) | |
* Notes | |
* Uses crazy closure to hook the actual meta data save in after the save post action of the parent has fired. | |
* I wanted to avoid directly saving the $_POST data as plugins may be modifying this before save. | |
* | |
* @param int $post_id | |
* @param int $revision_id | |
* @return null | |
*/ | |
function save_revision_meta( $post_id ) { | |
$revision_id = $post_id; | |
$parent_id = wp_is_post_revision( $revision_id ); | |
$closure = function( $post_id ) use ( $revision_id, $parent_id, &$closure ) { | |
if ( $post_id != $parent_id ) { | |
return; | |
} | |
remove_action( 'wp_insert_post', $closure, 100 ); | |
foreach ( array_keys( $this->fields ) as $meta_key ) { | |
$values = get_metadata( 'post', $parent_id, $meta_key ); | |
delete_metadata( 'post', $revision_id, $meta_key ); | |
foreach ( $values as $value ) { | |
add_metadata( 'post', $revision_id, $meta_key, $value ); | |
} | |
} | |
}; | |
add_action( 'wp_insert_post', $closure, 100 ); | |
} | |
/** | |
* Restore taxonomies. | |
* This should be hooked in on wp_restore_post_revision | |
* | |
* @param int $post_id | |
* @param int $revision_id | |
* @return null | |
*/ | |
function restore_revision_taxonomies( $post_id, $revision_id ) { | |
foreach ( array_keys( $this->taxonomies ) as $taxonomy ) { | |
$terms = wp_get_object_terms( $revision_id, $taxonomy ); | |
if ( empty( $terms ) ) { | |
wp_set_object_terms( $post_id, null, $taxonomy ); | |
} else { | |
$terms = array_map( 'intval', wp_list_pluck( $terms, 'term_id' ) ); | |
wp_set_object_terms( $post_id, $terms, $taxonomy ); | |
} | |
} | |
} | |
/** | |
* Save taxonomy revision. | |
* This should be hooked in on save_post. | |
* Note - uses a slightly crazy closure to hook the actual meta data save in | |
* after all the save post actions of the parent have fired. | |
* | |
* @param int $post_id | |
* @param int $revision_id | |
* @return null | |
*/ | |
function save_revision_taxonomies( $post_id ) { | |
$revision_id = $post_id; | |
$parent_id = wp_is_post_revision( $revision_id ); | |
$closure = function( $post_id ) use ( $revision_id, $parent_id, &$closure ) { | |
if ( $post_id != $parent_id ) { | |
return; | |
} | |
remove_action( 'wp_insert_post', $closure, 100 ); | |
foreach ( array_keys( $this->taxonomies ) as $taxonomy ) { | |
$terms = wp_get_object_terms( $parent_id, $taxonomy ); | |
if ( ! empty( $terms ) ) { | |
$terms = array_map( 'intval', wp_list_pluck( $terms, 'term_id' ) ); | |
wp_set_object_terms( $revision_id, $terms, $taxonomy ); | |
} | |
} | |
}; | |
add_action( 'wp_insert_post', $closure, 100 ); | |
} | |
function taxonomy_format_callback( $value, $field, $parent ) { | |
$terms = wp_get_object_terms( $parent->ID, $field ); | |
if ( ! empty( $terms ) ) { | |
return implode( "\r", wp_list_pluck( $terms, 'name' ) ); | |
} | |
} | |
} | |
add_action( 'plugins_loaded', function() { | |
HM_Post_Meta_Revisions::get_instance(); | |
} ); | |
/** | |
* Register revisions for a meta key. | |
* | |
* @param string $meta_key meta key | |
* @param string $label label used in revisions UI | |
* @param mixed $format_callback callback to format data for use in revisions UI. | |
* @return null | |
*/ | |
function hmpmr_register_revisions_for_meta_key( $meta_key, $label, $format_callback = null ) { | |
HM_Post_Meta_Revisions::get_instance()->register_revisions_for_meta_key( $meta_key, $label, $format_callback ); | |
} | |
/** | |
* Register revisions for a taxonomy. | |
* | |
* @param string $meta_key meta key | |
* @param string $label label used in revisions UI | |
* @param mixed $format_callback callback to format data for use in revisions UI. | |
* @return null | |
*/ | |
function hmpmr_register_revisions_for_taxonomy( $taxonomy, $format_callback = null ) { | |
HM_Post_Meta_Revisions::get_instance()->register_revisions_for_taxonomy( $taxonomy, $format_callback ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment