Verifică actualizarea vs postare nouă în acțiunea save_post
Este posibil ca în cadrul acțiunii save_post să determini dacă este vorba despre o postare nouă în curs de creare sau despre o postare existentă care este actualizată?

Începând cu versiunea 3.7 a WordPress - dacă îmi amintesc corect - hook-ul save_post
- mai multe informații despre acest hook și utilizarea lui la Code Reference: save_post
și Codex: save_post
- are un al treilea parametru $update
care poate fi folosit pentru a determina exact acest lucru.
@param int $post_ID ID-ul postului.
@param WP_Post $post Obiectul post.
@param bool $update Indică dacă acesta este un post existent care este actualizat sau nu.
Notă:
$update
nu este întotdeauna true
– puteți vedea și testa acest lucru singur cu codul de mai jos. Totuși, acest lucru nu este bine documentat, poate denumit departe de a fi optim și, prin urmare, creează așteptări înșelătoare. Codul de mai jos poate fi folosit pentru depanare, experimentați cu momentul în care să interceptați execuția codului, altfel nu veți vedea informațiile/mesajele. Cred că problema în comportamentul înșelător este gestionarea reviziilor și salvărilor automate – care ar putea fi dezactivate, dar nu recomand acest lucru și nu l-am testat. Nu sunt sigur dacă acest lucru merită un Trac Ticket, așa că nu am deschis unul, dacă credeți că da, vă rugăm să accesați linkul și să faceți-o voi înșivă. În afară de asta, așa cum se menționează în comentarii, dacă aveți o problemă specifică, postați o nouă întrebare.
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';
//condiții
if( ! $update && $post->post_status == "auto-draft" ) {
// se aplică la un post nou
echo ' && $post->post_status == "auto-draft"';
//die();
} else if ( ! $update ) {
// se aplică în principiu la revizia (salvată automat)
//die();
} else {
// se aplică la actualizarea unui post publicat
// când există o revizie, ceea ce este în mod normal cazul,
// comportamentul standard al WordPress, atunci este considerată
// o actualizare, ceea ce este punctul în care apare confuzia
// există alte metode, cum ar fi verificarea timpului sau a stării postului
// în funcție de cazul dumneavoastră specific, ar putea fi mai potrivit
// să folosiți una dintre acele alternative
//die();
}
echo '</pre>';
//die();
}

Parametrul $update
este ÎNTOTDEAUNA adevărat chiar și atunci când este un post nou. Deci acest parametru este inutil. Nu sunt sigur dacă a funcționat vreodată, dar cu siguranță nu funcționează așa cum este documentat în cea mai recentă versiune de WordPress 4.8.

@SolomonClosson Dacă te uiți la wp_publish_post
, atunci da. Dar acest lucru nu este valabil pentru utilizarea sa în wp_insert_post
. Am scris o funcție de depanare, o adaug în răspuns.

@SolomonClosson Dacă ai o problemă concretă actuală, te rog să pui o nouă întrebare. Aruncă o privire la reviziile pentru funcția de depanare pentru o explicație.

Hook-ul save_post
are un al treilea parametru care este întotdeauna setat la TRUE, deci nu sunt sigur ce legătură are cu alte hook-uri, fără să vorbim despre alte hook-uri. Mă refer la hook-ul din răspunsul tău. Acest lucru este incorect.

@SolomonClosson După cum am spus, hook-ul apare de două ori:
wp_insert_post()
, wp_publish_post()
. Ultimul este doar pentru postări programate, acolo $update
este întotdeauna setat la true
. În ceea ce privește wp_insert_post()
, $update
nu este întotdeauna true
.

Am întârziat la petrecere, dar hei, de ce nu, @Nicolai, ceea ce spui este ceea ce s-ar aștepta să se întâmple, dar nu pot obține ca $update să fie false chiar și atunci când mă conectez la 'wp_insert_post'. Indiferent unde mă conectez, este întotdeauna true. Nu înțeleg de ce nu este rezolvat acest lucru.

