web-dev-qa-db-fra.com

action save_post pour inclure le filtre wp_insert_post_data, collecte les informations du champ méta et empêche la boucle infinie

J'essaie de changer le titre d'un article, mais je veux inclure les informations d'un champ méta dont la valeur n'est sauvegardée dans la base de données qu'après que les articles ont déjà été enregistrés. Autre que cette chose, cela fonctionne très bien en tant que filtre wp_insert_post_data.

// add_filter('wp_insert_post_data', 'tr_change_show_title', 99, 2);

function tr_change_show_title($data, $postarr)
{
    if('post' != $data['post_type']) {
        // don't bother if its an auto-draft, as the post title may not have been completed yet, or in the trash
        if ( !in_array( $data['post_status'], array( 'auto-draft', 'trash' ) ))

        $child_ID = $postarr['ID']; // Child post id
        $parent_ID = get_post_meta($child_ID, "_wpcf_belongs_booking_id", true); // parent ID
        $post_type = $data['post_type'];

        if ($post_type == 'show' && get_post_type($parent_ID) == 'booking') {
            $parent_title = get_the_title($parent_ID);

            $data['post_title'] = $parent_title; // save the parent title first
        }

        if (function_exists('types_render_field')) {

            //this isn't working as the meta field isn't saved yet
            $show_time = types_render_field( "show-time", array("post_id"=>"$child_ID", "raw"=>"true") );
            if ($show_time){
                $data['post_title'] .= ' : ' . $show_time; // Append Show time to title
            }
        }
        $data['post_title'] .= ': show-' . $child_ID; // add the original post id
    }
    return $data;
}

J'ai lu le codex, et ce post wpse: https://wordpress.stackexchange.com/a/54713/13551https://codex.wordpress.org/Function_Reference/wp_update_post

Ce que je comprends, c'est qu'une boucle infinie est un risque. Pour éviter cela, nous décrochons puis reprenons le save_post avant et après la fin de notre travail. Je viens avec ce qui suit, mais je ne comprends pas très bien pourquoi je me heurte encore à une boucle infinie.

add_action( 'save_post', 'tr_save_post_show_title', 99 );

function tr_save_post_show_title($post_ID){
    if ( !wp_is_post_revision( $post_ID ) ) { // do nothing if a revision

        // Prevent infinite loop
        remove_action('save_post', 'tr_save_post_show_title');

        // Add our filter
        add_filter('wp_insert_post_data', 'tr_change_show_title', 99, 2);

        write_log(array( 'ID' => $post_ID));

        // Re-save the post this time with filter
        wp_update_post( array( 'ID' => $post_ID), true ); // true for error catching

        // Catch errors
        if (is_wp_error($post_id)) {
            $errors = $post_id->get_error_messages();
            foreach ($errors as $error) {
                write_log($error);
            }
        }
        // re-hook the save_post action
        add_action('save_post', 'tr_save_post_show_title');
    }
}
1
orionrush

Vous raccordez le tr_change_show_title à un filtre à l'intérieur de la fonction elle-même, qui peut créer une boucle infinie. Tous les éléments supprimant/ajoutant des actions et des filtres dans les fonctions doivent être supprimés; à la place, vérifiez si les données de publication doivent être mises à jour ou non. Dans votre cas, vous devriez vérifier si le titre a la valeur que vous désirez ou non, sinon lancez wp_update_post avec la nouvelle valeur:

add_action( 'save_post', 'tr_save_post_show_title', 99, 2 );
function tr_save_post_show_title( $post_ID, $post ){

    if ( !wp_is_post_revision( $post_ID ) ) { // do nothing if a revision

       $meta = get_post_meta($post_ID, "your-meta-key", true );

        if( $meta != '' ) {

            $desired_title = "Whatever you want as title";

            // Check the title value to check if it should be modified
            if( $post->post_title != $desired_title ) {

                $post->post_title = $desired_title;
                wp_update_post( $post, true );

            }

        }

    }


}

Vous craignez d'exécuter cette fonction après l'enregistrement/la mise à jour d'un méta-champ. Si le champ méta se présente sous la forme où vous modifiez la publication, vous pouvez accéder à la valeur du champ méta comme n'importe quel autre champ méta. Quoi qu'il en soit, si vous voulez être sûr que le champ méta a été sauvegardé/mis à jour, vous pouvez utiliser le hook d’action updated_{$meta_type}_meta au lieu de save_post; comme avantage, dans ce crochet d’action, vous avez un accès direct à la méta-valeur actuelle (le cas échéant):

