Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting hold of metadata when creating a post in WordPress

Tags:

wordpress

I am using the save_post action to inspect a metadata field in a custom post and take some action on that value. This is the essential guts of how I am doing it:

add_action('save_post', 'my_save_post');

function my_save_post($post_id)
{
    // Check if not autosaving, processing correct post type etc.
    // ...

    // Get the custom field value.
    $my_field_value = get_post_meta($post_id, 'my_field', true);

    // Do some action
    // ...
}

This works fine when updating the post through the admin page. However, when first creating the post, the my_field_value is always empty. The field does get saved correctly, but this action trigger does not seem to be able to see it, nor any other custom field values.

I would like the action to be performed on all posts of this type created, and I will be importing many through the CSV Imported plugin. Even then, the custom fields do get imported correctly, and the action trigger does get fired for each row imported, but the save_post action still cannot see the custom field value.

So far as I can see from documentation, the post has already been created by the time this action fires, so I should always be able to see that custom metafield.


The answer, it seems, is in the order in which things happen. When creating a post from a form, the custom fields are all collected by the appropriate actions and added to the post before my save_post action fires. This means my trigger is able to see those custom field values.

When importing from CSV, the basic post is created first, and then the custom metafields are added. The save_post trigger fires on the first creation, before the metafields are added, and so the custom field data is not visible to the save_post action.

My solution was to catch the updates of the metadata using the updated_post_meta and added_post_meta actions as well as the save_post action:

add_action('updated_post_meta', 'my_updated_post_meta', 10, 4);
add_action('added_post_meta', 'my_updated_post_meta', 10, 4);

function my_updated_post_meta($meta_id, $post_id, $meta_key, $meta_value)
{
    // Make sure we are handling just the meta field we are interested in.
    if ($meta_key != 'my_custom_field') return;
    if (wp_is_post_revision($post_id)) return;
    if (get_post_type($post_id) != 'my_post_type') return;
    if (trim($meta_value) == '') return;

    // Do my custom task (linking this post to a parent post in a different
    // post type). This is the same task performed by the save_post action.
    my_link_product_track($post_id, trim($meta_value));
}

That is essentially what I do, and it seems to work well. I do encapsulate all the above into a custom class in the theme, and don't recommend using global scope variables as shown here, but this is just to show the method.

like image 588
Jason Avatar asked Nov 04 '22 14:11

Jason


1 Answers

You should look at using $post->ID instead of $post_id -

$my_field_value = get_post_meta($post->ID, 'my_field', true);

get_post_meta in the Codex

EDIT:

Could you do something like this?

if($post->ID == ''){
    $pid = $post_id;
} else {
    $pid = $post->ID;
}

//$pid = $post->ID or $post_id, whichever contains a value
$my_field_value = get_post_meta($pid, 'my_field', true);

something that looks for a value in $post->ID and $post_id, and uses whichever one isn't blank?

like image 145
Xhynk Avatar answered Nov 16 '22 13:11

Xhynk