Periksa pembaruan vs pos baru pada tindakan save_post

21

Apakah mungkin dalam tindakan save_post untuk menentukan apakah itu posting baru yang dibuat atau posting yang ada sedang diperbarui?

hereswhatidid
sumber
Saya rasa ini tidak mungkin. Lihat komentar saya di bawah jawaban @ moraleida. Mengapa Anda perlu tahu apakah itu posting baru atau sedang diperbarui? Mungkin ada penyelesaian atau pendekatan alternatif.
Stephen Harris

Jawaban:

16

Sejak WordPress versi 3.7. - IIRC - save_posthook - informasi lebih lanjut tentang hook dan penggunaannya di Code Reference:save_post dan Codex:save_post - memiliki parameter ketiga $updateyang dapat digunakan untuk menentukan hal itu.

@par int $ post_ID ID Posting.
@param WP_Post $ post Objek posting.
@param bool $ update Apakah ini postingan yang ada sedang diperbarui atau tidak.


catatan:

$updatetidak selalu true- Anda dapat melihat dan mengujinya sendiri dengan kode di bawah ini. Ini tidak didokumentasikan dengan baik, mungkin jauh dari nama yang optimal, dan karenanya menciptakan harapan yang menyesatkan. Kode di bawah ini dapat digunakan untuk debugging, bermain-main dengan kapan untuk mencegat eksekusi kode, karena jika tidak, Anda tidak akan melihat informasi / pesan. Saya pikir, biang keladinya dalam perilaku menipu adalah penanganan revisi dan penyelamatan otomatis - yang bisa dinonaktifkan, tetapi saya tidak merekomendasikannya, dan belum mengujinya. Tidak yakin apakah ini menjamin Tiket Trac , jadi saya tidak membukanya, jika menurut Anda, ikuti tautannya dan lakukan sendiri. Selain itu, seperti yang dinyatakan dalam komentar, jika Anda memiliki masalah khusus, posting pertanyaan baru.

add_action( 'save_post', 'debug_save_post_update', 10, 3 );
function debug_save_post_update( $ID, $post, $update ) {

  echo '<pre>';
  print_r( $post ); echo '<br>';
  echo '$update == ';
  echo $update ? 'true' : 'false';

  //conditions
  if( ! $update && $post->post_status == "auto-draft" ) {
    // applies to new post
    echo ' && $post->post_status == "auto-draft"';
    //die();
  } else if ( ! $update ) {
    // applies basically to the (auto saved) revision 
    //die();
  } else {
    // applies to updating a published post
    // when there is a revision, which is normally the case, 
    // standard behavior of WordPress, then it is considered 
    // an update, which is where the confusion sets in
    // there are other methods, like checking time or post status
    // depending on your use case it might be more appropriate 
    // to use one of those alternatives 
    //die();
  }

  echo '</pre>';
  //die();
}
Nicolai
sumber
3
The $updateparameter adalah selalu benar bahkan ketika itu adalah posting baru. Jadi parameter ini tidak berguna. Tidak yakin apakah itu pernah berhasil sama sekali, tetapi pasti tidak berfungsi seperti yang didokumentasikan dalam versi terbaru dari wordpress 4.8.
Solomon Closson
@ SolomonClosson Jika Anda melihat wp_publish_post, maka ya. Tapi itu tidak benar untuk penggunaannya wp_insert_post. Saya telah menulis fungsi debug, saya menambahkannya ke jawabannya.
Nicolai
@ SolomonClosson Jika Anda memiliki masalah nyata yang sebenarnya, silakan ajukan pertanyaan baru. Lihatlah revisi untuk fungsi debug penjelasan.
Nicolai
The save_postkait memiliki parameter-3 yang selalu diatur ke TRUE, jadi tidak yakin apa ini ada hubungannya dengan kait lainnya, tidak berbicara tentang kait lainnya. Saya sedang berbicara tentang jawaban Anda. Ini salah.
Solomon Closson
@ SolomonClosson Seperti yang saya katakan, kail muncul dua kali: wp_insert_post(), wp_publish_post(). Yang terakhir hanya posting masa depan, ada $updatediatur untuk selalu true. Kalau tidak, dalam hal wp_insert_post(), $updatetidak selalu true.
Nicolai
11

