Get an attachment ID by URL in WordPress

We all know you can use wp_get_attachment_url() to return an attachment’s URL by passing in the ID, but what about the reverse scenario?

There are a lot of long-winded examples of how to get an attachment ID by URL floating around the interwebs. Most of them limit results to only returning images or use expensive DB queries. Really, there should be a function for this in core, but there isn’t.

Needless to say, I wasn’t really happy with any of the solutions I found people using, so I decided to take a stab at it.

Below is the most lightweight method I’ve come up with (so far) to get an attachment ID by passing through an attachment URL.

Example usage

Just as an example, this would echo the attachment ID integer of test-image.jpg onto the page:

This would echo the same result as above because we are ignoring www usage in the URL being passed through:

This would echo nothing, because the image doesn’t exist in the WordPress uploads directory:

And finally, this would also echo nothing because the URL of the file is pointing to an external domain:

Conclusion

We managed to fetch an attachment ID in just a few lines of code with no expensive DB queries! Awesome 8-)

Now you can do cool things like turn a URL into an absolute path:

For more information about what was used in this function, please see:
http://php.net/manual/en/function.explode.php
http://php.net/manual/en/function.parse-url.php
http://php.net/manual/en/function.str-ireplace.php
http://codex.wordpress.org/Function_Reference/home_url
http://codex.wordpress.org/Determining_Plugin_and_Content_Directories#Constants
http://codex.wordpress.org/Class_Reference/wpdb#SELECT_a_Column

Was this code helpful to you? Let me know in the comments!

20 thoughts on “Get an attachment ID by URL in WordPress

  1. Weston Ruter

    What’s the use case for this function? I’m trying to think of why I’d need to look up a post associated with an uploaded file. Is it to obtain the attachment ID for an image that has been inserted into a post, one for which the ID-containing class name has been stripped?

    Reply
    1. Frankie Jarrett Post author

      Hey Weston, yeah that’s one possible use case for it.

      In one of my themes I have a post meta field where users can enter a URL to a file, either one from the Media Library or an arbitrary one hosted elsewhere.

      By using this function we can determine whether or not the file in question has an attachment ID, and if so, the path can be retrieved using get_attached_file( $attachment_id ) to then pass inside a PHP force download script using readfile() in order to create a “Download File” link.

      I plan to post that force download functionality in its entirety in my next tutorial.

      Reply
      1. Rafal

        I personally used a similar snippet found on stackexchange to get couple of different image sizes based on a single URL.

        I guess that adding wp cache to the db query could improve the snippet a bit.

  2. Jeremy Ross

    Is it safe to search the guid field? If someone changes the permalinks, or migrates urls without updating the guid field, this wouldn’t return anything even if the file actually existed.

    Reply
    1. Frankie Jarrett Post author

      Hey Jeremy! Thanks for your question.

      Changing permalinks on attachments in the WP Admin is not possible AFAIK. Even if you could, the GUID uses the actual file URL and not the permalink, which is a shortened URL using the attachment_id query string.

      Attachment media is the one exception to the “never touch GUID” rule. Since it uses the URL as the GUID it actually should be updated to the new hostname after a migration.

      However, the DB query in this function is using RLIKE to find a partial string match starting with the wp-content directory and ignores the hostname completely. E.g. wp-content/uploads/2013/05/test-image.jpg

      So even if you fail to update the GUID on attachments during a hostname migration, this function will still work (as long as the uploads directory hasn’t also changed).

      Reply
  3. Radley

    I needed a system to scrape posts for an image to use as a featured image, if a featured image was not provided. However, I didn’t want to show a large image as a post thumbnail, so I wanted to reverse the URL to attachment ID then retrieve the thumbnail version of the image.

    The one problem I faced was that your code does not work if the image is resized (eg, MyAmazingImage-250×150.jpg). Just add this code above the “global $wpdb;” line:

    $parse_url[1] = preg_replace( ‘/-[0-9]{1,4}x[0-9]{1,4}\.(jpg|jpeg|png|gif|bmp)$/i’, ‘.$1′, $parse_url[1] );

    Reply
  4. Pingback: Adding an image uploader to the user profile page in WordPress | S2 Web

  5. sergio

    You are saying “…doesn’t exist in the WordPress uploads directory” but you are actually using the WP_CONTENT_URL directory to determine it, which is wrong.
    I keep the uploads directory outside the content directory as a rule for all my websites, and this would fail.

    You should use UPLOADS instead.

    Reply
  6. Andy Warren

    Just wanted to say that I’ve tried several different variations of this that I’ve found online. This is by far the easiest to use and the smallest amount of code as well. Great snippet. Thanks.

    Reply
  7. Michael

    The core function get_page_by_path() seems to almost do what you are trying to achieve. Unfortunately, it seems to be designed to return the parent of an attachment, if I read the code right. But the first 10 lines or so of that function should almost do it.

    Michael

    Reply
  8. igrynsh

    It doesn’t work if the image source in content is not the original full size image, because then the src contains something like …-600×400.jpg and that can’t be found in wp_posts table, so another search should be done in wp_postmeta.

    Reply

Leave a Reply