web-dev-qa-db-ja.com

Wordpress 4.4以降:CPT +メタデータの修正方法

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);
        }
    }

    //...
}

私が見落としていることが明白な何か、またはそのようなことを実行するための公式のアプローチがようやくありますか?これに関するドキュメントはせいぜいまばらです。任意のフィードバックはもちろん評価されています。


編集

add_filter( "_wp_post_revision_field_$field_name", array($this,'render_revision_field'), 10, 4 );が登録に失敗したようです。そのため、wodpressのincludes/revision.phpが適用しようとしたときには存在しません。

add_filter('_wp_post_revision_fields', array($this, 'extend_revision_screen_keys'), 10, 1);も追加されていないようです。

上記の私のクラスは、プラグインのルートindex.phpファイルに含まれていてインスタンス化されています。

おそらく問題はイベントの順番でしょうか。


編集2(2016-03-31)

@ialocin の概念実証のフォローアップ:

黙って失敗している問題に関して、それは問題が最初のリンクの提案が間違っていたということでしたようです。 revision.phpファイルが処理された後にフィルタrender_revision_fieldsを追加しました。

私はその登録をadmin_initに移動しました、そしてそれは今正しく拾われるようです。

global $revision fix:確認済み。

3つのパラメータの_wp_post_revision_field_foo対4:確認済み

get_the_ID():よくキャッチ。コピーペーストの犠牲者

今理解できないのは、保存/復元の正当化です。私が投稿にmeta_dataを保存したいと思っていた前は、次のようにしていました。

update_post_meta($post_id,$field_key,$field_value)

IIUC:現在のリビジョンバージョンでは、目的の投稿はリビジョンの親ですが、wp_is_post_revision( $post_id )が失敗した場合はどうなりますか?どういう意味ですか?それは現在リビジョンがないことを意味しています、そして私はあなたの例の行方不明のelseブランチで$ postを更新するべきですか?それは自動的に新しいリビジョンを作りませんか?

add_metadata/get_metadataがCPT値ではなく「post」に関連付けられるのはなぜですか(たとえば「product」と言います)。それともこの場合それでしょうか?改訂は常に「投稿」タイプとして保存され、目的のCPTの親と関連付けられているだけですか。

4
mlhaufe

100パーセント確実ではありません、あなたにとって何が失敗しているのか私はあなたに言うことができます、一般的にそれはうまくいくはずです。その証明は三番目に続いている。私があなたのためにいくつかの発言をする前に:

まず最初に、それは実際には黙って失敗しているのではなく、AJAXプロセスを実行している間にそうなるでしょう。そのため、FireBugのようなツールを使って詳しく調べてください。

第二に、get_the_ID() - あなたのコードで使われているように - はあなたに親の投稿IDを与えるでしょう。確かにこれはあなたが望むものではありません。正しく表示されているのであれば、すべての出現箇所を$post->IDで置き換えることができます。変更するにはこれで十分簡単です。

第三に、あなたが多かれ少なかれ "John Blackbourn" - アプローチ に従っているので、私は彼の コード例をプラグインとして取り入れました 私自身を詳しく見てみましょう。あなたのコードで作業するのに比べて、行うべきクリーンアップ作業が少なくなります。しかし、とにかく、下には必要な小さな変更が加えられたコードが表示されます。詳細についてはコメントを参照してください。

/*
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' );

それに簡単なテストをした後、それはかなりうまくいくようです。

7
Nicolai