Hook add_action per post completamente nuovi?

1 feb 2011, 07:47:33
Visualizzazioni: 43.1K
Voti: 22

publish_post viene eseguito quando un post viene pubblicato, o se viene modificato e il suo stato è "pubblicato". Argomenti della funzione action: ID del post.

-Documentazione API Plugin

Ho aggiunto l'hook publish_post a un plugin WordPress che sto scrivendo. La funzione chiamata dall'hook dovrebbe modificare le categorie di diversi post utilizzando la funzione wp_update_post.

Tuttavia questo hook non funziona poiché il risultato restituito dall'esecuzione di wp_update_post è sempre 0. La mia ipotesi è che l'esecuzione di wp_update_post causi un'altra istanza del mio hook perché ripubblica il post... il che credo porti alla condizione "...o se viene modificato e il suo stato è 'pubblicato'" della dichiarazione sopra.

Esiste un altro action-hook che posso utilizzare che verrà chiamato solo quando il post aggiunto è completamente nuovo e non modificato?

<?php
/* 
Plugin Name: Plugin Cambio Categorie 
Plugin URI: http://www.example.com
Description: Quando viene creato un nuovo post questo plugin causerà il
Version: 0.1
Author: Me
License: GPL2 
?>
<?php
class categoryShifter {
  function shiftCategories($post_ID) {

    $maxNumPostsFirstTeir = 4;

    $first_teir_cat = "Notizie Fresche 1";
    $second_teir_cat = "Notizie Datate 2";  

    $firephp = FirePHP::getInstance(true);

    $firephp->info('INIZIO: categoryShifter.shiftCategories()');

    $firephp->log($post_ID, 'post_ID: ');
    $firephp->trace('traccia fino a qui');    

    $first_teir_id = categoryShifter::getIDForCategory($first_teir_cat, $firephp); 
    $second_teir_id = categoryShifter::getIDForCategory($second_teir_cat, $firephp);

    $firephp->log($first_teir_id, '$first_teir_id');
    $firephp->log($second_teir_id, '$second_teir_id');   

    $qPostArgs = array(
      'numberposts' => 100,
      'order' => 'DESC', 
      'orderby' => 'post_date',
      'post_type' => 'post',
      'post_status' => 'published', 
      'category_name' => $first_teir_cat
    );

    $firstTeirPosts = get_posts($qPostArgs);   
    $firephp->log($firstTeirPosts, 'post ottenuti:');

    $firephp->log(sizeof($firstTeirPosts), 'dimensione');


    // NOTA: Questo sembra funzionare.
    for($i = sizeof($firstTeirPosts)-1; $i > $maxNumPostsFirstTeir-4; $i--) 
    {
      $newCats = array($second_teir_id);
      $editingId = $firstTeirPosts->ID;
      $result = wp_set_post_categories($editingId, $newCats); /* NOTA: Non funziona attualmente... restituisce un array con $second_teir_id al suo interno. */
      $firephp->log($result, 'Risultato'); 
    }

    /*
    $my_post = array();
    $my_post['ID'] = 132;
    $my_post['post_category'] = array($second_teir_id);


    $firephp->log('Prima', 'Prima'); 
    if(wp_update_post( $my_post ) == 0) {
        $firephp->Error('Errore Fatale, Post non aggiornato', 'errore');
    }
    $firephp->log('Dopo', 'Dopo');
    */
    return $post_ID;
  }


  function getIDForCategory($cat_name, $logger) {
    $logger->Info("Inizio: getIDForCategory()");

    $cats = get_categories();      

    $whichCatId = "";

    foreach($cats as $single_cat) {
      if($single_cat->name == $cat_name) {
       $whichCatId = $single_cat->term_id;
       break;
      }
    }
    $logger->Info("Fine: getIDForCategory()");
    return (int)$whichCatId;
  }
}

/* Hook Creazione Post */
/* add_action('publish_post', array('categoryShifter','shiftCategories')); */
add_action('wp_insert_post', array('categoryShifter', 'shiftCategories'));
?>

Per il momento sono passato all'utilizzo dell'hook wp_insert_post... ma ancora non riesco a far funzionare la funzione wp_set_post_categories per modificare le categorie dei post.

Capisco che probabilmente dovrò aggiornare questo codice in modo che tenga conto delle categorie esistenti del post e modifichi solo quelle specificate dal plugin, ma per ora è davvero solo una versione alfa.

4
Commenti

@leeand00 - Puoi pubblicare il tuo codice come aggiornamento alla tua risposta così possiamo vedere meglio cosa necessita di correzione?

