web-dev-qa-db-ja.com

非公開で投稿を公開する際に、post_dateを保留中のpost_dateと同じにする

CPTを private status に保存しています。そのため、移行はpendingからprivateになります。つまり、投稿が最初に送信されて保留中の場合は、その送信日がdbのpost_dateフィールドにあります。しかし、投稿が公開されると、日付は現在の日付に更新されました。

後日非公開にされる投稿であっても、投稿の当初の投稿日を保存したいです。

だから私は以下のようなことをしました:

function mycpt_keep_pending_date_on_publishing( $new_status, $old_status, $post ) {
    if( 'mycpt' === $post->post_type && 'pending' === $old_status && 'private' === $new_status ) :
        $pending_datetime = get_post_field( 'post_date', $post->ID, 'raw' );

        // Update the post  
        $modified_post = array(  
            'ID'            => $post->ID,  
            'post_date'     => $pending_datetime,
            'post_date_gmt' => get_gmt_from_date( $pending_datetime )
        );  

        // Update the post into the database  
        wp_update_post( $modified_post );

    endif;
}

add_action( 'transition_post_status', 'mycpt_keep_pending_date_on_publishing' );

しかし、うまくいきません。その理由は何ですか?

3
Mayeenul Islam

@Howdy_McGeeは、彼のコメントで正しい方向に進んでいます。 transition_post_status が発生するまでに、投稿はすでに更新されています(つまり、dbに書き込まれています)。

以下のように、 wp_insert_post_dataの代わりにtransition_post_statusにフックする必要があります。

add_filter ('wp_insert_post_data', 'mycpt_keep_pending_date_on_publishing', 10, 2) ;

function
mycpt_keep_pending_date_on_publishing ($data, $postarr)
{
    if ($data['post_type'] != 'mycpt') {
        return ($data) ;
        }

    // this check amounts to the same thing as transition_post_status(private, pending)
    if ('private' != $data['post_status'] || 'pending' != $postarr['original_post_status']) {
        return ($data) ;
        }

    $pending_datetime = get_post_field ('post_date', $data['ID'], 'raw') ;

    $data['post_date'] = $pending_datetime ;
    $data['post_date_gmt'] = get_gmt_from_date ($pending_datetime) ;

    return ($data) ;
}

注:私はあなたが使ったのと同じ関数名を使いましたが、その関数の本体は異なります。

他の答えに加えて、これはコードが一度だけ実行されることを確認する小さなプラグインです。後で実行しているプラ​​グインによってデータがリセットされる場合は、PHP_INT_MAX -1を優先順位として使用してください(公に配布されているプラ​​グインではありません)。この場合、remove_filter()に同じ値を設定する必要があります。そうしないと、コールバックは削除されません。

<?php
/**
 * Plugin Name: (WPSE) Static post date
 * Description: Keep the post date as the original date for posts published as private
 */
namespace WPSE;

add_filter( 'wp_insert_post_data', '\WPSE\save', 10, 2 );
function save( $post, $raw ) {
    if ( ! in_array( $post['post_status'], [ 'private', 'pending', ] ) ) {
        return $post;
    }
    if ( 'your_post_type' !== $post['post_type'] ) {
        return $post;
    }

    $date = get_post_field( 'post_date', $post['ID'], 'raw' );
    $post['post_date'] = $date;
    $post['post_date_gmt'] = get_gmt_from_date( $date );

    return $post;
}

add_action( 'transition_post_status', function() {
    # Make sure above callback is only triggered once
    remove_filter( 'wp_insert_post_data', '\WPSE\save' );
} );

IIRCの上記のコードに関する主な問題は、private_to_publishedフィルタが廃止されたため、投稿タイプのステータスフィルタを除く _ _ _という特別なものは何もないことです。次のプラグインを試して、それが機能するかどうかを確認してください(あなたの投稿タイプが本当にmycptという名前の場合):

<?php
/* Plugin Name: (WPSE) Test post type status actions */
add_action( 'private_mycpt', function( $ID, \WP_Post $post ) {
    var_dump( current_filter() );
    exit;
}, 10, 2 );
1
kaiser