update_post_meta() not working when used with WordPress action

I am trying to update the field when post status changes to published. It is getting the values properly but not updating when I check the what update field is returning.

It shows some number.

Please help not sure whether I should use this along with transition_post_status


Update - I have tried below hooks // the action is getting triggered but the fields are not updating

1. publish //works but no update is happening

2. save_post && save_post_l //works but no update is happening.


add_action('transition_post_status', 'updated_to_publish', 10, 3);
function updated_to_publish($new_status, $old_status, $post)
{

    if ($new_status == 'publish')) // I have removed the check for post type 
  {

        $post_id = $post->ID;

        if (get_field('advanced_option_edit_seo', $post_id)) {

            if (defined('WPSEO_VERSION')) {

                $metatitle = get_field('seo_title', $post_id);
                $metadesc = get_field('seo_meta_description', $post_id);
                $metakeywords = get_field('seo_keyword', $post_id);


                update_post_meta($post_id, '_yoast_wpseo_title', $metatitle );
                update_post_meta($post_id, '_yoast_wpseo_metadesc', $metadesc );
                update_post_meta($post_id, '_yoast_wpseo_focuskw', $metakeywords);

            }

        }

    } else {
        return;
    }

}



Update

I was able to solve the issue by using 'wp_insert_post' action . Can I know why other actions failed but 'wp_insert_post' worked?

code that i used for testing

add_action('transition_post_status', 'updated_to_publish', 10, 3);
    function updated_to_publish($new_status, $old_status, $post)
    {

        if (($new_status == 'publish') && ($post->post_type == 'l')) {

            $post_id = $post->ID;

            error_log( var_export( $post_id, 1 ) );

            if (get_field('advanced_option_edit_seo', $post_id)) {


                if (defined('WPSEO_VERSION')) {

                    // ACF field
                    $metatitle    = get_field('seo_title', $post_id);

                     error_log( var_export( $metatitle, 1 ) );

                    $metadesc     = get_field('seo_meta_description', $post_id);

                     error_log( var_export( $metadesc, 1 ) );
                    $metakeywords = get_field('seo_keyword', $post_id);

                     error_log( var_export( $metakeywords, 1 ) );
                    //plugin is activated


                    //old values 

                     $metadesc_old = get_post_meta($post->ID, '_yoast_wpseo_metadesc', true);
                        error_log( var_export( $metadesc_old, 1 ) );
                     $metatitle_old = get_post_meta($post->ID, '_yoast_wpseo_title', true);
                         error_log( var_export( $metatitle_old, 1 ) );
                     $metakeywords_old = get_post_meta($post->ID, '_yoast_wpseo_focuskw', true);
                        error_log( var_export( $metakeywords_old, 1 ) );

                    update_post_meta($post_id, '_yoast_wpseo_title', $metatitle, $metatitle_old);
                       error_log( var_export( $tyone, 1 ) );
                   update_post_meta($post_id, '_yoast_wpseo_metadesc', $metadesc, $metadesc_old);
                       error_log( var_export( $tytwo, 1 ) );
                     update_post_meta($post_id, '_yoast_wpseo_focuskw', $metakeywords, $metakeywords_old);  
                       error_log( var_export( $tythree, 1 ) ); 

                }

            }

        } else {
            return;
        }

        //Do something
    }

Answers 3

  • So I installed the Yoast SEO plugin, and tested your code, and now I can positively say "neither no nor yes, but you could" to this question:

    Please help not sure whether I should use this along with transition_post_status

    transition_post_status is fired before the wp_insert_post action is fired, and the Yoast SEO plugin is actually saving (adding/updating) all its custom fields via the wp_insert_post action:

    // See WPSEO_Metabox::save_postdata() (in wordpress-seo/admin/metabox/class-metabox.php)
    add_action( 'wp_insert_post', array( $this, 'save_postdata' ) );
    

    So your code itself works, and the fields do get updated (if the new and current values are not the same and that all the if conditions are met, of course); however the Yoast SEO plugin overrides the value via the WPSEO_Metabox::save_postdata() function, which should answer this question:

    I was able to solve the issue by using 'wp_insert_post' action . Can I know why other actions failed but 'wp_insert_post' worked?

    Why did I say neither no nor yes, but you could?

    Because you can use transition_post_status along with wp_insert_post like so:

    add_action( 'transition_post_status', 'do_updated_to_publish', 10, 2 );
    function do_updated_to_publish( $new_status, $old_status ) {
        if ( $new_status !== $old_status && 'publish' === $new_status ) {
            add_action( 'wp_insert_post', 'updated_to_publish', 10, 2 );
        }
    }
    
    function updated_to_publish( $post_id, $post ) {
        // Remove it; it will be re-added via the do_updated_to_publish() function,
        // if necessary or when applicable.
        remove_action( 'wp_insert_post', 'updated_to_publish', 10, 2 );
    
        if ( ! defined( 'WPSEO_VERSION' ) || 'l' !== $post->post_type ) {
            return;
        }
    
        if ( get_field( 'advanced_option_edit_seo', $post_id ) ) {
            // Make your update_post_meta() calls here.
            update_post_meta( $post_id, '_yoast_wpseo_focuskw', 'test' );
            error_log( 'focuskw updated for post #' . $post_id );
        }
    }
    

    Tried and tested working with Yoast SEO version 9.1.


  • try "wpseo_title" Filter for updating wpseo_title.

    add_filter('wpseo_title', 'filter_product_wpseo_title');
    
    function filter_product_wpseo_title($title) {
    global $post;
    $post_id = $post->ID;
            if (get_field('advanced_option_edit_seo', $post_id)) {
    
                if (defined('WPSEO_VERSION')) {
    
                    $title = get_field('seo_title', $post_id);
    
                }
    
            }
    
    
        return $title;
    }
    

    for more seo data update example: https://yoast.com/wordpress/plugins/seo/api/


  • Your original function relies on the $_POST['post_type'] being set to the appropriate value. As a general rule, you should avoid using global variables - if you use only want the function gives to you, you don't have to think about the contexts in what it should be called.

    In this case, that's what's happened. You're function relies on a global variable $_POST['post_type'], and while that works in one 'state' (publishing a post) it doesn't in another (a cron job, updating a post). In short, $_POST['post_type'] isn't always what you think it should be.

    The following retrieves the post type from the passed $post variable:

    add_action('transition_post_status', 'updated_to_publish', 10, 3);
    

    function updated_to_publish($new_status, $old_status, $post) {

    if (($new_status == 'publish') && (get_post_type( $post ) == 'l')) {
    
        $post_id = $post->ID;
    
        if (get_field('advanced_option_edit_seo', $post_id)) {
    
            if (defined('WPSEO_VERSION')) {
    
               //Code goes here
    
            }
        }
    
    } else {
        return;
    }
    

    }

    Visit this link from where I just have copied the answer


Related Questions