Modul în care efectuez această verificare (în cadrul unei funcții hook) este să compar data postării cu data modificării (în GMT pentru standardizare)
function check_new_vs_update( $post_id ){
$myPost = get_post($post_id);
$created = new DateTime( $myPost->post_date_gmt );
$modified = new DateTime( $myPost->post_modified_gmt );
$diff = $created->diff( $modified );
$seconds_difference = ((($diff->y * 365.25 + $diff->m * 30 + $diff->d) * 24 + $diff->h) * 60 + $diff->i)*60 + $diff->s;
if( $seconds_difference <= 1 ){
// Postare nouă
}else{
// Postare actualizată
}
}
add_action('save_post', 'check_new_vs_update' );
Această metodă funcționează deoarece chiar și la creare, postarea are o dată 'modificată' atașată, care este exact aceeași cu data 'creării', dar permitem o variație de 1 secundă în cazul în care o secundă trece în timpul creării postării.

Uneori post_date_gmt
este 2019-03-12 01:31:30
iar post_modified_gmt
este 2019-03-12 01:31:31
. :(

@HeYifei何一非 bun punct, dacă procesarea începe la sfârșitul unei anumite secunde, acest lucru s-ar putea întâmpla. Am actualizat răspunsul meu, mulțumesc

Băieți, doar o informație. Hook-ul este declanșat la restaurarea și ștergerea unui post.

Nu pot să cred că trebuie să fie atât de complicat. WordPress nu încetează să mă uimească.

Ca să fim corecți, ei au literalmente milioane de utilizatori și este un proiect open-source. Din păcate, nu pot include fiecare funcționalitate și aceasta probabil nu este una dintre cele mai utilizate. În ultimii ani, lucruri precum îmbunătățirea editorului și securitatea au fost prioritizate și asta e bine! Adică, până și jQuery abia acum este actualizat! Până la versiunea actuală, rulează încă 1.x!

Am ales să verific pur și simplu existența unei valori personalizate înainte de a o seta. În acest fel, dacă este un post nou creat, valoarea personalizată nu ar exista încă.
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 != '') {
// este o înregistrare nouă
$termid = 'update';
} else {
// este o înregistrare existentă
}
update_post_meta($post_id, '_termid', $termid);
}
add_action('save_post', 'attributes_save_postdata');

Pentru ca aceasta să funcționeze, trebuie mai întâi să creezi câmpul personalizat folosind add_post_meta?

Conform Codex: [update_post_meta] poate fi folosit în locul funcției add_post_meta(). http://codex.wordpress.org/Function_Reference/update_post_meta

Aceasta ar putea eșua dacă postările au fost create înainte ca codul să fie activat prin intermediul unei activări de plugin. Postările mai vechi nu au meta setat, deci prima actualizare pentru ele va fi considerată ca una nouă.

Exemplu de răspuns pentru ialocin cu parametrul "update":
function save_func($ID, $post,$update) {
if($update == false) {
// faci ceva dacă este prima publicare
} else {
// Faci ceva dacă este o actualizare
}
}
add_action( 'save_post', 'save_func', 10, 3 );

O modalitate mai bună de a structura acest lucru ar fi fie să plasați blocul de actualizare primul, permițând să faceți doar if($update)
, fie să păstrați blocul nou primul, dar folosind if( ! $update )
. Ultima variantă va încuraja practici mai bune și este preferată în locul metodei dumneavoastră conform standardelor de codare WordPress în cazuri precum operatorul ternar