Cara saya melakukan pemeriksaan ini (dalam fungsi terkait) adalah membandingkan tanggal posting dan tanggal yang dimodifikasi (dalam GMT untuk standarisasi)

function check_new_vs_update( $post_id ){
    $myPost        = get_post($post_id);
    $post_created  = new DateTime( $myPost->post_date_gmt );
    $post_modified = new DateTime( $myPost->post_modified_gmt );

    if( abs( $post_created->diff( $post_modified )->s ) <= 1 ){
        // New post
    }else{
        // Updated post
    }
}
add_action('save_post', 'check_new_vs_update' );

Ini berfungsi karena meskipun pada saat pembuatan posting memiliki tanggal 'dimodifikasi' yang melekat padanya, yang persis sama dengan tanggal 'dibuat', tetapi kami mengizinkan varian 1 detik, jika kedua detik berlalu selama pembuatan pos.

James Cushing
sumber
1
Terkadang post_date_gmtis 2019-03-12 01:31:30dan the post_modified_gmtis 2019-03-12 01:31:31. :(
He Yifei 何 一 非
1
@HeYifei 何 一 非 poin yang bagus, jika pemrosesan dimulai pada akhir detik yang diberikan, ini bisa terjadi. Saya telah memperbarui jawaban saya, terima kasih
James Cushing
Guys, hanya sebuah info. Kait dipecat saat memulihkan dan menghapus sebuah pos.
melvin
6

Saya akhirnya hanya memeriksa keberadaan nilai khusus sebelum menyetelnya. Dengan begitu, jika itu adalah kiriman yang baru dibuat, nilai khusus belum akan ada.

function attributes_save_postdata($post_id) {
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
  if (!wp_verify_nonce($_POST['_attributes_noncename'], plugin_basename(__FILE__))) return;
  if ('page' == $_POST['post_type']) {
    if (!current_user_can('edit_page', $post_id)) return;
  } else {
    if (!current_user_can('edit_post', $post_id)) return;
  }
  $termid = get_post_meta($post_id, '_termid', true);
  if ($termid != '') {
    // it's a new record
    $termid = 'update';
  } else {
    // it's an existing record
  }
  update_post_meta($post_id, '_termid', $termid);
}
add_action('save_post', 'attributes_save_postdata');
hereswhatidid
sumber
Agar ini berfungsi, apakah Anda harus terlebih dahulu membuat bidang khusus menggunakan add_post_meta?
MF1
Per Codex: [update_post_meta] dapat digunakan sebagai pengganti fungsi add_post_meta (). codex.wordpress.org/Function_Reference/update_post_meta
hereswhatidid
Ini mungkin gagal, jika posting dibuat sebelum kait kode diaktifkan melalui aktivasi plugin. Posting lama tidak memiliki set meta, maka pembaruan pertama untuk mereka akan dianggap sebagai baru.
Vasu Chawla
4

Contoh jawaban ialocin dengan paremeter "perbarui":

function save_func($ID, $post,$update) {

   if($update == false) {
     // do something if its first time publish
   } else {
     // Do something if its update
   }
}

add_action( 'save_post', 'save_func', 10, 3 );
Goran Jakovljevic
sumber
2
Cara yang lebih baik untuk membuat struktur ini adalah dengan menempatkan blok pembaruan terlebih dahulu, memungkinkan untuk hanya melakukan if($update)atau menjaga blok baru terlebih dahulu tetapi menggunakan if( ! $update ). Yang terakhir akan mendapatkan OP menjadi praktik yang lebih baik dan lebih disukai daripada metode Anda dengan standar pengkodean WordPress dalam kasus-kasus seperti operator ternary
James Cushing
1

Anda dapat menggunakan kait tindakan pre_post_update untuk kode pembaruan dan save_post untuk kode posting baru. Ini berfungsi sebelum sebuah posting diperbarui.

Darshan Thanki
sumber
4
save_posthook dipecat baik ketika posting dibuat dan diperbarui (setelah WordPress telah disimpan ke database). pre_post_updatedipecat ketika posting diperbarui, tetapi sebelum posting diperbarui - ini bisa menjadi penting.
Stephen Harris
1

Seperti Darshan Thanki mengisyaratkan (dan Stephen Harris lebih lanjut diuraikan), Anda dapat menggunakan pre_post_updateuntuk keuntungan Anda.

global $___new_post;
$___new_post = true;

add_action(
  'pre_post_update',
  function() {
    global $___new_post;
    $___new_post = false;
  },
  0
);

function is_new_post() {
  global $___new_post;
  return $___new_post;
}

Alasan mengapa saya menggunakan global adalah karena function is_new_post() use ( &$new_post )tidak valid dalam PHP (mengejutkan ...) jadi menarik variabel itu ke dalam lingkup fungsi tidak berfungsi - maka global.

Perhatikan bahwa ini benar-benar hanya dapat digunakan secara andal di dalam / setelah save_postacara (yang biasanya cukup, setidaknya untuk apa yang kita lakukan dengannya).

Qix
sumber
0

Ketika save_post dipicu, semua informasi tentang pos itu sudah tersedia, jadi secara teori Anda bisa menggunakan

function f4553265_check_post() {

    if (!get_posts($post_id)) {
    // if this is a new post get_posts($post_id) should return null
    } else {
    // $post_id already exists on the database
    }
}
add_action('save_post','f4553265_check_post');

ini belum teruji. =)

