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:
<?php echo fjarrett_get_attachment_id_by_url( 'https://secureservercdn.net/4ad.004.godaddywp.com/wp-content/uploads/2013/05/test-image.jpg' ) ?> |
This would echo the same result as above because we are ignoring www
usage in the URL being passed through:
<?php echo fjarrett_get_attachment_id_by_url( 'https://secureservercdn.net/4ad.004.godaddywp.com/wp-content/uploads/2013/05/test-image.jpg' ) ?> |
This would echo nothing, because the image doesn’t exist in the WordPress uploads directory:
<?php echo fjarrett_get_attachment_id_by_url( 'https://frankiejarrett.com/foo/test-image.jpg' ) ?> |
And finally, this would also echo nothing because the URL of the file is pointing to an external domain:
<?php echo fjarrett_get_attachment_id_by_url( 'http://www.anotherdomain.com/wp-content/uploads/2013/05/test-image.jpg' ) ?> |
Conclusion
We managed to fetch an attachment ID in just a few lines of code with no expensive DB queries! Awesome 😎
Now you can do cool things like turn a URL into an absolute path:
<?php $url = 'https://secureservercdn.net/4ad.004.godaddywp.com/wp-content/uploads/2013/05/test-image.jpg'; $attachment_id = fjarrett_get_attachment_id_by_url( $url ); $path = ( $attachment_id ) ? get_attached_file( $attachment_id ) : null; echo $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!
Weston Ruter
May 8, 2013 — 7:20 pm
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?
Frankie Jarrett
May 8, 2013 — 8:48 pm
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 usingreadfile()
in order to create a “Download File” link.I plan to post that force download functionality in its entirety in my next tutorial.
Rafal
May 12, 2013 — 7:05 am
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.
Jeremy Ross
May 20, 2013 — 12:17 am
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.
Frankie Jarrett
May 20, 2013 — 10:05 am
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).
Radley
August 20, 2013 — 3:15 pm
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] );
Anh Tran
September 17, 2014 — 12:04 pm
Nice solution. I’ve just thought about this situation and found your comment. Great!
pimschaaf
March 10, 2015 — 10:12 am
Thanks, works swimmingly. Just note that the code uses $parsed_url instead of $parse_url (with a d after parse) and the apostrophes may need replacement because of the formatting on this blog.
sergio
October 8, 2013 — 9:37 pm
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.
sergio
October 8, 2013 — 9:48 pm
Oh, never mind. I just noticed it’s just using it to determine hosts.
Good work 😉
Frankie Jarrett
November 5, 2013 — 10:24 am
Thanks 🙂
Andy Warren
October 16, 2013 — 8:51 am
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.
Willy Makend
November 5, 2013 — 10:22 am
Thank you. It Works!
Tarjan Gerloude
December 22, 2013 — 2:52 pm
such a shame, looking exact for this option, shows no error nor image 🙁
Michael
January 14, 2014 — 6:10 am
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
igrynsh
February 21, 2014 — 1:09 pm
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.
N Atta Kusi Adusei
May 15, 2014 — 2:08 pm
@igrynsh Check @radley’s comment for solution: https://frankiejarrett.com/get-an-attachment-id-by-url-in-wordpress/#comment-643
Great snippet @Frankie. Thumbs!
logbook loan advice
May 27, 2014 — 7:44 am
WOW just what I was searching for. Came here by searching for dekalb county schools
Marco Godínez
August 15, 2014 — 12:01 pm
It seems not work with old wordpress multisites when the files are saved on “wp-content/blogs.dir” directory because I have urls like http://*.domain.com/files/2014/08/image.jpg What do you recommend?
Ron
October 8, 2014 — 1:35 pm
Is this script still available Frankie, would love to try it out.
Nicole
November 4, 2014 — 10:32 am
Yup after some digging I was able to find it here https://gist.github.com/fjarrett/5544469
ppovoroznuk
December 21, 2014 — 8:59 am
Frank, that’s a great solution.
Can I use it in a commercial WP theme?
Frankie Jarrett
December 22, 2014 — 11:13 am
Sure, I don’t see why not.
Jacqui
February 1, 2015 — 4:41 pm
Thanks for this awesome snippet. I was able to get the post thumbnail from a custom field url instead of the full size image which was in a custom folder inside the wp-content folder.
Ben Czegeny
May 23, 2015 — 7:24 pm
I’m running into trouble using this code coupled with the fact that my media is physically stored in an AWS s3 bucket. However it still is linked in my database and can be attached to posts with all the normal wordpress functions.
the way you have this set up it will return nothing because it see’s my media being stored elsewhere. Is there any way around that.
I tried commenting out the line:
if ( ! isset( $parsed_url[1] ) || empty( $parsed_url[1] ) || ( $this_host != $file_host ) ) {
return;
}
But it still returns nothing. Here is a sample of the url going into your function
http://momentsafterdark.s3-us-west-2.amazonaws.com/wp-content/uploads/2015/04/28032252/IMG_7584.jpg
You can see it’s attachment url here : http://www.momentsafterdark.ca/?attachment_id=1259
Any idea’s?
Johan
May 31, 2015 — 2:46 pm
Thanks for sharing. I will actually use this in a plugin that will be released soon on the wp-plugin directory. A link to this page is found in the sourcecode. 🙂
HV Sombrilla
July 16, 2015 — 12:29 am
Thanks you. I used for get a cropped version of the current image url.
Luca
July 31, 2015 — 5:02 am
Thank you very much! This is the best solution I’ve found so far, especially for the domain-agnostic thing.
I’ve featured this article here in stackoverflow:
http://stackoverflow.com/questions/25671108/get-attachment-id-by-file-path-in-wordpress/31743463#31743463
Max
September 3, 2015 — 11:50 pm
This code solves the problem of images like:
…/MyAmazingImage-250×150.jpg
and also use the UPLOADS folder 🙂
function get_attachment_id_by_url($url) {
global $wpdb;
// Get the upload directory paths
$upload_dir_paths = wp_upload_dir();
// Split the $url into two parts with the wp-content directory as the separator
$parsed_url = explode( parse_url( $upload_dir_paths['baseurl'], PHP_URL_PATH ), $url );
// Get the host of the current site and the host of the $url, ignoring www
$this_host = str_ireplace( 'www.', '', parse_url( home_url(), PHP_URL_HOST ) );
$file_host = str_ireplace( 'www.', '', parse_url( $url, PHP_URL_HOST ) );
// Return nothing if there aren't any $url parts or if the current host and $url host do not match
if ( ! isset( $parsed_url[1] ) || empty( $parsed_url[1] ) || ( $this_host != $file_host ) ) {
return;
}
// Now we're going to quickly search the DB for any attachment GUID with a partial path match
// Example: /uploads/2013/05/test-image.jpg
$parsed_url[1] = preg_replace('/-[0-9]{1,4}x[0-9]{1,4}.(jpg|jpeg|png|gif|bmp)$/i', '.$1', $parsed_url[1]);
$attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}posts WHERE guid RLIKE %s;", $parsed_url[1] ) );
// Returns null if no attachment is found
return $attachment[0];
}
Gallib
December 28, 2015 — 4:06 am
Hi,
thanks for the function, works great.
I recommand to check if $attachment is empty before returning it, otherwise php will show a warning.
if (!empty($attachment)) {
return $attachment[0];
}
return null;
Alexandre Sadowski
January 28, 2016 — 5:37 am
Hi,
Some plugins use your code but this is not very optimised for big websites with a lot of images.
A query is made on all posts of the table wp_posts, or he would already be easier to target only attachments. #better #faster #stronger 😀
https://gist.github.com/asadowski10/496068291ec5ca5f3016
Thanks
Chibuike Mba
September 22, 2016 — 3:57 pm
Thanks, saved me hours