14

I want to upload an image and set it as a featured image in a post. What i tried was this:

$image_id = media_sideload_image($image_url, $post_id, $post_id);
update_post_meta($post_id, '_thumbnail_id', $image_id);

But media_sideload_image() is not returning the image_id, but the render html image. How can I get the image_id?

8 Answers 8

30

Here is an example of how to bypass this limitation using actions/hooks:

function new_attachment( $att_id ){
    // the post this was sideloaded into is the attachments parent!

    // fetch the attachment post
    $att = get_post( $att_id );

    // grab it's parent
    $post_id = $att->post_parent;

    // set the featured post
    set_post_thumbnail( $post_id, $att_id );
}

// add the function above to catch the attachments creation
add_action('add_attachment','new_attachment');

// load the attachment from the URL
media_sideload_image($image_url, $post_id, $post_id);

// we have the image now, and the function above will have fired too setting the thumbnail ID in the process, so lets remove the hook so we don't cause any more trouble 
remove_action('add_attachment','new_attachment');

The idea is that when media_sideload_image is ran, it:

  • downloads the image
  • adds it as an attachment ( a post of type attachment )
  • then attaches that attachment to the post whose ID you provided ($post_id)

Your issue is that it does not provide the newly created attachment posts ID.

But, when an attachment is created, an action is fired containing its ID. We can hook into this before we create the attachment, and save the featured thumbnail with the post ID it gave us, then unhook afterwards.

4
  • 1
    Brilliant! That helped so much.
    – MTT
    Commented Dec 11, 2014 at 17:43
  • 2
    If this answers your question could you mark it as correct?
    – Tom J Nowell
    Commented Dec 11, 2014 at 19:07
  • i cant read your English .can someone edit this post?
    – HiDd3N
    Commented Dec 20, 2016 at 10:58
  • 2
    @HiDd3N I've simplified some of the english used, it should have more common words with a lower reading age
    – Tom J Nowell
    Commented Dec 20, 2016 at 14:55
13

There is no need for the older solutions anymore.

You can get The ID with a fourth paramenter($return) set to 'id'

<?php media_sideload_image($file, $post_id, $desc, $return); ?> 

https://codex.wordpress.org/Function_Reference/media_sideload_image

0
6

I've build a function to get the ID from DB, searching by URL.

function get_attachment_id_from_src ($image_src) {
  global $wpdb;
  $query = "SELECT ID FROM {$wpdb->posts} WHERE guid='$image_src'";
  $id = $wpdb->get_var($query);
  return $id;
}

You can get URL (insted of html code) with a fourth paramenter set to 'src' Codex: media_sideload_image()

$src = media_sideload_image($url, $item_id, $desc,'src');
get_attachment_id_from_src($src);
4

@Tom J Nowell's answer is spot on. I found another alternative (using different functions) explained here but I like this one more.

In my case I have an array of $posts with all the posts I want to insert and a separate $media (same $nid keys as $posts) with the media. My code is the same solution as Tom's but refactored to use an anonymous function:

foreach( $posts as $nid=>$post )
    $posts[$nid]['ID'] = wp_insert_post( $post );

foreach( $posts as $nid=>$post )
    foreach( $media[$nid] as $m=>$mitem ) {

        if( 0 == $m ) add_action( 'add_attachment',
            function( $att_id ) use ($posts, $nid, $mitem) {
                update_post_meta($posts[$nid]['ID'], '_thumbnail_id', $att_id);
                $posts[$nid]['media_urls'][] = $mitem['url'];
            }
        );
        media_sideload_image($mitem['url'], $post['ID']);
        remove_all_actions( 'add_attachment' );
    }

In my case I assume the 1st item in each $media[$nid] shuold be the featured image of its post.

WordPress shouold definitely change media_sideload_image() so it returns the $id . In fact the function has it at hand, see the source here. In fact there's a track ticket for this and they even have patches to apply this to your core in the mean time if you want.

1
  • Looks like it's slated to get patched in 4.8
    – Tom Auger
    Commented May 9, 2017 at 20:03
3

I was looking for a solution and decided to look at the code for media_sideload_image() which was very straightforward. It uses media_handle_sideload() which gives us the attachment id.

I modified it to return the attachment id instead of the html source of the image, and even added a way to send it new filename.

function media_sideload_image_custom($file, $post_id, $desc = null, $file_name = null)
{
    if ( ! empty($file) ) {
        // Download file to temp location
        $tmp = download_url( $file );

        // fix file filename for query strings
        if( empty($file_name) ) { 
            preg_match('/[^\?]+\.(jpg|JPG|jpe|JPE|jpeg|JPEG|gif|GIF|png|PNG)/', $file, $matches);
            $file_array['name'] = basename($matches[0]);
        } else {
            $file_array['name'] = sanitize_file_name($file_name);
        }
        $file_array['tmp_name'] = $tmp;

        // If error storing temporarily, unlink
        if ( is_wp_error( $tmp ) ) {
            @unlink($file_array['tmp_name']);
            $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 null;
}
0

You can use the media_handle_sideload instead of media_sideload_image.Also if you are using this function in functions.php don't forgot to add below three lines.

require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');

$id = media_handle_sideload( $file_array, $post_id );
var_dump($id);
0

I looked at the function, https://developer.wordpress.org/reference/functions/media_sideload_image/ -- it has a 4th argument, "return_type" that specifies the response. If you want the ID, add the 4th argument with 'id'

1
  • Thanks! Yes Olaf's answer has that I think
    – Rup
    Commented Jan 22 at 10:24
0

In this example, media_sideload_image() is used to sideload the image, and then get_posts() is used to query the attachment post by looking for an attachment with the _wp_attached_file meta key matching the file name of the image

  // Download and attach the image

    $attachment_id = media_sideload_image($image_url, $post_id);
    
    // Get the attachment ID by querying the attachment post
    $attachment = get_posts(array('post_type' => 'attachment', 'posts_per_page' => 1, 'post_status' => 'inherit', 'meta_query' => array(array('key' => '_wp_attached_file', 'value' => basename($image_url)))));
    if (!empty($attachment)) {
        $image_id = $attachment[0]->ID;
        
        // Now you have the $image_id
        echo "Image ID: $image_id";
    } else {
        echo "Failed to retrieve the image ID.";
    }
1
  • But media_sideload_image can return the post ID for you, asin most of the other answers here.
    – Rup
    Commented Jan 19 at 10:18

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.