0

I'm a beginner in wordpress / php trying to learn. I want to use the update_post_meta function to populate one meta value (X) with another meta value (Y) everytime Y is changed. I did research and found a code that does this but it only updates the last published post. Can you help me how to modify the code so it works on every post?

    $args = array(
    'post_type' => 'listing',
    'post_status' => 'publish',
    'posts_per_page' => 1,
    'meta_key' => 'y'
);
$dbResult = new WP_Query($args);
global $post;
if ($dbResult->have_posts()) {
   $dbResult->the_post();

   $value = get_post_meta($post->ID,'y',true);
}

update_post_meta( $post->ID, 'x', $value) ; ?>

1 Answer 1

1

@Jawequo-

You need to know how WordPress works in order to understand the answer to your question. There are a ton of functions, and they all call each other to do their job. As the best way to learn about coding is to read code, I'll provide links in walking you thru how post meta is made, updated, and deleted. In my doing this, you'll be able to better find answers to your questions in the future.

Let's say you create a post using wp_insert_post(). If you trace this function, you'll see the meta data for the post is inserted on line 4511 of the code by way of the update_post_meta() function, which, in turn, calls update_metadata() to do all the heavy lifting. If the metadata does not exist (which it doesn't at this point as we're creating a brand new post), add_metadata() will be called on line 250 of the code to insert it into the database. Ok, cool, now we know how a post and its metadata is created.

Later on, let's say you update that same post using wp_update_post(). If you trace this function, you'll see that wp_insert_post() is called on line 4788 of the code. As we've already traced this function, we know how a post and its metadata is updated (and inserted if it doesn't exist). Ok, cool, now we know how a post and its metadata are updated.

At some point in time, you get tired of the post, so you delete it using wp_delete_post(). If you trace this function, you'll see that the metadata gets deleted by way of delete_metadata_by_mid() on line 3446 of the code. Ok, cool, now we know how a post and its metadata are deleted.

Let's now say that you want to just screw around with the metadata of an existing post. You can add meta data by way of add_post_meta(). If you trace this function, you'll see that add_metadata() is called to do all the heavy lifting. To update existing metadata, you call update_post_meta(), which we already traced above. To delete metadata from a post, we call delete_post_meta(), which invokes delete_metadata() to do its heavy lifting. If you take a good look at delete_post_meta(), you'll see that it is just about identical to delete_metadata_by_id() in terms of the order of the hooks and method by which the metadata is deleted. Ok, cool, now we know how to manipulate individual meta of a post without having to update the entire post itself.

It was important to explain all of this because you must have a working understanding of how post meta is updated. And, if you traced the code along with me, you'll have seen those huge blocks of comments above the apply_filters() and do_action() functions. Those are called hooks, and the way WordPress notifies us that if we want to do something, that notification is our chance.

So, if you want to updates a piece of metadata when WordPress manipulates metadata, we can use one of the hooks described in add_metadata(), update_metadata(), or delete_metadata() (which are identical to those in delete_metadata_by_id()). So, let's start with adding metadata after metadata is added using the added_{$meta_type}_meta hook hook. If you trace down from wp_update_post() (or one of the other related functions above) you'll see that $meta_type = "post", so the hook we'll use is add_post_meta:

add_action('added_post_meta', 'mort_metadata_changed', 10, 4);

As you are writing code for WordPress, I must assume that you already know about hooks. In case you don't here's a nice little tutorial about them. The hooks for after metadata is updated or deleted from a post are nearly identical to the added hook: updated_{$meta_type}_meta (update_post_meta) and deleted_{$meta_type}_meta (delete_post_meta). So, the hooks we want to use are nearly identical as well.

add_action('updated_post_meta', 'mort_metadata_changed', 10, 4);
add_action('deleted_post_meta', 'mort_metadata_changed', 10, 3);

Notice that deleting only needs the first three parameters to be sent to the mort_metadata_changed function. This is because the fourth parameter (the new meta value) is empty as the metadata would have been deleted. Let's now create a function for these hooks to call.

function mort_metadata_changed($meta_id, $object_id, $meta_key, $meta_value=NULL) {
    // WordPress just did something with metadata.  Now, its our turn to do
    // something before WordPress continues on its merry way!
}

Notice the final parameter, $meta_value, has a default of NULL. By checking this, we will be able to tell if the function was called via the delete_post_meta hook or not. Importantly, however, take notice that we have interjected ourselves into the inner-workings of WordPress: every time a post's metadata is updated, the mort_metadata_changed() function will execute.

With the information you have obtained by reading the notes above each hook in the code, you now know what each variable contains at the time it is passed to mort_metadata_changed(). Just in case you're lost, try this on for size:

/**
 *  This will be called every time post metadata changes.
 *
 *  @param  int[]   $tmp         The meta IDs, which we won't use.
 *  @param  int     $post_id     The ID of the post whose metadata was changed.
 *  @param  string  $meta_key    The name of the meta data changed.
 *  @param  string  $meta_value  New value of the metadata.  `delete_post_meta`
 *                                only passes the first three parameters, so
 *                                the `NULL` default value can be checked to
 *                                determine if the change is a deletion of the
 *                                post's metadata.
 */
function mort_metadata_changed($tmp, $post_id, $meta_key, $meta_value=NULL) {
    // Did the post meta we're looking for change?
    if(get_post_type($post_id) !== 'listing'
    || get_post_status($post_id) !== 'publish'
    || $meta_key !== 'y'
    ) {
        // Nope. Something other than `y` of a published listing changed.
        return;
    }
    // Validation was passed.  Time to do the mimic.
    if(is_null($meta_value)) {
        // Metadata deleted.
        delete_post_meta($post_id, 'x');
    } else {
        // Metadata added/updated.
        update_post_meta($post_id, 'x', $meta_value);
    }
}

As for where to put this code, I again assume you know how to get your code to run. But if you don't, here's a nice tutorial on the subject.

4
  • 1
    Wow, thank you for this detailed answer didn't expect that. It gave me a lot of value and yes I'm trying to learn more every day by doing and reading into stuff. The code you provided also seems to work for now!
    – Jawequo
    Apr 2, 2022 at 13:16
  • You betcha, @Jawequo. Hopefully, you learned how to trace the code a bit. Thank you for setting my answer as the correct one. Would you be so kind as to upvote it as well?
    – Mort 1305
    Apr 2, 2022 at 16:36
  • Unfortunately I'm not able to do because i just registered this account but as soon as i have enough posts i will do for sure :)
    – Jawequo
    Apr 3, 2022 at 0:23
  • You can trace code without any accounts. Just follow the links I provided to the codex.
    – Mort 1305
    Apr 3, 2022 at 0:48

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.