在WordPress 4.4+中,如何为自定义帖子类型及其元数据启用修订?如何使此信息显示在差异视图中?
我试图实现以下博客帖子中描述的内容,但结果是我的实现默默失败:
http://carolandrews.co.uk/saving-revisions-for-custom-post-type-meta-data/https://johnblackbourn.com/post-meta-revisions-wordpress
WP Post Meta Revisions插件不能处理修订屏幕的情况,似乎只能部分工作?它被列为兼容:4.3.3,所以我想我不会太惊讶。相关WordPress票证(20564)也在6个月内没有更新。
以上所有的解决方案都有点过时了吗,还是我的错误?
以下是我的尝试:
我的自定义帖子类型已注册到supports => array(\'revisions\')
这些工作与本机WordPress字段的预期一样。
我使用面向对象的方法来开发插件/主题,并有一个抽象类来表示我的自定义帖子类型。每个子类代表一个特定的CPT。
相关部分如下:
abstract class Foo_Post {
//...
public function __construct(){
$post_type = $this->get_post_type();
add_action(\'init\', array($this,\'init\'));
//...
add_filter(\'_wp_post_revision_fields\', array($this, \'extend_revision_screen_keys\'),10,1);
add_action(\'wp_restore_post_revision\', array(\'restore_revision\', 10, 2 ) );
add_action(\'admin_head\', array($this,\'render_revision_fields\') );
}
public function init() {
$post_type = $this->get_post_type();
//...
add_action("save_post_$post_type", array($this,\'save_post\'), 10, 2);
}
public function extend_revision_screen_keys($fields) {
foreach($this->fields() as $field_name => $field_value) {
if (!isset($field_value[\'field_type\']) || Foo_Post::is_native_field($field_value))
continue;
$fields[$field_name] = $field_name;
}
return $fields;
}
public function render_revision_fields() {
foreach($this->fields() as $field_name=>$field_value){
if (!isset($field_value[\'field_type\']) || Foo_Post::is_native_field($field_value))
continue;
add_filter( \'_wp_post_revision_field_\'.$field_name, array($this,\'render_revision_field\'), 10, 4 );
}
}
public function render_revision_field($value, $field_name, $post, $context) {
foreach($this->fields() as $field_key => $field_value) {
if (!isset($field_value[\'field_type\']) || Foo_Post::is_native_field($field_value) || $field_key != $field_name)
continue;
switch($field_value[\'field_type\']) {
case Foo_FieldType::checkbox :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::date :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::email :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::number :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::multi_text :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
//native types don\'t need to be rendered as it is managed by wordpress
case Foo_FieldType::rel_many :
$value = get_post_meta(get_the_ID(),$field_key,true);
$value = join(\',\',$value);
break;
case Foo_FieldType::rel_single :
$value = get_post_meta(get_the_ID(),$field_key,true);
$value = join(\',\',$value);
break;
case Foo_FieldType::rich_text :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::select :
$value = get_post_meta(get_the_ID(),$field_key,true);
$value = join(\',\',$value);
break;
case Foo_FieldType::single_text :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::tel :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
case Foo_FieldType::url :
$value = get_post_meta(get_the_ID(),$field_key,true);
break;
}
}
return $value;
}
public function restore_revision($post_id, $revision_id){
$revision = get_post( $revision_id );
$meta = get_post_meta( $post_id );
foreach($meta as $field_key => $field_value) {
//only want the metadata fields I\'ve defined. (prefixed with _foo_)
$pos = strpos($field_key,\'_foo_\');
if($pos !== false && $pos == 0) {
$meta = get_metadata( \'post\', $revision->ID, $field_key, true );
if ( false !== $meta )
update_post_meta( $post_id, $field_key, $meta );
//TODO: Why the following?
//else
// delete_post_meta( $post_id, \'my_meta\' );
}
}
}
public function save_post($post_id, $post) {
if(!$this->can_save($post_id))
return;
$parent_id = wp_is_post_revision($post_id);
$revision = $parent_id ? get_post( $parent_id ) : null;
foreach($this->fields() as $field_key => $field_value) {
$value = NULL;
switch($field_value[\'field_type\']) {
case Foo_FieldType::checkbox :
$value = isset($_POST[$field_key]) ? ($_POST[$field_key] == \'true\' ? \'checked\' : \'\') : false;
break;
case Foo_FieldType::date :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : date(\'Y-m-d H:i:s\');
break;
case Foo_FieldType::email :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'\';
break;
case Foo_FieldType::multi_text :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'\';
break;
case Foo_FieldType::number :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'0\';
break;
//skipping native type as it is managed by wordpress
case Foo_FieldType::rel_many :
$value = isset($_POST[$field_key]) ? array_map(\'intval\', (array) $_POST[$field_key]) : array();
break;
case Foo_FieldType::rel_single :
$value = isset($_POST[$field_key]) ? $_POST[$field_key] : -1;
break;
case Foo_FieldType::rich_text :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'\';
break;
case Foo_FieldType::select :
$value = isset($_POST[$field_key]) ? $_POST[$field_key] : \'\';
break;
case Foo_FieldType::single_text :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'\';
break;
case Foo_FieldType::tel :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'\';
break;
case Foo_FieldType::url :
$value = isset($_POST[$field_key]) ? trim($_POST[$field_key]) : \'\';
break;
}
if(!is_null($value))
$this->save_post_field_value($post_id, $revision, $field_key, $value);
}
}
//...
}
有没有什么明显的地方我忽略了,或者最终有没有一个官方的方法来实施这样的事情?关于这方面的文档充其量也很稀少。任何反馈都将不胜感激。
<小时>
Edit
看起来像是
add_filter( "_wp_post_revision_field_$field_name", array($this,\'render_revision_field\'), 10, 4 );
无法注册。所以当wodpress的包含/修订时。php试图应用它,但它不存在。
它看起来也像add_filter(\'_wp_post_revision_fields\', array($this, \'extend_revision_screen_keys\'), 10, 1);
也不会添加。
我上面的类包含在插件的根索引中并实例化。php文件。
也许问题在于事件的顺序?
<小时>Edit 2 (2016-03-31)
跟进@ialocin\'s概念验证:
关于无声失败的问题,问题似乎是第一个链接的建议不正确。它添加了过滤器render_revision_fields
修订后。php文件已处理。
我已经将该注册移到admin\\u init,现在看起来可以正常获取。
global $revision
修复:已确认。
_wp_post_revision_field_foo
共3个参数与4个参数:已确认
get_the_ID()
: 抢手货复制粘贴的牺牲品
我现在不明白的是保存/恢复的理由。之前,当我想在帖子上保存meta\\u数据时,我会执行以下操作:
update_post_meta($post_id,$field_key,$field_value)
IIUC:现在对于修订版,所需的帖子是修订版的父级,但是如果
wp_is_post_revision( $post_id )
失败?这是什么意思?这是否意味着当前没有修订,我应该更新示例中缺失的else分支中的$post?那不会自动进行新的修订吧?
为什么add_metadata/get_metadata
是否与“post”关联,而不是与CPT值关联(例如说“product”?还是应该在这种情况下?修订是否始终存储为“post”类型,并且仅与所需CPT的父级关联?
最合适的回答,由SO网友:Nicolai Grossherr 整理而成
我不能百分之百确定你的失败之处,但我可以告诉你,一般来说,它应该是可行的。证据如下第三条。在我对你说几句话之前:
首先,我的猜测是,它确实不是无声地失败,而是在执行AJAX过程时失败。所以,使用像FireBug这样的工具来仔细研究一下。
其次,我很确定get_the_ID()
- 在代码中使用-将为您获取父帖子ID,这肯定不是您想要的。如果我看得没错,那么可以将所有事件替换为$post->ID
- 所以这很容易改变。
第三,当你或多或少地遵循»John Blackbourn«-approach, 我拿走了他的example code as plugin 仔细看看我自己。与使用代码相比,要做的清理工作更少。但无论如何,下面的代码中有一些必要的小改动,请参阅注释了解详细信息,以使其正常工作。
/*
Plugin Name: Post Meta Revisions
Description: Revisions for the \'foo\' post meta field
Version: http://wordpress.stackexchange.com/questions/221946
Author: John Blackbourn
Plugin URI: http://lud.icro.us/post-meta-revisions-wordpress
*/
function pmr_fields( $fields ) {
$fields[\'foo\'] = \'Foo\';
return $fields;
}
// global $revision doesn\'t work, using third parameter $post instead
function pmr_field( $value, $field, $post ) {
return get_metadata( \'post\', $post->ID, $field, true );
}
function pmr_restore_revision( $post_id, $revision_id ) {
$post = get_post( $post_id );
$revision = get_post( $revision_id );
$meta = get_metadata( \'post\', $revision->ID, \'foo\', true );
if ( false === $meta )
delete_post_meta( $post_id, \'foo\' );
else
update_post_meta( $post_id, \'foo\', $meta );
}
function pmr_save_post( $post_id, $post ) {
if ( $parent_id = wp_is_post_revision( $post_id ) ) {
$parent = get_post( $parent_id );
$meta = get_post_meta( $parent->ID, \'foo\', true );
if ( false !== $meta )
add_metadata( \'post\', $post_id, \'foo\', $meta );
}
}
// we are using three parameters
add_filter( \'_wp_post_revision_field_foo\', \'pmr_field\', 10, 3 );
add_action( \'save_post\', \'pmr_save_post\', 10, 2 );
add_action( \'wp_restore_post_revision\', \'pmr_restore_revision\', 10, 2 );
add_filter( \'_wp_post_revision_fields\', \'pmr_fields\' );
快速测试后,它似乎运行得很好。