MikeSchinkel MikeSchinkel
1 feb 2011 07:49:24

@Mike Ecco l'aggiornamento!

leeand00 leeand00
1 feb 2011 08:12:22

@MikeSchinkel A volte è solo perché non ho ancora avuto la possibilità di provare le risposte, e non volevo segnare una che non fosse una buona risposta... ma tornerò indietro e vedrò cosa posso fare!

leeand00 leeand00
1 feb 2011 18:28:44

@MikeSchinkel Ok, li ho sistemati e ho selezionato le risposte migliori, scusa per questo, non mi ero reso conto di come avevo trascurato questo StackExchange in particolare.

leeand00 leeand00
1 feb 2011 18:34:37
Tutte le risposte alla domanda 6
4
22
// Azioni di WordPress che attivano 'your_function' quando uno stato post cambia in "pubblicato"
add_action('new_to_publish', 'your_function');     // Da nuovo a pubblicato
add_action('draft_to_publish', 'your_function');   // Da bozza a pubblicato
add_action('pending_to_publish', 'your_function'); // Da in attesa a pubblicato
1 feb 2011 08:50:56
Commenti

Che ne dici dell'azione wp_insert_post? http://core.trac.wordpress.org/browser/tags/3.3.1/wp-includes/post.php#L2656

soulseekah soulseekah
23 mar 2012 11:56:58

Ma queste verranno eseguite di nuovo se, ad esempio, lo stato viene cambiato da pubblicato a bozza e poi nuovamente a pubblicato?

brandonjp brandonjp
27 lug 2019 19:07:05

@soulseekah L'hook wp_insert_post verrà chiamato nuovamente quando modifichi un post esistente e lo salvi. Testato su WordPress 5.9. So che il tuo commento è del 2012 ma nel caso qualcuno fosse curioso a riguardo.

vee vee
1 feb 2022 08:32:59

@vee, probabilmente le bozze vengono create ad ogni salvataggio.

soulseekah soulseekah
2 feb 2022 10:43:11
2
22

Ho letto approfonditamente il core di WordPress e ho provato tutto. wp_transition_post_status(), new_to_publish(), new_{post_type}(), wp_insert_post().

Tutti questi, alla fine, sono inaffidabili.

wp_transition_post_status() non è affidabile perché il nuovo stato "publish" è lo stato predefinito sia per la creazione di nuovi post che per l'aggiornamento di quelli esistenti. Lo stato precedente non è affidabile per definire cosa è un nuovo post e cosa non lo è perché può essere draft, auto-draft, publish, ecc.

new_to_publish() non funziona per i custom post type.

new_{post_type} passa solo $post come parametro, e non puoi sapere se è nuovo o un aggiornamento di uno esistente

wp_insert_post() ha un parametro $update che dovrebbe essere TRUE se si stanno aggiornando post esistenti e FALSE se si stanno creando nuovi post, ma è inaffidabile perché restituisce TRUE per i nuovi post a causa di auto-draft.

Soluzione: Utilizzo di un post meta

Alla fine ho utilizzato un post meta personalizzato che ho chiamato check_if_run_once che eseguirà una certa logica solo una volta:

/**
*   Fai qualcosa quando viene creato un nuovo libro
*/
function new_book($post_id, $post, $update) {
    if ( $post->post_type == 'book' && $post->post_status == 'publish' && empty(get_post_meta($post_id, 'check_if_run_once')) ) {
        # Nuovo Post

        # Fai qualcosa qui...

        # E aggiorna il meta così non verrà eseguito di nuovo
        update_post_meta( $post_id, 'check_if_run_once', true );
    }
}
add_action( 'wp_insert_post', 'new_book', 10, 3 );

Opzionalmente, se hai bisogno di aggiornare i tuoi post esistenti con il meta "check_if_run_once", in modo che non esegua il codice sopra per i post esistenti creati prima di aver aggiunto quella funzione, potresti fare:

/**
*   Questa è una funzione temporanea per aggiornare i post esistenti con il post meta "check_if_run_once"
*   Accedi al tuo sito loggato come admin e aggiungi ?debug all'URL.
*/
function temporary_function() {
    if (current_user_can('manage_options')) {
        $posts = get_posts(array(
            'post_type' => 'book',
            'posts_per_page' => -1, // Potresti dover paginare questo in base a quanti post hai
            'fields' => 'ids'
        ));
        foreach($posts as $post_id) {
            update_post_meta($post_id, 'check_if_run_once', true);
        }
    }
}
if (isset($_GET['debug'])) {
    add_action('init', 'temporary_function');
}
30 lug 2018 03:50:24
Commenti

