Simple question: I know this can be achieved with a hook somewhere, but I’m having trouble tracking down exactly where I need to look to implement it. Basically, I need to hook into the featured image / thumbnail hook and update the image URL on the fly. Can someone lend a hand on how I might achieve this with the hook system?

I’ve essentially created a post inheritance plugin whereby an author can create a template and then mass generate new posts that all inherit from this template. These generated posts are fully dynamic in that at runtime in the public view, my plugin fires and checks to see if the active post is template-based. If it is, the plugin grabs the template’s content and inserts that into the currently viewed post. This is working great for the title and text replacement already. Now what I need to do is to display a featured image for these posts, again based on the template’s featured image. I don’t want to actually update these posts in the DB, I simply need to develop it so that when a template calls the_post_thumbnail, my plugin fires and inserts the image automatically.

I hope that clears it up a bit.

2 Answers
2

HTML generated by the_post_thumbnail() & get_the_post_thumbnail() can be altered using the post_thumbnail_html filter. This works even when there is no post thumbnail. Example:

/**
 * Filters the post thumbnail HTML.
 *
 * @since 2.9.0
 *
 * @param string       $html              The post thumbnail HTML.
 * @param int          $post_id           The post ID.
 * @param string       $post_thumbnail_id The post thumbnail ID.
 * @param string|array $size              The post thumbnail size. Image size or array of width and height
 *                                        values (in that order). Default 'post-thumbnail'.
 * @param string       $attr              Query string of attributes.
 */
function wpse_post_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
    // Optionally add any logic here for determining what markup to output.
    // $html will be an empty string if there is no post thumbnail.
    $new_html="<img src="https://placekitten.com/g/600/600" alt="kitten">";
    return $new_html;
}
add_action( 'post_thumbnail_html', 'wpse_post_thumbnail_html', 10, 5 );

The above solution requires that the theme is calling the_post_thumbnail(), but it will work when the post does not have a thumbnail associated with it.

Note that the solution above would not work in the example below if the post does not have a thumbnail. Here, the conditional statement prevents has_post_thumbnail() from being called:

// the_post_thumbnail() will only be called if the post has a thumbnail.
if ( has_post_thumbnail() ) {
    the_post_thumbnail( 'large' );
}

Alternate technique (alters src value for existing featured images)

The wp_get_attachment_image_src filter allows for the src of an attachment to be modified.

This powerful filter affects all attachment image src values, so it is necessary to add/remove the callback function attached to wp_get_attachment_image_src based on the desired conditions.

The begin_fetch_post_thumbnail_html and end_fetch_post_thumbnail_html actions are perfect for this.

Here’s some example code that changes the featured image based on the post id. You can modify this code to use whatever logic is necessary to determine when the wpse_wp_get_attachment_image_src callback should be added and removed.

/**
 * Fires before fetching the post thumbnail HTML.
 *
 * Provides "just in time" filtering of all filters in wp_get_attachment_image().
 *
 * @since 2.9.0
 *
 * @param int          $post_id           The post ID.
 * @param string       $post_thumbnail_id The post thumbnail ID.
 * @param string|array $size              The post thumbnail size. Image size or array of width
 *                                        and height values (in that order). Default 'post-thumbnail'.
 */
function wpse_begin_fetch_post_thumbnail_html( $post_id, $post_thumbnail_id, $size ) {
    // For example, if the post id is 1479, we will add our callback to modify the image.
    // You could use whatever logic you need to determine if the filter should be added.
    if ( 1479 === $post_id ) {
        add_filter( 'wp_get_attachment_image_src', 'wpse_wp_get_attachment_image_src', 10, 4 );
    }
} 
add_action( 'begin_fetch_post_thumbnail_html', 'wpse_begin_fetch_post_thumbnail_html', 10, 3 );

/**
 * Fires after fetching the post thumbnail HTML.
 *
 * @since 2.9.0
 *
 * @param int          $post_id           The post ID.
 * @param string       $post_thumbnail_id The post thumbnail ID.
 * @param string|array $size              The post thumbnail size. Image size or array of width
 *                                        and height values (in that order). Default 'post-thumbnail'.
 */
function wpse_end_fetch_post_thumbnail_html( $post_id, $post_thumbnail_id, $size ) {
    // Now we remove the callback so that it only affects the desired post.
    if ( 1479 === $post_id ) {
        remove_filter( 'wp_get_attachment_image_src', 'wpse_wp_get_attachment_image_src', 10, 4 );
    }
} 
add_action( 'end_fetch_post_thumbnail_html', 'wpse_end_fetch_post_thumbnail_html', 10, 3 ); 

/**
 * Filters the image src result.
 *
 *
 * @param array|false  $image         Either array with src, width & height, icon src, or false.
 * @param int          $attachment_id Image attachment ID.
 * @param string|array $size          Size of image. Image size or array of width and height values
 *                                    (in that order). Default 'thumbnail'.
 * @param bool         $icon          Whether the image should be treated as an icon. Default false.
 */
function wpse_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
    $image[0] = 'https://placekitten.com/g/600/600';
    return $image;
}

Leave a Reply

Your email address will not be published. Required fields are marked *