Sprawdź aktualizację vs nowy post w akcji save_post

21

Czy w ramach akcji save_post można ustalić, czy jest to nowy post, czy istniejący wpis jest aktualizowany?

hereswhatidid
źródło
Nie sądzę, żeby to było możliwe. Zobacz mój komentarz poniżej odpowiedzi @ moraleida. Dlaczego musisz wiedzieć, czy jest to nowy post, czy jest aktualizowany? Może istnieć obejście lub alternatywne podejście.
Stephen Harris

Odpowiedzi:

16

Od wersji WordPress 3.7. - IIRC - save_posthook - więcej informacji na temat hooka i jego wykorzystania w Code Reference:save_post i Codex:save_post - ma trzeci parametr, $updatektórego można użyć do określenia właśnie tego.

@param int $ post_ID Identyfikator postu.
@param WP_Post $ post Obiekt obiektu.
@param bool $ update Czy jest to istniejący wpis jest aktualizowany, czy nie.


Uwaga:

$updatenie zawsze true- możesz to zobaczyć i przetestować samodzielnie za pomocą poniższego kodu. Nie jest to jednak dobrze udokumentowane, być może dalekie od optymalnej nazwy, a zatem stwarza mylące oczekiwania. Poniższy kod może być użyty do debugowania, pobaw się, kiedy przechwycić wykonanie kodu, ponieważ w przeciwnym razie nie zobaczysz informacji / komunikatów. Myślę, że winowajcą jest zachowanie poprawek i automatycznych zapisów - które można wyłączyć, ale nie polecam go i nie przetestowałem. Nie jestem pewien, czy to uzasadnia bilet Trac , więc nie otworzyłem go, jeśli tak uważasz, skorzystaj z linku i zrób to sam. Oprócz tego, jak stwierdzono w komentarzach, jeśli masz konkretny problem, opublikuj nowe pytanie.

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
źródło
3
Ten $updateparametr jest ZAWSZE prawdziwy, nawet jeśli jest to nowy post. Ten parametr jest więc bezużyteczny. Nie jestem pewien, czy kiedykolwiek w ogóle działało, ale na pewno nie działa tak, jak zostało to udokumentowane w najnowszej wersji wordpress 4.8.
Solomon Closson
@ SolomonClosson Jeśli spojrzysz na to wp_publish_post, to tak. Ale to nie dotyczy jego użycia w wp_insert_post. Napisałem funkcję debugowania, dodaję ją do odpowiedzi.
Nicolai
@ SolomonClosson Jeśli masz konkretny konkretny problem, zadaj nowe pytanie. Spójrz na wersje dla funkcji debugowania wyjaśnienie.
Nicolai
save_postHak ma 3rd parametr, który jest zawsze ustawiony na true, więc nie wiem, co to ma wspólnego z innymi haki, nie mówiąc o innych haków. Mówię o haczyku w twojej odpowiedzi. To jest niepoprawne.
Solomon Closson
@ SolomonClosson Jak powiedziałem, hak występuje dwa razy: wp_insert_post(), wp_publish_post(). Ten ostatni to tylko przyszłe posty, $updatezawsze będzie true. W przeciwnym razie, w odniesieniu do wp_insert_post(), $updatenie zawsze tak jest true.
Nicolai
11

Sposób, w jaki przeprowadzam to sprawdzenie (w ramach funkcji przechwyconej) polega na porównaniu daty publikacji i daty modyfikacji (w GMT w celu standaryzacji)

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

Działa to, ponieważ nawet podczas tworzenia postu jest do niego dołączona data „zmodyfikowana”, która jest dokładnie taka sama jak data „utworzona”, ale dopuszczamy odchylenie 1 sekundy w obu kierunkach, w przypadku gdy sekunda tyka podczas tworzenia Poczta.