Am întâlnit recent hook-ul save_post
legat de crearea și actualizarea postărilor. După ce am citit codul sursă pentru a înțelege fluxul, am descoperit că următoarea metodă ar putea fi utilă. Deoarece nu a fost menționată anterior, o împărtășesc în caz că ar fi de folos cuiva. (Testat pe versiunea WordPress 5.3.3)
Fluxul de creare a unei postări este aproximativ:
- După apăsarea butonului "Adaugă nou" (Postare)
- Se apelează
$post = get_default_post_to_edit( $post_type, true );
unde get_default_post_to_edit()
primește argumentul$create_in_db = true
- astfel
wp_insert_post()
este apelat imediat, se creează o postareauto-draft
, chiar dacă nu este salvată. De fiecare dată când se apasăAdaugă nou
, se creează unauto-draft
$update
este întotdeaunatrue
pentru publicare. Deci, când se publică o postare nouă, valoarea estetrue
.
Comparând obiectul $_POST pentru o postare nouă și una actualizată sau republicată, diferența evidentă este valoarea _wp_http_referer
. Pentru postările noi, valoarea este /wp-admin/post-new.php
.
Presupunere: se presupune că postarea este publicată/adaugată din interfața de utilizator. Dacă acest lucru se face prin alte mecanisme sau cod personalizat, verificarea trebuie ajustată corespunzător.
add_action( 'save_post', 'test_save_post_check', 0, 3 );
function test_save_post_check( $post_ID, $post, $update ) {
// alte verificări + aceasta
// verificarea prezenței 'post-new' în '_wp_http_referer'
if( strpos( wp_get_raw_referer(), 'post-new' ) > 0 ) {
// postare nouă
} else {
// actualizare
}
}

aici este un cod funcțional pe care l-am testat și l-am folosit pe site-ul meu, care rezolvă următoarele două probleme asociate cu acțiunea save_post:
problema de a verifica între actualizare sau inserare
problema inserării de două ori prin acțiunea save_post
function save_annonces_callback($post_ID, $post, $update){ $post_type = get_post_type($post_ID); if ( $post_type === 'annonces' ){ //acest lucru previne inserarea de două ori prin acțiunea save_post :) if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) { return; } else { //verifică dacă este un post nou, deci inserează if( strpos( wp_get_raw_referer(), 'post-new' ) > 0 ){ //efectuează inserarea }else{ //efectuează actualizarea } } } }add_action('save_post','save_annonces_callback', 10, 3);

Hook-ul save_post
este declanșat atât când un articol este creat, cât și când este actualizat (după ce WordPress l-a salvat în baza de date). Hook-ul pre_post_update
este declanșat când un articol este actualizat, dar înainte ca articolul să fie actualizat - acest lucru poate fi important.

După cum a sugerat Darshan Thanki (și Stephen Harris a dezvoltat în continuare), puteți utiliza pre_post_update
în avantajul vostru.
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;
}
Motivul pentru care am folosit variabile globale este pentru că function is_new_post() use ( &$new_post )
nu este valid în PHP (șocant...) așa că includerea acelei variabile în scope-ul funcției nu funcționează -- de aceea am folosit global.
Rețineți că această soluție poate fi folosită în mod fiabil doar în cadrul sau după evenimentul save_post
(ceea ce este de obicei suficient, cel puțin pentru ceea ce facem noi cu ea).

Când acțiunea save_post este declanșată, toate informațiile despre acel articol sunt deja disponibile, așa că teoretic ai putea folosi
function f4553265_check_post() {
if (!get_posts($post_id)) {
// dacă acesta este un articol nou, get_posts($post_id) ar trebui să returneze null
} else {
// $post_id există deja în baza de date
}
}
add_action('save_post','f4553265_check_post');
această soluție nu a fost testată, totuși. =)

Până când ajungi la save_post
, postarea în sine ar fi deja salvată în baza de date - deci get_posts
ar returna postarea curentă.

Adevărat, tocmai am verificat în Codex. Mulțumesc pentru informație.