add_action( 'updated_post_meta', 'tr_save_post_show_title', 99, 4 );
function tr_save_post_show_title( $meta_id, $object_id, $meta_key, $meta_value ) {

    if ( $meta_key == 'the_meta_key_here' && $meta_value != '' && $object_id && ! wp_is_post_revision( $object_id ) ) {

        //write_log(array( 'ID' => $post_id ));

        // Get post data
        $post = get_post( $object_id );

        if( $post ) {
            $desired_title = 'Combine here the $post->post_title with $meta_value as you desire.';

            // Check the title value to check if it should be modified
            if( $post->post_title != $desired_title ) {

                $post->post_title = $desired_title;
                wp_update_post( $post );

            }

        }

    }

}
1
cybmeta

Mon approche de ce problème consiste à accéder aux métadonnées "brutes" directement à partir de $ _POST [metabox_id] dans le hook de filtre wp_insert_post_data. Je reconnais que cette approche convient mieux à mon projet où les publications sont entièrement générées à partir de métadonnées et doivent être restituées à chaque fois. Difficile que quelqu'un trouve cela utile.

0
Amarok

En ce qui concerne la contribution de @ cybmeta, je pense que le plug-in Types peut nous jeter en désordre.

Il a raison de dire que vous ne pouvez pas (du moins dans ce contexte) ajouter un filtre au niveau de save_post sans créer une boucle infinie.

Alors que j'essayais d'accéder à la valeur d'un méta-champ, sa suggestion pour updated_post_meta pouvait être appropriée, mais ne semblait pas fonctionner car la clé méta n'était pas disponible lors de l'exécution du hook. Cela pourrait à nouveau être un problème avec la façon dont Types configure les champs personnalisés.

Finalement, j'ai corrigé mon approche initiale. Indépendamment de l’influence de Types, voici un exemple pratique de modification du titre d’un message au point save_post, intégrant la valeur d’un champ méta et empêchant une boucle infinie. Étant donné que save_post est la dernière action de la chaîne, il doit être exécuté après toutes les autres modifications de la base de données. Par conséquent, vous devez être assez confiant que WP_Post Object inclura toutes les valeurs de champs méta et toutes les modifications apportées par les filtres ou actions précédents. Si je n'avais pas voulu des informations actuelles de mes méta-champs, un simple filtrage via wp_insert_post_data aurait suffi.

add_action('save_post', 'tr_save_post_show_title', 99, 2);

function tr_save_post_show_title ($post_ID, $post) {
    if($post->post_type == 'show' && !in_array($post -> post_status, array('auto-draft', 'revision', 'trash'))) {
        // don't bother if our CPT post is an auto-draft, a revision or in the trash

        $parent_ID = get_post_meta($post_ID, "_wpcf_belongs_booking_id", true); // Types relationship
        $current_title = $post -> post_title; // Get current post title saved in DB

        $post_showtime = get_post_meta($post_ID, "wpcf-show-time", true ); // our custom meta field
        if ($post_showtime == ''){
            $post_showtime = 'To be confirmed';
        }

        if ($parent_ID && get_post_type($parent_ID) == 'booking') { // Check to see if Types a parent relationship has been assigned.

            $show_post_title = get_the_title($parent_ID); // get the id of the parent post
            if ($show_post_title != ''){
                $show_post_title .= ': '  . $post_showtime;
            }
        } else if (!$parent_ID){ // when a parent is not assigned
            $show_title = "Show not yet assigned to venue: " . $post_showtime;
        }
        if ($current_title != $show_post_title ){ // The current title does not match what we would like it to be

            // Prevent infinite loop
            remove_action('save_post', 'tr_save_post_show_title');

            // Re-save the post with our new title
            wp_update_post( array( 'ID' => $post_ID, 'post_title' => $show_post_title ), false ); // true for error catching

            // re-hook the save_post action
            add_action('save_post', 'tr_save_post_show_title', 99, 2);

            // Catch any errors with our custom logging function http://goo.gl/P9HbcK
            if (is_wp_error($post_ID)) {
                $errors = $post_id->get_error_messages();
                foreach ($errors as $error) {
                    write_log($error);
                }
            }
        }
    }
}

Fait intéressant save_post_<post_type> lequel est exécuté juste avant que save_post ne reçoive pas non plus les valeurs les plus récentes du champ méta .

0
orionrush