71

While looking through the function reference entry for wp_insert_post(), I noticed that there's no parameter in the array it requires which will allow me to set the 'Featured Image' for a post, displayed as the post thumbnail in my theme.

I have looked into functions like set_post_thumbnail(), as suggested by Mr. Bennett, but this seems to be a relatively new addition to WordPress itself and the WordPress codex. As such, there aren't any sources that I can find which explain how the $thumbnail_id parameter should be acquired and supplied. If this really is the function to use, in what way could I provide it with a valid $thumbnail_id parameter when all I have is an image URL?

Thanks in advance!

0

5 Answers 5

121
+50

You can set an image as post thumbnail when it is in your media library. To add an image in your media library you need to upload it to your server. WordPress already has a function for putting images in your media library, you only need a script that uploads your file.

Usage:

Generate_Featured_Image( '../wp-content/my_image.jpg', $post_id );

// $post_id is Numeric ID... You can also get the ID with:
wp_insert_post()

Function:

function Generate_Featured_Image( $image_url, $post_id  ){
    $upload_dir = wp_upload_dir();
    $image_data = file_get_contents($image_url);
    $filename = basename($image_url);
    if(wp_mkdir_p($upload_dir['path']))
      $file = $upload_dir['path'] . '/' . $filename;
    else
      $file = $upload_dir['basedir'] . '/' . $filename;
    file_put_contents($file, $image_data);

    $wp_filetype = wp_check_filetype($filename, null );
    $attachment = array(
        'post_mime_type' => $wp_filetype['type'],
        'post_title' => sanitize_file_name($filename),
        'post_content' => '',
        'post_status' => 'inherit'
    );
    $attach_id = wp_insert_attachment( $attachment, $file, $post_id );
    require_once(ABSPATH . 'wp-admin/includes/image.php');
    $attach_data = wp_generate_attachment_metadata( $attach_id, $file );
    $res1= wp_update_attachment_metadata( $attach_id, $attach_data );
    $res2= set_post_thumbnail( $post_id, $attach_id );
}

http://codex.wordpress.org/Function_Reference/wp_upload_dir

http://codex.wordpress.org/Function_Reference/wp_insert_attachment


EDIT: Added path creation

http://codex.wordpress.org/Function_Reference/wp_mkdir_p

13
  • Thank you for your efforts! This only works when using $upload_dir['basedir'] (rather than path) though, because when I inspect the attachment through the post edit interface it is referenced as .../uploads/FILENAME.EXT while $upload_dir['path'] would store it in something like .../uploads/2012/02/FILENAME.EXT. It might be even better to somehow change how the file is referenced, but I wouldn't know how.
    – Chris
    Commented Feb 6, 2012 at 18:02
  • 1
    Added path creation in my answer. Commented Feb 6, 2012 at 18:47
  • Appreciate your quick response :). I still get the same result however, here's a screenshot displaying my problem: i.imgur.com/iKTNs.png . The upper section is the result of placing an echo in your conditional, just to see what's going on.
    – Chris
    Commented Feb 6, 2012 at 20:17
  • Changed it again, didn't pass the full path to wp_insert_attachment and wp_generate_attachment_metadata. Hope this will solve the problem. Commented Feb 6, 2012 at 20:28
  • 1
    Warning: This answer rewrites the file if it has the same name, beware. It should generate names using $post_id or at least uniqid() Commented May 31, 2017 at 21:59
23

I'd like to improve Robs answer by utilizing the WP core functions download_url and media_handle_sideload

<?php
/**
* Downloads an image from the specified URL and attaches it to a post as a post thumbnail.
*
* @param string $file    The URL of the image to download.
* @param int    $post_id The post ID the post thumbnail is to be associated with.
* @param string $desc    Optional. Description of the image.
* @return string|WP_Error Attachment ID, WP_Error object otherwise.
*/
function Generate_Featured_Image( $file, $post_id, $desc ){
    // Set variables for storage, fix file filename for query strings.
    preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
    if ( ! $matches ) {
         return new WP_Error( 'image_sideload_failed', __( 'Invalid image URL' ) );
    }

    $file_array = array();
    $file_array['name'] = basename( $matches[0] );

    // Download file to temp location.
    $file_array['tmp_name'] = download_url( $file );

    // If error storing temporarily, return the error.
    if ( is_wp_error( $file_array['tmp_name'] ) ) {
        return $file_array['tmp_name'];
    }

    // Do the validation and storage stuff.
    $id = media_handle_sideload( $file_array, $post_id, $desc );

    // If error storing permanently, unlink.
    if ( is_wp_error( $id ) ) {
        @unlink( $file_array['tmp_name'] );
        return $id;
    }
    return set_post_thumbnail( $post_id, $id );

}
4
  • 1
    Using the WordPress native functions are the best practice, Thank you. Commented Sep 15, 2018 at 15:39
  • For some reason, this version gave me errors saying "A valid URL was not provided." , whereas Rob Vermeer's answer worked.
    – Flimm
    Commented Aug 28, 2019 at 17:09
  • I can confirm that the modified code does not work, which is a shame as URL sideloading would be awesome! Commented Nov 9, 2020 at 23:16
  • This code is working perfectly for me even though I had trouble with the original answer. Commented Nov 18, 2020 at 22:47