O altă abordare care folosește o funcție încorporată și nu necesită adăugări în baza de date ar implica get_post_status()
.
$post_status = get_post_status();
if ( $post_status != 'draft' ) {
//schiță
} else {
//nu este o schiță: poate fi publicat, în așteptare, etc.
}
Totuși, rețineți că poate să nu fie potrivit dacă intenționați să setați ulterior starea înapoi la "draft" - instrucțiunile dvs. vor fi repetate data viitoare când veți actualiza postarea.
În funcție de context, s-ar putea să doriți să luați în considerare diferitele șiruri returnate de get_post_status()
pentru a construi un scenariu mai potrivit.
Consultați Codex pentru get_post_status() și Starea Postării
Valorile posibile sunt:
- 'publish' - O postare sau pagină publicată
- 'pending' - postarea așteaptă moderare
- 'draft' - o postare în stadiu de schiță
- 'auto-draft' - o postare nou creată, fără conținut
- 'future' - o postare programată pentru publicare în viitor
- 'private' - nu este vizibilă pentru utilizatorii nelogati
- 'inherit' - o revizie. vezi get_children.
- 'trash' - postarea este în coșul de gunoi. adăugat începând cu Versiunea 2.9.

Nu cred că această funcționalitate face ceea ce s-a cerut. Dacă creez un articol nou și apoi apăs 'Publică', funcția save_post()
este executată pentru prima dată, dar în timpul acelei execuții get_post_status()
returnează deja 'publish' și nu 'draft', chiar dacă articolul este încă în procesul de publicare.

Deoarece parametrul $update
este inutil, acesta este cel mai rapid mod pe care l-am testat:
function wpse48678_check_is_post_new($post_id, $post, $update)
{
if (false !== strpos($_POST['_wp_http_referer'], 'post-new.php')) {
return true; // Sau fă altceva.
} else {
return false; // Sau fă altceva.
}
}
add_action('save_post_{$post_type}', 'wpse48678_check_is_post_new', 10, 3);

Am petrecut ore întregi pe asta
În prezent sunt în procesul de dezvoltare a unui plugin și am vrut să trimit o notificare tuturor autorilor atunci când o pagină era "Creată" pe site-ul companiei mele de Web Design.
Inițial am încercat să folosesc următoarele:
add_action('save_post_page', function($post_id, $post, $update) {
if(!$update){
echo("Este un post nou!");
}else{
echo("Este un post vechi!");
}
}
Continuam să afișeze "Este un post vechi!". Dar de ce??? După ce am cercetat, am aflat că după ce apeși butonul "Adaugă Pagină Nouă", WordPress creează instantaneu un auto-draft care setează variabila $update la true. Cât de util.
După ore de cercetare, am găsit în sfârșit următoarea soluție care funcționează:
// Se declanșează când un post își schimbă "statusul", de ex. din pending în draft, publicat în programat.
add_action('transition_post_status', function($new_status, $old_status, $post) {
// Verifică dacă postul trece de la auto-draft la orice alt status (draft, pending, publish, etc.)
if 'auto-draft' === $old_status && $new_status !== 'auto-draft'){
echo("Este un post nou!");
}else{
echo("Este un post vechi!");
}
}
Notă: În WordPress, "draft" și "auto-draft" sunt diferite. Un status "draft" este un post pe care utilizatorul îl setează manual ca draft, indicând faptul că este în lucru. Pe de altă parte, "auto-draft" este atribuit automat unui post atunci când este creat dar încă nepublicat. Practic, un alt mod de a spune auto-salvare.
Sper că acest lucru va ajuta câteva persoane... E timpul să mai petrec încă 4 ore pe o altă problemă haha.

Ar trebui să funcționeze, băieți
add_action( 'wp_after_insert_post', 'clearCDNCache', 10, 4);
public function clearCDNCache($post_id, $post, $update, $post_before){
if ( ! empty($_POST['_wpnonce']) ) {
// Execută funcția personalizată doar o dată
}
// Adaugă un nou mod
if (!empty($_POST['_wp_http_referer']) && $_POST['_wp_http_referer'] == '/wp-admin/post-new.php') {
} else {
// Modul de actualizare
}
}
