Gancho add_action para publicaciones completamente nuevas

1 feb 2011, 07:47:33
Vistas: 43.1K
Votos: 22

publish_post se ejecuta cuando se publica una entrada o si se edita y su estado es "publicado". Argumentos de la función de acción: ID de la entrada.

-Documentación de la API del Plugin

He añadido el gancho publish_post a un plugin de WordPress que estoy escribiendo. La función llamada por el gancho está destinada a cambiar las categorías de varias entradas usando la función wp_update_post.

Sin embargo, este gancho no funciona ya que el resultado devuelto al ejecutar wp_update_post siempre es 0. Mi mejor suposición es que ejecutar wp_update_post causa otra instancia de mi gancho al volver a publicar la entrada... lo que creo que provoca el "...o si se edita y su estado es 'publicado'" de la declaración anterior.

¿Hay algún otro gancho de acción que pueda usar que solo se llame cuando la entrada agregada sea completamente nueva y no editada?

<?php
 /* 
 Nombre del Plugin: Plugin Cambiador de Categorías
 URI del Plugin: http://www.example.com
 Descripción: Cuando se crea una nueva entrada, este plugin causará el 
 Versión: 0.1
 Autor: Yo
 Licencia: GPL2 
?>
<?php
class categoryShifter {
  function shiftCategories($post_ID) {

    $maxNumPostsFirstTeir = 4;

    $first_teir_cat = "Noticias Frescas 1";
    $second_teir_cat = "Historias Ligeramente Antiguas 2";  

    $firephp = FirePHP::getInstance(true);

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

    $firephp->log($post_ID, 'post_ID: ');
    $firephp->trace('rastreo hasta aquí');    

    $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, 'entradas obtenidas:');

    $firephp->log(sizeof($firstTeirPosts), 'tamaño');


    // NOTA: Esto parece funcionar.
    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: No funciona actualmente... devuelve un array con el $second_teir_id en él. */
      $firephp->log($result, 'Resultado'); 
    }

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


    $firephp->log('Antes', 'Antes'); 
    if(wp_update_post( $my_post ) == 0) {
        $firephp->Error('Error Fatal, Entrada no actualizada', 'error');
    }
    $firephp->log('Después', 'Después');
    */
    return $post_ID;
  }


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

    $cats = get_categories();      

    $whichCatId = "";

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

/* Gancho para Creación de Entrada */
/* add_action('publish_post', array('categoryShifter','shiftCategories')); */
add_action('wp_insert_post', array('categoryShifter', 'shiftCategories'));
?>

He cambiado a usar el gancho wp_insert_post por el momento... pero todavía no puedo hacer que la función wp_set_post_categories cambie las categorías de las entradas.

Entiendo que probablemente necesitaré actualizar este código para que tenga en cuenta las categorías existentes de la entrada y solo modifique las especificadas por el plugin, pero por ahora es realmente solo una versión alfa.

4
Comentarios

@leeand00 - ¿Puedes publicar tu código como una actualización de tu respuesta para que podamos ver mejor qué necesita corrección?

MikeSchinkel MikeSchinkel
1 feb 2011 07:49:24

@Mike ¡Aquí está la actualización!

leeand00 leeand00
1 feb 2011 08:12:22

@MikeSchinkel A veces es simplemente porque no he tenido la oportunidad de probar las respuestas aún, y no quería marcar una que no sea una buena respuesta... ¡pero volveré a revisar y veré qué puedo hacer!

leeand00 leeand00
1 feb 2011 18:28:44

@MikeSchinkel Vale, los limpié y seleccioné las mejores respuestas, lo siento por eso, no me di cuenta de cómo había descuidado este StackExchange en particular.

leeand00 leeand00
1 feb 2011 18:34:37
Todas las respuestas a la pregunta 6
4
22
// Acciones que se disparan cuando un post cambia de estado a 'publicado'
add_action('new_to_publish', 'tu_funcion');  // De nuevo a publicado
add_action('draft_to_publish', 'tu_funcion'); // De borrador a publicado
add_action('pending_to_publish', 'tu_funcion'); // De pendiente a publicado
1 feb 2011 08:50:56
Comentarios

¿Qué tal la acción 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

Pero ¿se ejecutarán nuevamente si, por ejemplo, el estado cambia de publicado a borrador y luego a publicado otra vez?

brandonjp brandonjp
27 jul 2019 19:07:05

@soulseekah El hook wp_insert_post se llamará nuevamente al editar una entrada existente y guardar. Probado en WordPress 5.9. Sé que tu comentario es del 2012 pero por si alguien tiene curiosidad sobre esto.

vee vee
1 feb 2022 08:32:59

@vee, probablemente se están creando borradores en cada guardado.

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

He leído extensamente el núcleo de WordPress y lo he probado todo. wp_transition_post_status(), new_to_publish(), new_{post_type}(), wp_insert_post().

Todos estos resultan, al final, poco confiables.

wp_transition_post_status() no es confiable porque el nuevo estado "publish" es el estado predeterminado tanto para crear nuevas publicaciones como para actualizar las existentes. El estado anterior no es confiable para definir qué es una nueva publicación y qué no, ya que puede ser draft, auto-draft, publish, etc.

new_to_publish() no funciona para tipos de publicaciones personalizados.

new_{post_type} solo pasa $post como parámetro, y no puedes saber si es nuevo o si se está actualizando uno existente.

