WordPress 4.4+:如何修订CPT+元数据

时间:2016-03-28 作者:mlhaufe

在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的父级关联?

1 个回复
最合适的回答,由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\' );
快速测试后,它似乎运行得很好。

相关推荐

How to delete post revisions?

我没有设置修订数量的限制,这使得我的一些帖子有20多个修订,那么如何删除这些修订呢?顺便说一下,我正在使用WPMU,并且有很多博客,那么如何删除我所有博客的WordPress修订版呢?