James Cushing
źródło
1
Czasami post_date_gmtjest 2019-03-12 01:31:30i post_modified_gmtjest 2019-03-12 01:31:31. :(
He Yifei 何 一 非
1
@HeYifei 非 一 非 dobry punkt, jeśli przetwarzanie rozpocznie się pod koniec danej sekundy, może się to zdarzyć. Zaktualizowałem swoją odpowiedź, dzięki
James Cushing
Chłopaki, tylko informacja. Hak jest uruchamiany podczas przywracania i usuwania postu.
melvin
6

Skończyło się na sprawdzeniu istnienia niestandardowej wartości przed jej ustawieniem. W ten sposób, jeśli jest to nowo utworzony post, wartość niestandardowa jeszcze nie istniałaby.

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
źródło
Aby to zadziałało, czy musisz najpierw utworzyć pole niestandardowe za pomocą add_post_meta?
MF1
Zgodnie z kodeksem: [update_post_meta] może być użyte zamiast funkcji add_post_meta (). codex.wordpress.org/Function_Reference/update_post_meta
hereswhatidid
Może się to nie powieść, jeśli posty zostały utworzone przed włączeniem haka do kodu poprzez aktywację wtyczki. Starsze posty nie mają ustawionego meta, dlatego pierwsza aktualizacja dla nich zostanie uznana za nową.
Vasu Chawla
4

Przykład odpowiedzi na ialocin za pomocą paremetera „update”:

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
źródło
2
Lepszym sposobem na ustrukturyzowanie tego byłoby albo umieszczenie bloku aktualizacji na pierwszym miejscu, pozwalając na zrobienie if($update)lub utrzymanie nowego bloku na pierwszym miejscu, ale użycie if( ! $update ). Ta ostatnia wprowadzi OP do lepszej praktyki i jest preferowana w stosunku do twojej metody przez standardy kodowania WordPress w przypadkach takich jak operator trójskładnikowy
James Cushing,
1

Możesz użyć haka akcji pre_post_update dla kodu aktualizacji i save_post dla nowego kodu pocztowego. Działa przed aktualizacją posta.

Darshan Thanki
źródło
4
save_posthook jest uruchamiany zarówno po utworzeniu, jak i aktualizacji posta (po zapisaniu go przez WordPress w bazie danych). pre_post_updatejest uruchamiany, gdy post jest aktualizowany, ale przed aktualizacją postu - może to być ważne.
Stephen Harris,
1

Jak podpowiedział Darshan Thanki (a Stephen Harris dalej rozwijał), możesz skorzystać pre_post_updatena swoją korzyść.

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

Powodem, dla którego użyłem globałów jest to, że function is_new_post() use ( &$new_post )nie jest poprawne w PHP (szokujące ...), więc wciągnięcie tej zmiennej do zakresu funkcji nie działa - stąd globalne.

Zauważ, że tak naprawdę można to niezawodnie wykorzystać tylko w / po save_postzdarzeniu (co zwykle jest wystarczające, przynajmniej do tego, co robimy).

Qix
źródło
0

Po uruchomieniu save_post wszystkie informacje o tym poście są już dostępne, więc teoretycznie możesz ich użyć

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

jest to jednak niesprawdzone. =)

moraleida
źródło
3
Zanim dotrzesz do save_postsamego posta, byłby on już zapisany w bazie danych - get_postszwróci więc bieżący post.
Stephen Harris
To prawda, właśnie sprawdziłem to w Kodeksie. Dzięki za zgłoszenie się.
moraleida,
0

Inne podejście, które wykorzystuje wbudowaną funkcję i nie wymaga dodawania do bazy danych get_post_status().

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

Pamiętaj jednak, że może nie być właściwe, jeśli planujesz później przywrócić status „szkic” - instrukcje zostaną powtórzone przy następnej aktualizacji posta. W zależności od kontekstu warto rozważyć różne ciągi znaków, które mogą zostać zwrócone, get_post_status()aby zbudować bardziej odpowiedni scenariusz.

Zobacz Codex dla get_post_status () i Statusu Postu

Możliwe wartości to:

  • „opublikuj” - opublikowany post lub strona
  • „w toku” - wpis oczekuje na sprawdzenie
  • „projekt” - post w stanie roboczym
  • „auto-draft” - nowo utworzony post, bez zawartości
  • „przyszłość” - post do opublikowania w przyszłości
  • „prywatny” - niewidoczny dla użytkowników, którzy nie są zalogowani
  • „dziedziczenie” - wersja. patrz get_children.
  • „kosz” - post znajduje się w koszu. dodano w wersji 2.9.
John112
źródło
Nie sądzę, że robi to, o co proszono. Jeśli utworzę nowy post, a następnie kliknę przycisk „Publikuj”, save_post()jest wykonywany po raz pierwszy, ale podczas tego wykonania jest get_post_status()już zwracany komunikat „publikuj”, a nie „wersja robocza”, nawet jeśli jest on dopiero publikowany.
cgogolin,