3

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.

4
+50

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.

  • Thanks Birgire, this makes sense in retrospect that _thumbnail_id is removed as soon as we click the "Remove featured image" link below the Featured Image. I was forgetting that it actually removed it straight away via an AJAX call. I have to wait a few hours before I can award the bounty but I'll do so later on. – Rick Curran Nov 27 '15 at 9:46
  • You're welcome @RickCurran, you had it 99% figured out, glad I could help with the remaning 1% ;-) – birgire Nov 27 '15 at 9:54
1

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);
  } 
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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