web-dev-qa-db-ja.com

wp_insert_post_dataフィルターを組み込み、メタフィールド情報を収集し、無限ループを防止するsave_postアクション

私は投稿のタイトルを変更しようとしていますが、私は投稿が既に保存されるまでその値がデータベースに保存されないメタフィールドからの情報を含めたいと思います。これ以外にwp_insert_post_dataフィルタとしてはうまく機能しています。

// add_filter('wp_insert_post_data', 'tr_change_show_title', 99, 2);

function tr_change_show_title($data, $postarr)
{
    if('post' != $data['post_type']) {
        // don't bother if its an auto-draft, as the post title may not have been completed yet, or in the trash
        if ( !in_array( $data['post_status'], array( 'auto-draft', 'trash' ) ))

        $child_ID = $postarr['ID']; // Child post id
        $parent_ID = get_post_meta($child_ID, "_wpcf_belongs_booking_id", true); // parent ID
        $post_type = $data['post_type'];

        if ($post_type == 'show' && get_post_type($parent_ID) == 'booking') {
            $parent_title = get_the_title($parent_ID);

            $data['post_title'] = $parent_title; // save the parent title first
        }

        if (function_exists('types_render_field')) {

            //this isn't working as the meta field isn't saved yet
            $show_time = types_render_field( "show-time", array("post_id"=>"$child_ID", "raw"=>"true") );
            if ($show_time){
                $data['post_title'] .= ' : ' . $show_time; // Append Show time to title
            }
        }
        $data['post_title'] .= ': show-' . $child_ID; // add the original post id
    }
    return $data;
}

私はコーデックスを読んだ、そしてこのwpseの投稿: https://wordpress.stackexchange.com/a/54713/13551https://codex.wordpress.org/Function_Reference/wp_update_post

私が理解していることは、無限ループはリスクであるということです。これを避けるために、私達は私達の仕事の核心部分の前後にsave_postのフックを解除してから再度フックします。私は次のことを思いついたが、なぜImがまだ無限ループに陥っているのか全く理解していない。

add_action( 'save_post', 'tr_save_post_show_title', 99 );

function tr_save_post_show_title($post_ID){
    if ( !wp_is_post_revision( $post_ID ) ) { // do nothing if a revision

        // Prevent infinite loop
        remove_action('save_post', 'tr_save_post_show_title');

        // Add our filter
        add_filter('wp_insert_post_data', 'tr_change_show_title', 99, 2);

        write_log(array( 'ID' => $post_ID));

        // Re-save the post this time with filter
        wp_update_post( array( 'ID' => $post_ID), true ); // true for error catching

        // Catch errors
        if (is_wp_error($post_id)) {
            $errors = $post_id->get_error_messages();
            foreach ($errors as $error) {
                write_log($error);
            }
        }
        // re-hook the save_post action
        add_action('save_post', 'tr_save_post_show_title');
    }
}
1
orionrush

tr_change_show_titleを関数自体の内側のフィルタにフックすると、無限ループになる可能性があります。関数内のアクションやフィルタを削除/追加するものはすべて削除する必要があります。代わりに、投稿データを更新する必要があるかどうかを確認してください。あなたのケースでは、タイトルがあなたが望む値を持っているかどうか、新しい値でwp_update_postを実行していないのであればチェックするべきです:

add_action( 'save_post', 'tr_save_post_show_title', 99, 2 );
function tr_save_post_show_title( $post_ID, $post ){

    if ( !wp_is_post_revision( $post_ID ) ) { // do nothing if a revision

       $meta = get_post_meta($post_ID, "your-meta-key", true );

        if( $meta != '' ) {

            $desired_title = "Whatever you want as title";

            // Check the title value to check if it should be modified
            if( $post->post_title != $desired_title ) {

                $post->post_title = $desired_title;
                wp_update_post( $post, true );

            }

        }

    }


}

メタフィールドが保存または更新された後にその関数を実行することについて心配しています。メタフィールドが投稿を編集しているフォームにある場合は、他のメタフィールドと同様にメタフィールド値にアクセスできます。とにかく、メタフィールドが保存/更新されたことを確認したい場合は、updated_{$meta_type}_metaの代わりにsave_postアクションフックを使用することができます。利点として、このアクションフックでは、現在のメタ値(もしあれば)に直接アクセスできます。