moraleida
sumber
3
Pada saat Anda sampai ke save_postpos itu sendiri sudah disimpan ke database - demikian juga get_postsakan mengembalikan pos saat ini.
Stephen Harris
Benar, baru saja memeriksanya di Codex. Terimakasih atas peringatannya.
moraleida
0

Pendekatan lain yang menggunakan fungsi built-in dan tidak ada penambahan ke database akan melibatkan get_post_status().

$post_status = get_post_status();
if ( $post_status != 'draft' ) {
    //draft
} else { 
    //not a draft: can be published, pending, etc. 
}

Namun perhatikan bahwa mungkin tidak tepat jika Anda berencana untuk mengatur kembali status ke "draft" nanti - instruksi Anda akan diulangi saat berikutnya Anda akan memperbarui posting. Tergantung pada konteksnya, Anda mungkin ingin mempertimbangkan berbagai string yang dapat dikembalikan dengan get_post_status()membangun skenario yang lebih tepat.

Lihat Codex untuk get_post_status () dan Status Posting

Nilai yang mungkin adalah:

  • 'publish' - Posting atau halaman yang dipublikasikan
  • 'tertunda' - pos adalah peninjauan tertunda
  • 'draft' - posting dalam status draft
  • 'auto-draft' - posting yang baru dibuat, tanpa konten
  • 'masa depan' - sebuah posting untuk diterbitkan di masa depan
  • 'pribadi' - tidak terlihat oleh pengguna yang tidak masuk
  • 'mewarisi' - sebuah revisi. lihat get_children.
  • 'trash' - pos ada di trashbin. ditambahkan dengan Versi 2.9.
John112
sumber
Saya tidak berpikir ini melakukan apa yang diminta. Jika saya membuat posting baru dan kemudian tekan 'Terbitkan', save_post()dieksekusi untuk pertama kalinya, tetapi selama eksekusi get_post_status()sudah kembali 'terbitkan' dan bukan 'draft', meskipun itu hanya dalam proses penerbitan.
cgogolin