Perché questa risposta non ha più voti e non è quella accettata? La risposta accettata non spiega bene le cose e non tiene conto che le persone tendono a usare questo per CPT ecc..

Bram Hammer Bram Hammer
8 lug 2021 21:00:47

Grazie mille, davvero. Che risposta fantastica!

Marco Floriano Marco Floriano
27 feb 2024 16:16:09
0

Precisamente individuare la creazione di un nuovo articolo è in realtà più complicato di quanto sembri. Tecnicamente ci sono diversi modi in cui un articolo può essere creato o aggiornato e ci sono molte cose non così ovvie che tecnicamente sono anche articoli (le revisioni, ad esempio).

WordPress fornisce hook dinamici che tracciano non solo la creazione dell'articolo, ma anche cosa era e cosa è diventato. Vedi Transizioni di Stato degli Articoli nel Codex.

1 feb 2011 08:51:01
4

Più che seguire la documentazione, ho sperimentato e questo funziona per me (WP 3.3). Ricevo una chiamata all'hook transition_post_status con $new_status impostato su "auto-draft" quando creo un nuovo articolo.

function my_post_new($new_status, $old_status=null, $post=null){
    if ($new_status == "auto-draft"){
        // fai qualcosa qui
    }
}
add_action('transition_post_status', 'my_post_new');
23 mar 2012 11:38:50
Commenti

Questo verrà eseguito ogni volta che viene salvato un auto-draft, cioè più o meno ogni minuto durante la modifica.

soulseekah soulseekah
23 mar 2012 11:54:27

Ottimo punto. Nel mio caso non è un problema, ma potrebbe esserlo per altri, a seconda di ciò che si sta facendo.

PapaFreud PapaFreud
23 mar 2012 12:50:24

volevo votare positivamente, ma non posso ancora. quindi i complimenti vanno qui, @PapaFreud. tra l'altro, ora è documentato su http://codex.wordpress.org/Post_Status_Transitions. ancora grazie, amico

Ana Ban Ana Ban
22 mag 2012 15:30:02

@soulseekah Punto interessante che hai sollevato, ho testato questo, e auto-draft viene assegnato come $new_status di un articolo al momento della sua creazione (cioè Aggiungi nuovo), una sola volta. Non appena scatta la prima procedura di AUTOSAVE dopo 1 minuto, il valore di $new_status viene aggiornato a draft. Lo $old_status rimane NULL finché l'articolo non viene salvato manualmente o pubblicato. Quindi tecnicamente questo funzionerebbe e non verrebbe attivato ogni volta che l'editor salva automaticamente il tuo lavoro. Come misura aggiuntiva potresti verificare che lo $old_status sia NULL per confermare -> if ($new_status == "auto-draft" && $old_status === NULL)

Adam Adam
22 mag 2013 16:57:23
0

Ho scoperto che l'opzione migliore è verificare lo stato del post quando viene chiamato wp_insert_post.

Quando un nuovo post viene creato, lo stato iniziale è auto-draft.

if (!function_exists('benyonsFunction')) {
    function benyonsFunction($postId, $post) {
        if ($post->post_status == "auto-draft") {
            error_log('NUOVO POST!!!');
        }
    }
}

add_action('wp_insert_post', 'benyonsFunction', 10, 2);

Questo error_log verrà attivato solo una volta.

5 feb 2020 11:49:20
2

Il modo più pulito e affidabile per gestire questo per un tipo di post conosciuto è utilizzare l'hook {$new_status}_{$post->post_type} che fornisce lo stato precedente e confrontarlo con "publish".

Ad esempio, se vuoi attivare un'azione quando una nuova "pagina" viene creata, useresti:

add_action( 'publish_page', function( int $post_id, \WP_Post $post, string $old_status ) {
    if ( 'publish' === $old_status ) {
        // Niente da fare qui.
        return;
    }
    // La logica di business va qui.
}, 10, 3 );
18 feb 2023 00:46:36
Commenti

No, questo verrà attivato ogni volta che una pagina passa da qualsiasi stato a 'publish', quindi si attiverà molte più volte rispetto alla sola prima creazione.

Christophvh Christophvh
31 mar 2023 16:42:18

Perché la tua pagina dovrebbe passare a "publish" più di una volta? Una volta che una pagina è pubblicata, è online e lo stato tipicamente non cambia a meno che non la si sposti in "trash" per rimuoverla dal sito.

Mat Lipe Mat Lipe
1 apr 2023 17:59:21