Turn a URL into an Attachment / Post ID

Is there any way I can take a URL of an image and find the attachment or post id of that image in the database?

Here is the situation:

Read More

I’m in a loop going over all the ‘img’ tags that are surrounded by ‘a’ tags in my post content. if the src attribute of the ‘img’ tag does not match the href attribute of the outer ‘a’ tag, then i want to replace the ‘img’ tag. In doing this, if the ‘img’ that is to be removed is in the gallery, i want to delete that post, and then put my replacement ‘img’ in its place. I tried using a function like this:

function find_image_post_id($url) {
  global $wpdb;
  $postid = $wpdb->get_var($wpdb->prepare("SELECT DISTINCT ID FROM $wpdb->posts WHERE guid='$url'"));
  if ($postid) {
    return $postid;
  }
  return false;
}

This apparently is not right because the guid is ironically not globally unique. I had (earlier in the same script) uploaded a file with the same name (why? because it was higher resolution and i am trying to replace low resolution versions of the same image) and although wordpress will save the image with a different name in the directory, the guid’s were set to be the same. (possibly a bug).

Is there another technique I can use?

Related posts

Leave a Reply

6 comments

  1. Massively improved function developed for plugin heavy on images:

    if ( ! function_exists( 'get_attachment_id' ) ) {
        /**
         * Get the Attachment ID for a given image URL.
         *
         * @link   http://wordpress.stackexchange.com/a/7094
         *
         * @param  string $url
         *
         * @return boolean|integer
         */
        function get_attachment_id( $url ) {
    
            $dir = wp_upload_dir();
    
            // baseurl never has a trailing slash
            if ( false === strpos( $url, $dir['baseurl'] . '/' ) ) {
                // URL points to a place outside of upload directory
                return false;
            }
    
            $file  = basename( $url );
            $query = array(
                'post_type'  => 'attachment',
                'fields'     => 'ids',
                'meta_query' => array(
                    array(
                        'key'     => '_wp_attached_file',
                        'value'   => $file,
                        'compare' => 'LIKE',
                    ),
                )
            );
    
            // query attachments
            $ids = get_posts( $query );
    
            if ( ! empty( $ids ) ) {
    
                foreach ( $ids as $id ) {
    
                    // first entry of returned array is the URL
                    if ( $url === array_shift( wp_get_attachment_image_src( $id, 'full' ) ) )
                        return $id;
                }
            }
    
            $query['meta_query'][0]['key'] = '_wp_attachment_metadata';
    
            // query attachments again
            $ids = get_posts( $query );
    
            if ( empty( $ids) )
                return false;
    
            foreach ( $ids as $id ) {
    
                $meta = wp_get_attachment_metadata( $id );
    
                foreach ( $meta['sizes'] as $size => $values ) {
    
                    if ( $values['file'] === $file && $url === array_shift( wp_get_attachment_image_src( $id, $size ) ) )
                        return $id;
                }
            }
    
            return false;
        }
    }
    
  2. I modified Rarst’s code to allow you to match just the filename instead of the full path. This is helpful if you are about to sideload the image if it does not exist. Currently this only works if file names are unique but I will be adding a hash check later to help with images that have the same filename.

    function get_attachment_id( $url, $ignore_path = false ) {
    
    if ( ! $ignore_path ) {
    
        $dir = wp_upload_dir();
        $dir = trailingslashit($dir['baseurl']);
    
        if( false === strpos( $url, $dir ) )
            return false;
    }
    
    $file = basename($url);
    
    $query = array(
        'post_type' => 'attachment',
        'fields' => 'ids',
        'meta_query' => array(
            array(
                'key'     => '_wp_attached_file',
                'value'   => $file,
                'compare' => 'LIKE',
            )
        )
    );
    
    $ids = get_posts( $query );
    
    foreach( $ids as $id ) {
        $match = array_shift( wp_get_attachment_image_src($id, 'full') );
        if( $url == $match || ( $ignore_path && strstr( $match, $file ) ) )
            return $id;
    }
    
    $query['meta_query'][0]['key'] = '_wp_attachment_metadata';
    $ids = get_posts( $query );
    
    foreach( $ids as $id ) {
    
        $meta = wp_get_attachment_metadata($id);
    
        foreach( $meta['sizes'] as $size => $values ) {
            if( $values['file'] == $file && ( $ignore_path || $url == array_shift( wp_get_attachment_image_src($id, $size) ) ) )
                return $id;
        }
    }
    
    return false;
    }
    
  3. Ok I found the answer that no one has on the net I been looking for days now. Keep in mine this only works if your theme or plugin is using the WP_Customize_Image_Control() if you are using WP_Customize_Media_Control() the get_theme_mod() will return the ID and not the url.

    For my solution I was using the newer version WP_Customize_Image_Control()

    A lot of posts on the forums have the get_attachment_id() which does not work anymore. I used attachment_url_to_postid()

    Here is how I was able to do it. Hope this helps someone out there

    // This is getting the image / url
    $feature1 = get_theme_mod('feature_image_1');
    
    // This is getting the post id
    $feature1_id = attachment_url_to_postid($feature1);
    
    // This is getting the alt text from the image that is set in the media area
    $image1_alt = get_post_meta( $feature1_id, '_wp_attachment_image_alt', true );
    

    Markup

    <a href="<?php echo $feature1_url; ?>"><img class="img-responsive center-block" src="<?php echo $feature1; ?>" alt="<?php echo $image1_alt; ?>"></a>
    
  4. Since wordpress version 4.0 there is a wordpress core function attachment_url_to_postid that “Tries to convert an attachment URL into a post ID.” But these function has huge flaw cos it can’t convert custom image url sizes.

    Almost all top answers before trying solve these problem, but all of them have a very heavy database query trying to get all existing attachments and then loop through all of them trying to get attachment metadata and find custom sizes in it. It works well only if you have small amount of attachments in your wordpress project. But you definitely will get performance problem if you have big project with 10000 + attachments.

    But you can extend attachment_url_to_postid core function through existing filter attachment_url_to_postid then trying to force attachment_url_to_postid function search among custom image sizes too.
    Just add code below to functions.php file of your active wordpress theme.
    and then use attachment_url_to_postid function as you use before but with additional custom sizes functionality.

        add_filter( 'attachment_url_to_postid', 'change_attachment_url_to_postid', 10, 2 );
        function change_attachment_url_to_postid( $post_id, $url ) {
            if ( ! $post_id ) {
                $file  = basename( $url );
                $query = array(
                    'post_type'  => 'attachment',
                    'fields'     => 'ids',
                    'meta_query' => array(
                        array(
                            'key'     => '_wp_attachment_metadata',
                            'value'   => $file,
                            'compare' => 'LIKE',
                        ),
                    )
                );
    
                $ids = get_posts( $query );
    
                if ( ! empty( $ids ) ) {
    
                    foreach ( $ids as $id ) {
                        $meta = wp_get_attachment_metadata( $id );
    
                        foreach ( $meta['sizes'] as $size => $values ) {
                            $image_src = wp_get_attachment_image_src( $id, $size );
                            if ( $values['file'] === $file && $url === array_shift( $image_src ) ) {
                                $post_id = $id;
                            }
                        }
                    }
                }
            }
    
            return $post_id;
        }
    
  5. Here is an alternative solution:

    $image_url = get_field('main_image'); // in case of custom field usage
    $image_id = attachment_url_to_postid($image_url);
    
    // retrieve the thumbnail size of our image
    $image_thumb = wp_get_attachment_image_src($image_id, 'thumbnail');
    

    Since WP 4.0 they introduced a function attachment_url_to_postid() that behaves similarly to your’s find_image_post_id()

    Please check the this url for your reference.