10

Try using set_post_thumbnail().

Edit by Otto: You clarified your question, so I'll clarify the response Chip gave.

Basically, you need to make the 'attachment' for the post as well. When an image is uploaded into the WordPress media library, a special post entry is made for it with a post type of attachment. This attachment is linked to some specific post via the post_parent identifier.

So if you know the ID of the attachment, then calling set_post_thumbnail with the post object or ID and the attachment ID will simply set the post thumbnail flag.

If you have not created the attachment yet, then you will need to do that first. Easiest way to do that is with wp_insert_attachment(). This function takes an array of a few parameters, the filename (the file must already be in the proper uploads directory), and the post ID of the parent post that you want to attach the attachment to.

Just having a file uploaded and attached to a post doesn't do anything automatically. This is simply a sort of categorization mechanism. The gallery mechanism, for example, uses the attached images of a post to build the [gallery] for that post. A thumbnail for a post is just one of the attached images which has be set to be the thumbnail.

More info on how to use wp_insert_attachment can be found in the codex (linked above).

5
  • Thank you for your reply! How would I retrieve the thumbnail ID, though? I'm starting out with an image URL, so I guess I should somehow add an image to the wordpress library using another function?
    – Chris
    Commented Jan 27, 2012 at 17:44
  • As you are already inserting a post, I had assumed that you were already attaching images to the post you're inserting. Is that not a valid assumption? Commented Jan 27, 2012 at 18:15
  • Sorry, but I have not yet found out how to actually attach images to a post by URL. Also, I would not want the image to actually be displayed in the post itself. I'm currently looking for the function which will return the $thumbnail_id, and thought that maybe wp_insert_attachment() would work, until I noticed it already required the attachment to be in the upload directory. I don't know how to get an image file there by its URL, and I'm not sure whether this is the function I'm looking for in the first place. Thank you for your help!
    – Chris
    Commented Jan 27, 2012 at 20:59
  • Can you please rewrite your question with this information, to better-describe what you're trying to accomplish? (Or, leave this one as-is, and start a new question, to ask how to get the attachment ID when inserting a post?) Commented Jan 27, 2012 at 21:03
  • The original question has been edited and partly rephrased, please check back :).
    – Chris
    Commented Jan 27, 2012 at 21:38
5

Just found this and made it much simpler, works but I'm no security scrubber

if(!empty($_FILES)){
    require_once( ABSPATH . 'wp-admin/includes/post.php' );
    require_once( ABSPATH . 'wp-admin/includes/image.php' );
    require_once( ABSPATH . 'wp-admin/includes/file.php' );
    require_once( ABSPATH . 'wp-admin/includes/media.php' );

    $post_ID = "your post id!";

    $attachment_id = media_handle_upload( 'file', $post_ID );
    set_post_thumbnail( $post_ID, $attachment_id );
}

simple or what? after getting the right files, wordpress will handle the media and upload it, then set it as a thumbnail.

3

set_post_thumbnail() is the best function for this requirement.

I think, you find the ID of an attachment via get_children() or get_posts(). The result have an array and inside this array is the ID. The follow example for testing; i hope it works; write without tests, only on scratch.

For your requirement it is important, that you change get_the_ID() with your post-ID; return the ID of the Attachment and this can you use foth set_post_thumbnail().

$attachments = get_children( 
    array(
        'post_parent' => get_the_ID(), 
        'post_type' => 'attachment', 
        'post_mime_type' => 'image'
    )
);
foreach ( $attachments as $attachment_id => $attachment ) {
    echo wp_get_attachment_image($attachment_id);
}

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