Question

I'm trying to update a custom field after a post thumbnail (Featured Image) is either added or removed from a post. The aim of this is to keep track of whether a featured image has been added or removed in order to do a synchronised export of only the updated 'dirty' posts for use in an external service.

I've looked throughout the codex for a hook that would be triggered after a post_thumbnail is set but I haven't been able to find anything. The solution I'd hoped would work was to use the slimly documented 'updated_post_meta' action (not to be confused with 'update_post_meta'!), using the following code:

add_action('updated_post_meta', 'check_dirty_fields_updated_post_meta', 10, 4);
function check_dirty_fields_updated_post_meta($meta_id, $post_id, $meta_key, $meta_value) {
    if ('_thumbnail_id' == $meta_key) {
        update_post_meta($post_id, 'thumbnails_dirty', 1);
    }

    if ('schedule' == $meta_key) {
        update_post_meta($post_id, 'schedule_dirty', 1);
    }
}

So, 'updated_post_meta' should be triggered whenever post_meta is updated, but unfortunately '_thumbnail_id' never gets triggered so the 'thumbnails_dirty' custom field that I subsequently want to set doesn't get updated.

You'll see from that code that I'm also checking to see if a meta_key of 'schedule' is ever updated and then marking another custom field called 'schedule_dirty' (the 'schedule' post_meta value is a custom field that gets set within the standard post UI) In the case of this more standard custom field the 'updated_post_meta' action does see it when it's updated and set the 'schedule_dirty' as intended.

The problem I have is that I can't see why the '_thumbnail_id' post_meta isn't triggering the 'updated_post_meta' action.

Compounding the problem further I just can't find any clear documentation on when the post thumbnail is set and subsequently updating it's related '_thumbnail_id' post_meta field. I note that when setting the Featured Image on a post that this is set straight away and therefore does not seem to be dependent on the 'save_post' action, so whilst I have looked through various aspects related to saving posts I think the answer lies elsewhere.

A few other bits of info that might be relevant to know:

  • The posts in question here are a custom post type

  • I'm also using the Multiple Post Thumbnails plugin and subsequently want to check for the updated state of these additional post thumbnails too.

Was it helpful?

Solution

I think you want to use the added_post_meta hook instead of updated_post_meta because you're not updating the meta here, only adding it. At least in the case of the _thumbnail_id, where we must delete it before adding it again (no update) through the admin UI.

Investigating this further we see that this part of the update_metadata() function:

if ( empty( $meta_ids ) ) {
    return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
}

is causing you the problem, because it calls add_metadata() and returns it, before the update_{$meta_type}_meta and updated_{$meta_type}_meta hooks are ever fired.

You therefore need to hook into the add_metadata() function, instead of the update_metadata() function, through e.g. the add_{$meta_type}_meta (before) or added_{$meta_type}_meta (after) hooks.

If we check out the wp_ajax_set_post_thumbnail() function, that's ajax-requested from the admin UI when adding/removing the featured image, we see that it uses the functions set_post_thumbnail() and delete_post_thumbnail().

The latter one is a wrapper for delete_metadata(), that fires up the delete_{$meta_type}_meta (before) and deleted_{$meta_type}_meta (after) hooks.

OTHER TIPS

This is a working example that hooks into the add / remove events for a post thumbnail. It also includes the meta key required for the Secondary thumbnail created by the MultiPostThumbnail. Help for this solution came from here and the MultiPostThumbnail docs. birgire gives a good explanation about these hooks in the accepted answer.

// Initialize the MultiPostThumbnails based on https://github.com/voceconnect/multi-post-thumbnails/wiki

if (class_exists('MultiPostThumbnails')) {
    new MultiPostThumbnails(
        array(
            'label' => 'Secondary Image',
            'id' => 'secondary-image',
            'post_type' => 'post'
        )
    );
}

// Listen for Updates

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

function ___after_post_meta( $meta_id, $post_id, $meta_key, $meta_value )
{
  if( $meta_key === '_thumbnail_id' ){

    // Primary Thumbnail Added
    update_post_meta($post_id, 'thumbnails_dirty', 1);

  } else if ( $meta_key === 'post_secondary-image_thumbnail_id' ) {

    // Secondary Thumbnail Added
    update_post_meta($post_id, 'thumbnails_dirty', 1);
  } 
}

add_action( 'deleted_post_meta', '___deleted_post_meta', 10, 4 );

function ___deleted_post_meta ( $deleted_meta_ids, $post_id, $meta_key, $only_delete_these_meta_values )
{
  if( $meta_key === '_thumbnail_id'){

    // Primary Thumbnail Deleted
    update_post_meta($post_id, 'thumbnails_dirty', 1);

  } else if ( $meta_key === 'post_secondary-image_thumbnail_id' ) {

    // Secondary Thumbnail Deleted
    update_post_meta($post_id, 'thumbnails_dirty', 1);
  } 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top