I'm taking multiple location values with each post, so it's an array (always). My post meta form field is like so:

<select name="<?php echo $project_prefix; ?>offer_locations[]" id="<?php echo $project_prefix; ?>offer_locations" required multiple="multiple">

If the post already exists without any value for locations, the existing value will come null, but as the field is mandatory, the new location value [on saving] will surely be an array, and we should add the postmeta value.

The conditionals I made with array_diff() is working fine. I made a custom scenario and checked the code, and even in WordPress, I've checked the code (custom code block), as you can see couple of var_dump(), echo and exit() inline. But...

function save_post_specifics_meta( $post_id ) {
    global $project_prefix;

    // verify nonce
    if (!isset($_POST['post_specifics_nonce']) || !wp_verify_nonce($_POST['post_specifics_nonce'], basename(__FILE__)))
       return $post_id;

    // check autosave
    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
       return $post_id;

    // check permissions
    if ( 'post' == $_POST['post_type'] && !current_user_can('edit_post', $post_id) )
    return $post_id;

    //Location meta data
    $existing_locations = get_post_custom_values( "{$project_prefix}post_locations", $post_id );
    $new_locations      = $_POST["{$project_prefix}post_locations"]; //always an array

    var_dump($existing_locations);  //for debugging only
    var_dump($new_locations);       //for debugging only

    if( is_array( $existing_locations ) ) {
        $new_diff       = array_diff( $new_locations, $existing_locations );
        $existing_diff  = array_diff( $existing_locations, $new_locations );
    } else {
        $new_diff       = $new_locations;
        $existing_diff  = $existing_locations;
    var_dump($new_diff);            //for debugging only
    var_dump($existing_diff);       //for debugging only

    if( $new_diff ) {
        foreach( $new_diff as $new_location ) {
            add_post_meta( $post_id, "{$project_prefix}post_locations", $new_location );
            echo "New Multiple: ", $new_location, '<br>'; //for debugging only

    if( $existing_locations && $existing_diff ) {
        if( is_array( $existing_diff ) ) {
            foreach ( $existing_diff as $existing_location ) {
                delete_post_meta( $post_id, "{$project_prefix}post_locations", $existing_location );
                echo "Delete Multiple: ", $existing_location, '<br>'; //for debugging only
        } else {
            delete_post_meta( $post_id, "{$project_prefix}post_locations", $existing_diff );
            echo "Delete Single: ", $existing_diff, '<br>'; //for debugging only

    exit(); //for debugging only


add_action( 'save_post',        'save_post_specifics_meta', 10 );
add_action( 'new_to_publish',   'save_post_specifics_meta', 10 );

On saving or updating post, location meta field is doing as expected. But if the data entry operator hit the Preview Changes button, the add_post_meta() is triggering, even within the true conditional braces, and adding duplicate entries, I don't know how!!! :o

I then added true to the last parameter (line#40) to make the value unique, so that I can stop duplicate entries. But adding true stopped adding any new value to the meta_key even on saving.

How can I stop adding meta value on Preview Changes hit?

  • 2
    Maybe you could check for the $_POST variable submitted, when triggering »Preview Changes«, to not save on on preview. It should be $_POST[ 'wp-preview' ] = 'dopreview' - just an idea though, no certainty if this will actually suffice. Oct 25, 2015 at 18:32
  • @ialocin Thanks for pointing there. I don't wanna bypass just now, I need to figure out what's happening there... I var_dump($post_id); exit();, and hitting Preview Changes reveal that the $post_id is not passing exact when hitting preview changes, because it's creating an inherit post_status (a revision) with a different post_id (#1407) of actual post_id (#1301). That's why, get_post_custom_values( "{$project_prefix}post_locations", $post_id ); is missing values completely on "Preview" hit. How can I let the system get the actual post_id when in revision mode? Oct 27, 2015 at 5:48
  • 2
    The post_parent column of a revision contains the $post_id of the post of which the revision is a version from. So something like $rev_obj = get_post( 1407 ); $parent_post_id = $rev_obj->post_parent; should work. Oct 27, 2015 at 11:04
  • 2
    @ialocin it's completely ok. Everybody is busy. I's just concern that, after all, I got the solution based on your comments. So the credit goes to you. <3 Oct 27, 2015 at 18:04
  • 1
    no worries, let me say it with Linus Torvalds, I'm doing this just for fun - and not for points - so all is good :) Oct 27, 2015 at 21:33

1 Answer 1


Actually I'd love to have an answer from @ialocin, because he suggested me the way. But as the code is a bit long for comment field I'm posting it here as an answer. But I'd love to accept an answer more appropriate to the situation:

After @ialocin's suggestion, I got that, the $post_id wasn't accurate for a Preview Changes hit, so the $existing_locations wasn't getting the correct db info. Now I changed the following line:

$existing_locations = get_post_custom_values( "{$project_prefix}post_locations", $post_id );

into the following conditional lines:

if( $_POST[ 'wp-preview' ] === 'dopreview' ) {
    //if it's a preview hit, grab the actual post's data
    $actual_post_id     = wp_get_post_parent_id( $post_id );
    $existing_locations = get_post_custom_values( "{$project_prefix}post_locations", $actual_post_id );
} else {
    //else, go with the actual post
    $existing_locations = get_post_custom_values( "{$project_prefix}post_locations", $post_id );

Everything is working as expected in localhost. Though sometimes, the Preview hit fails the preview_id and preview_nonce etc. and doesn't show the preview, but when they're set, the preview is, exactly what it should be.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.