wp_insert_post() tiene un parámetro $update que debería ser TRUE al actualizar publicaciones existentes y FALSE al crear nuevas, pero no es confiable porque devuelve TRUE para nuevas publicaciones debido a auto-draft.

Solución: Usar un post meta

Terminé usando un post meta personalizado al que llamé check_if_run_once que ejecutará cierta lógica solo una vez:

/**
*   Hacer algo cuando se crea un nuevo 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')) ) {
        # Nueva Publicación

        # Hacer algo aquí...

        # Y actualizar el meta para que no se ejecute nuevamente
        update_post_meta( $post_id, 'check_if_run_once', true );
    }
}
add_action( 'wp_insert_post', 'new_book', 10, 3 );

Opcionalmente, si necesitas actualizar tus publicaciones existentes con el meta "check_if_run_once", para que no ejecute el código anterior en publicaciones existentes creadas antes de agregar esa función, podrías hacer:

/**
*   Esta es una función temporal para actualizar publicaciones existentes con el post meta "check_if_run_once"
*   Accede a tu sitio web iniciado sesión como administrador y agrega ?debug a la URL.
*/
function temporary_function() {
    if (current_user_can('manage_options')) {
        $posts = get_posts(array(
            'post_type' => 'book',
            'posts_per_page' => -1, // Puede que necesites paginar esto dependiendo de cuántas publicaciones tengas
            '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 jul 2018 03:50:24
Comentarios

¿Por qué esto no tiene más votos a favor y no es la respuesta aceptada? La respuesta aceptada no explica las cosas y no tiene en cuenta que la gente suele usar esto para CPT, etc.

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

Gracias, hombre, de verdad. ¡Qué gran respuesta!

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

Dirigir con precisión la creación de una nueva entrada es en realidad más complicado de lo que parece. Técnicamente hay múltiples formas en que una entrada puede crearse o actualizarse, y hay muchas cosas no tan obvias que técnicamente también son entradas (como las revisiones, por ejemplo).

WordPress proporciona hooks dinámicos que rastrean no solo la creación de entradas, sino también qué era antes y en qué se convirtió. Consulta Transiciones de Estado de Entradas en el Codex.

1 feb 2011 08:51:01
4

Más por experimentación que siguiendo la documentación, esto funciona para mí (WP 3.3). Obtengo una llamada al hook transition_post_status con $new_status establecido como "auto-draft" cuando creas una nueva entrada.

function my_post_new($new_status, $old_status=null, $post=null){
    if ($new_status == "auto-draft"){
        // hacer cosas aquí
    }
}
add_action('transition_post_status', 'my_post_new');
23 mar 2012 11:38:50
Comentarios

Esto se activará cada vez que se guarde un borrador automático, es decir, aproximadamente cada minuto mientras se edita.

soulseekah soulseekah
23 mar 2012 11:54:27

Buen punto. En mi caso esto no es un problema pero podría serlo para otros, dependiendo de lo que estuvieras haciendo.

PapaFreud PapaFreud
23 mar 2012 12:50:24

Quería votar a favor, pero aún no puedo. Así que mis elogios van aquí, @PapaFreud. Por cierto, esto ahora está documentado en http://codex.wordpress.org/Post_Status_Transitions. De nuevo, gracias hombre.

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

@soulseekah Punto interesante que mencionaste, probé esto, y auto-draft se asigna como el $new_status de una publicación al momento de su creación (es decir, Agregar nuevo), una sola vez. Tan pronto como se ejecuta el primer procedimiento de AUTOSAVE después de 1 minuto, el valor de $new_status se actualiza a draft. El $old_status sigue siendo NULL hasta que la publicación se guarda o publica manualmente. Entonces, técnicamente esto funcionaría y no se ejecutaría cada vez que el editor guarde automáticamente tu trabajo. Como medida adicional podrías verificar que $old_status sea NULL para confirmar -> if ($new_status == "auto-draft" && $old_status === NULL)

Adam Adam
22 may 2013 16:57:23
0

Encontré que la mejor opción era verificar el estado de la publicación cuando se llama a wp_insert_post.

Cuando se crea una nueva publicación, el estado inicial es auto-draft.

if (!function_exists('benyonsFunction')) {
    function benyonsFunction($postId, $post) {
        if ($post->post_status == "auto-draft") {
            error_log('¡¡¡NUEVA PUBLICACIÓN!!!');
        }
    }
}

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

Este error_log solo se ejecutará una vez.

5 feb 2020 11:49:20
2

La forma más limpia y confiable de manejar esto para un tipo de publicación conocido es usar el hook {$new_status}_{$post->post_type} que proporciona el estado anterior y compararlo con "publish".

Por ejemplo, si quisieras activar una acción cuando se crea una nueva "página", usarías:

add_action( 'publish_page', function( int $post_id, \WP_Post $post, string $old_status ) {
    if ( 'publish' === $old_status ) {
        // Nada que hacer aquí.
        return;
    }
    // Aquí va la lógica de negocio.
}, 10, 3 );
18 feb 2023 00:46:36
Comentarios

No, esto se activará cada vez que una página cambie de cualquier estado a 'publicado', por lo que se activará muchas más veces que solo en la primera creación.

Christophvh Christophvh
31 mar 2023 16:42:18

¿Por qué tu página cambia a "publicado" más de una vez? Una vez que una página se publica, está activa y el estado normalmente no cambia a menos que la muevas a "papelera" para eliminarla del sitio.

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