3

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

4

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;
}
5
  • Thank you for the thorough answer! This definitely started to point me in the right direction, but unfortunately, those two action hooks do not fire if the post has no featured image set. I didn't anticipate this being an issue, so I did not add it to my original post, but none of these pages will have a featured image set and will need to be updated as the page is generated.
    – Kevin
    Commented Jan 17, 2017 at 15:12
  • Would you expand on what you mean by 'updated as the page is generated'? Are you referring to when a page is viewed on the front end or when it's published via the back end? Would this code add a featured image in a literal sense, or are you just trying to display a certain image where the featured image would normally be displayed (please show the relevant code from your template in the original question). Commented Jan 17, 2017 at 15:47
  • I've updated the original post. I hope that clears it up a bit more. Yes, I'm referring to when a page is viewed on the front-end. The code doesn't need to literally add a featured image, I just need to insert an image when the_post_thumbnail is called from within a template. This is a distributed plugin amongst our network so I need to achieve this without any sort of template modifications.
    – Kevin
    Commented Jan 17, 2017 at 16:18
  • Thanks for the updates. I've added another approach which uses the post_thumbnail_html filter. It will work as long as the_post_thumbnail() is called. Commented Jan 18, 2017 at 0:03
  • 1
    You've been a HUGE help with this issue. Unfortunately, because most themes check for the existence of the post thumbnail before calling the_post_thumbnail, we're still stuck in a hard place. I think we'll need to set the featured image for our generated posts when they're generated. I wanted to avoid this so that the master template image could be updated and would update all of the generated posts automatically, but I just don't see how that will be possible since has_post_thumbnail() will return false for these generated posts.
    – Kevin
    Commented Jan 18, 2017 at 3:27
0

With PHP it is possible... Just create a function which copies your featured image and renames it (same location or different folder) and returns the new URL. I guess you are doing it for SEO thing? You can also take help of GD Library to compress your images.

Here is stack help. and here is a function I used for like purpose-

function tb_get_image($image_url,$new_url,$upload_folder=""){
  $slug = $new_url;
  $uri =  WP_CONTENT_DIR."/uploads/".$upload_folder;
  $folder =  WP_CONTENT_URL."/uploads/".$upload_folder;  

  $localimage = $uri.$slug.".jpg"; #GET Extension using PHP_PATHINFO
  $image = $folder.$slug.".jpg"; #GET Extension using PHP_PATHINFO

  if(file_exists($localimage) && getimagesize($localimage)){
      return $image;
  }else{

    ...
    ...
    ...
    CODE YOU WANT TO MODIFY OR MOVE IMAGE
    MAY BE ANOTHER FUNCTION TO DO IT
    ...
    ...
    ...
    ...
    return $image;
  }
  return false;
}

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.