add_action( 'updated_post_meta', 'tr_save_post_show_title', 99, 4 );
function tr_save_post_show_title( $meta_id, $object_id, $meta_key, $meta_value ) {

    if ( $meta_key == 'the_meta_key_here' && $meta_value != '' && $object_id && ! wp_is_post_revision( $object_id ) ) {

        //write_log(array( 'ID' => $post_id ));

        // Get post data
        $post = get_post( $object_id );

        if( $post ) {
            $desired_title = 'Combine here the $post->post_title with $meta_value as you desire.';

            // Check the title value to check if it should be modified
            if( $post->post_title != $desired_title ) {

                $post->post_title = $desired_title;
                wp_update_post( $post );

            }

        }

    }

}
1
cybmeta

この問題に対する私のアプローチは、wp_insert_post_dataフィルター・フックの$ _POST [metabox_id]から直接「生の」メタデータにアクセスすることです。このアプローチは、投稿が完全にメタデータから生成され、毎回再レンダリングする必要がある私のプロジェクトに適していることを認めます。タフな人はそれが便利だと思うかもしれません。

0
Amarok

@ cybmetaの貢献に関しては、Typesプラグインが私たちに曲線を投げかけているのかもしれないと思います。

彼はあなたが(少なくともこの文脈では)無限ループを作らずにsave_postのところにフィルタを追加することができないという点で正しいです。

私はメタフィールドの値にアクセスしようとしていたので、updated_post_metaに対する彼の提案は適切かもしれませんが、フックが実行されたときにメタキーが利用できなかったのでうまくいきませんでした。これもまた、Typesがカスタムフィールドを設定する方法の問題です。

最後に私は私の最初のアプローチを修正しました。型からの影響に関係なく、以下は投稿のタイトルをsave_postの時点で変更し、メタフィールドの値を組み込んで、無限ループを防止する実用的な例です。 save_postはチェーン内の最後のアクションであるため、他のすべてのデータベース変更の後に実行する必要があります。したがって、WP_Post Objectにはメタフィールド値、および前のフィルタまたはアクションによるすべての変更が含まれると確信できます。私のメタフィールドから最新の情報が欲しくなかったら、wp_insert_post_dataによる単純なフィルタリングで十分でしょう。

add_action('save_post', 'tr_save_post_show_title', 99, 2);

function tr_save_post_show_title ($post_ID, $post) {
    if($post->post_type == 'show' && !in_array($post -> post_status, array('auto-draft', 'revision', 'trash'))) {
        // don't bother if our CPT post is an auto-draft, a revision or in the trash

        $parent_ID = get_post_meta($post_ID, "_wpcf_belongs_booking_id", true); // Types relationship
        $current_title = $post -> post_title; // Get current post title saved in DB

        $post_showtime = get_post_meta($post_ID, "wpcf-show-time", true ); // our custom meta field
        if ($post_showtime == ''){
            $post_showtime = 'To be confirmed';
        }

        if ($parent_ID && get_post_type($parent_ID) == 'booking') { // Check to see if Types a parent relationship has been assigned.

            $show_post_title = get_the_title($parent_ID); // get the id of the parent post
            if ($show_post_title != ''){
                $show_post_title .= ': '  . $post_showtime;
            }
        } else if (!$parent_ID){ // when a parent is not assigned
            $show_title = "Show not yet assigned to venue: " . $post_showtime;
        }
        if ($current_title != $show_post_title ){ // The current title does not match what we would like it to be

            // Prevent infinite loop
            remove_action('save_post', 'tr_save_post_show_title');

            // Re-save the post with our new title
            wp_update_post( array( 'ID' => $post_ID, 'post_title' => $show_post_title ), false ); // true for error catching

            // re-hook the save_post action
            add_action('save_post', 'tr_save_post_show_title', 99, 2);

            // Catch any errors with our custom logging function http://goo.gl/P9HbcK
            if (is_wp_error($post_ID)) {
                $errors = $post_id->get_error_messages();
                foreach ($errors as $error) {
                    write_log($error);
                }
            }
        }
    }
}

興味深いことに save_post_<post_type>save_postがメタから最新の値を取得していない直前に実行されます。どちらかのフィールド。

0
orionrush