Get attachment ID by file path in WordPress - wordpress

I know the path of the file and I like to get the attachment ID.
There's a function wp_get_attachment_url() which requires the ID to get the URL but I need it reverse (with path not URL though)

UPDATE: since wp 4.0.0 there's a new function that could do the job. I didn't tested it yet, but it's this:
https://developer.wordpress.org/reference/functions/attachment_url_to_postid/
OLD ANSWER: so far, the best solution I've found out there, is the following:
https://frankiejarrett.com/2013/05/get-an-attachment-id-by-url-in-wordpress/
I think It's the best for 2 reasons:
It does some integrity checks
[important!] it's domain-agnostic. This makes for safe site moving. To me, this is a key feature.

I used this cool snipped by pippinsplugins.com
Add this function in your functions.php file
// retrieves the attachment ID from the file URL
function pippin_get_image_id($image_url) {
global $wpdb;
$attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $image_url ));
return $attachment[0];
}
Then use this code in your page or template to store / print / use the ID:
// set the image url
$image_url = 'http://yoursite.com/wp-content/uploads/2011/02/14/image_name.jpg';
// store the image ID in a var
$image_id = pippin_get_image_id($image_url);
// print the id
echo $image_id;
Original post here: https://pippinsplugins.com/retrieve-attachment-id-from-image-url/
Hope ti helps ;)
Francesco

Try attachment_url_to_postid function.
$rm_image_id = attachment_url_to_postid( 'http://example.com/wp-content/uploads/2016/05/castle-old.jpg' );
echo $rm_image_id;
More details

None of the other answers here appear to work properly or reliably for a file path. The answer using Pippin's function also is flawed, and doesn't really do things "the WordPress Way".
This function will support either a path OR a url, and relies on the built-in WordPress function attachment_url_to_postid to do the final processing properly:
/**
* Find the post ID for a file PATH or URL
*
* #param string $path
*
* #return int
*/
function find_post_id_from_path( $path ) {
// detect if is a media resize, and strip resize portion of file name
if ( preg_match( '/(-\d{1,4}x\d{1,4})\.(jpg|jpeg|png|gif)$/i', $path, $matches ) ) {
$path = str_ireplace( $matches[1], '', $path );
}
// process and include the year / month folders so WP function below finds properly
if ( preg_match( '/uploads\/(\d{1,4}\/)?(\d{1,2}\/)?(.+)$/i', $path, $matches ) ) {
unset( $matches[0] );
$path = implode( '', $matches );
}
// at this point, $path contains the year/month/file name (without resize info)
// call WP native function to find post ID properly
return attachment_url_to_postid( $path );
}

Cropped URLs
None of the previous answers supported ID lookup on attachment URLs that contain a crop.
e.g: /uploads/2018/02/my-image-300x250.jpg v.s. /uploads/2018/02/my-image.jpg
Solution
Micah at WP Scholar wrote a blog post and uploaded the code to this Gist. It handles both original and cropped URL lookup.
I included the code below as a reference but, if you find useful, I'd encourage you to leave a comment on his post or star the gist.
/**
* Get an attachment ID given a URL.
*
* #param string $url
*
* #return int Attachment ID on success, 0 on failure
*/
function get_attachment_id( $url ) {
$attachment_id = 0;
$dir = wp_upload_dir();
if ( false !== strpos( $url, $dir['baseurl'] . '/' ) ) { // Is URL in uploads directory?
$file = basename( $url );
$query_args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
'key' => '_wp_attachment_metadata',
),
)
);
$query = new WP_Query( $query_args );
if ( $query->have_posts() ) {
foreach ( $query->posts as $post_id ) {
$meta = wp_get_attachment_metadata( $post_id );
$original_file = basename( $meta['file'] );
$cropped_image_files = wp_list_pluck( $meta['sizes'], 'file' );
if ( $original_file === $file || in_array( $file, $cropped_image_files ) ) {
$attachment_id = $post_id;
break;
}
}
}
}
return $attachment_id;
}
Another pro with this solution is that we leverage the WP_Query class instead of making a direct SQL query to DB.

Find IDs for resized images, PDFs and more
Like GFargo pointed out, most of the answers assume the attachment is an image. Also attachment_url_to_postid assumes a url (not a file path).
I believe this better answers the actual question when supplied a file (with path):
function getAttachmentIDFromFile($filepath)
{
$file = basename($filepath);
$query_args = array(
'post_status' => 'any',
'post_type' => 'attachment',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
),
)
);
$query = new WP_Query($query_args);
if ($query->have_posts()) {
return $query->posts[0]; //assume the first is correct; or process further if you need
}
return 0;
}

Based on the answer from #FrancescoCarlucci I could do some improvements.
Sometimes, for example when you edit an image in WordPress, it creates a copy from the original and adds the copys upload path as post meta (key _wp_attached_file) which is not respected by the answer.
Here the refined query that includes these edits:
function jfw_get_image_id($file_url) {
$file_path = ltrim(str_replace(wp_upload_dir()['baseurl'], '', $file_url), '/');
global $wpdb;
$statement = $wpdb->prepare("SELECT `ID` FROM `wp_posts` AS posts JOIN `wp_postmeta` AS meta on meta.`post_id`=posts.`ID` WHERE posts.`guid`='%s' OR (meta.`meta_key`='_wp_attached_file' AND meta.`meta_value` LIKE '%%%s');",
$file_url,
$file_path);
$attachment = $wpdb->get_col($statement);
if (count($attachment) < 1) {
return false;
}
return $attachment[0];
}

Related

Save array of images to user in Wordpress?

Is it possible to save array of images to the user?
I already created a form and I'm at the saving part.
I already have this code:
update_user_meta($user->ID, 'gallery', $_POST['gallery_images']);
gallery_images contains the array of input images in the form.
And I know this is not working. Is it possible to save an array of images in user? If possible, how?
PS.
I'm using the latest version of wordpress.
(Revised answer)
As pointed in the comment to the other answer, you can use media_handle_upload() to upload the images, but since the function only supports single upload, then for multiple uploads, you can set a temporary $_FILES item like so:
// Load upload-related and other required functions.
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
$post_id = 0; // set to the proper post ID, if attaching to a post
$uploaded = []; // attachment IDs
foreach ( $_FILES['gallery_images']['tmp_name'] as $key => $file ) {
// Set a temporary $_FILES item.
$_FILES['_tmp_gallery_image'] = [
'name' => $_FILES['gallery_images']['name'][ $key ],
'type' => $_FILES['gallery_images']['type'][ $key ],
'size' => $_FILES['gallery_images']['size'][ $key ],
'tmp_name' => $file,
'error' => $_FILES['gallery_images']['error'][ $key ],
];
// Upload the file/image.
$att_id = media_handle_upload( '_tmp_gallery_image', $post_id );
if ( ! is_wp_error( $att_id ) ) {
$uploaded[] = $att_id;
}
}
unset( $_FILES['_tmp_gallery_image'] );
// Save the attachment IDs.
$user = wp_get_current_user();
update_user_meta( $user->ID, 'gallery', $uploaded );
And I'm saving the attachment IDs, but of course, it's up to you if you'd rather save the image URLs, etc.
PS: You can check the original answer here to see how you can also upload the images using media_handle_sideload(). (It works well, but instead of going through a wrapper (function), we should just call media_handle_upload() unless if you're "uploading" external/remote image/file.) Sorry about that answer.. :)
You can serialize the data, and when you need it unserialize it.
update_user_meta($user->ID, 'gallery', serialize($_POST['gallery_images']));
serialize:
https://www.php.net/manual/fr/function.serialize.php

How can I put these codes into function.php in WordPress?

I want to upload file with Chinese character to a WordPress website. However, the name of the file is gibberish. I have searched the question and found some solutions. One is to modify the //wp-admin/includes/file.php
function wp_handle_upload( &$file, $overrides = false, $time = null ) {
//….
// Move the file to the uploads dir
//$new_file = $uploads['path'] . “/$filename”;
$new_file = $uploads['path'] . “/” . iconv(“UTF-8″,”GB2312″,$filename);
//…
//return apply_filters( ‘wp_handle_upload’, array( ‘file’ => $new_file, ‘url’ => $url, ‘type’ => $type ), ‘upload’ );
return apply_filters( ‘wp_handle_upload’, array( ‘file’ => $uploads['path'] . “/$filename”, ‘url’ => $url, ‘type’ => $type ) , ‘upload’);
}
As I know, it changes the encoding of the filename. But I want to put it in the function.php in the theme folder. What can I do ?

Is it possible to update post meta from array in one call?

Code snippet:
$save_dbarray = array(
'email' => 'email#email.se',
'adress' => 'adress'
);
//Save values from created array into db
foreach($save_dbarray as $meta_key=>$meta_value) {
update_post_meta($post_id, $meta_key, $meta_value);
}
Is there any way to optimize above code? In this simple scenario, it wouldn't matter, but If I have a large array then I guess it might be performance issues when updating?
I would like to do something like:
update_post_meta($post_id, $save_dbarray);
Is this possible?
While the other answers are creative solutions to your problem, they don't seem to address the actual issue or answer your question.
The Answer
No. WordPress's update_post_meta only works on one field at a time. Your best bet is to stick with the method you're using above, with the foreach loop. The other answers provide ways of storing that meta in a single field, which is probably fine for some but (as in my case) some need to query against those values, and having a serialized or JSON-encoded array doesn't cut it.
Unfortunately, WP provides no "bulk meta update" method, and if it did, it would likely be a foreach loop. You can always write a function to help make your code cleaner, at least:
<?php
function update_post_meta_array( $post_id, $meta ) {
if ( ! get_post( $post_id ) || ! is_array( $meta ) || empty( $meta ) ) {
return false;
}
foreach ( $meta as $meta_key => $meta_value ) {
update_post_meta( $post_id, $meta_key, $meta_value );
}
return true;
}
phatskat is correct in that there's no built-in way to do this and a foreach loop is required.
This is the most efficient I've found - wrote about it in a blog post as well:
add_action('init', 'bulk_update_post_meta_data');
function bulk_update_post_meta_data() {
$args = array(
'posts_per_page' => -1,
'post_type' => 'POSTTYPEHERE',
'suppress_filters' => true
);
$posts_array = get_posts( $args );
foreach($posts_array as $post_array) {
update_post_meta($post_array->ID, 'POSTMETAKEY', 'NEWVALUE');
}
}
Why not try with serialize() like this:
According to update_post_meta() documentation you can pass the $meta_value as array, that will be serialized into a string.
$save_dbarray = array(
'email' => 'email#email.se',
'adress' => 'adress'
);
update_post_meta($post_id, 'my_custom_fields', $save_dbarray);
Possible multiple value at a time you can your value genearte escaped_json
$escaped_json = '{"key":"value with \\"escaped quotes\\""}';
update_post_meta( $id, 'double_escaped_json', wp_slash($escaped_json) );

Gettin atrribute thumbnail from node from a wordpress rss feed

I've been trying to get this seemingly easy peace of code to work.
I'm loading rss from a wordpress site and it all works fine except for the thumbnails. Since in the XML they are set as an attribute instead of a nodeValue i can't seem to get import them. (i've really tried a lot)
$rss = new DOMDocument();
$rss->load('http://goalprogramme.wordpress.com/feed/');
$feed = array();
foreach ($rss->getElementsByTagName('item') as $node) {
// in XML it looks like <media:thumbnail url="http://goalprogramme.files.wordpress.com/2014/01/dsc_0227.jpg?w=150"/>
//echo $node->getElementsByTagName('media:thumbnail')->item(0)->getAttribute('url');
//push items
$item = array (
'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue,
'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
'date' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue,
'thumbnail' => $node->getElementsByTagName('media:thumbnail')->item(0)->getAttribute('url') // this line doesn't work !!!
);
array_push($feed, $item);
}
Any help would be greatly appreciated.
Thanks so much in advance!
Hours later i've created another piece of code that does work. If anyone needs it it, here it is:
$feed_array = array();
$feed = simplexml_load_file('http://goalprogramme.wordpress.com/feed/');
foreach ($feed->channel->item as $item) {
$title = (string) $item->title;
$description = (string) $item->description;
$link = (string) $item->link;
$date = (string) $item->date;
if ($media = $item->children('media', TRUE)) {
if ($media->thumbnail) {
$attributes = $media->thumbnail->attributes();
$thumbnail = (string)$attributes['url'];
}
}
$item = array (
'title' => $title ,
'desc' => $description,
'link' => $link,
'date' => $date,
'thumbnail' => $thumbnail
);
array_push($feed_array, $item);
}

wordpress get attachments that are not images

wordpress has really great functions when it comes to image attachments - but I can not find any documentation on how to get attachments that are not images .
for now, I wrote this function :
function ok99_get_post_file_attachment($mime='application/pdf',$limit=-1) {
global $post;
$attachments = get_children( array('post_parent' => $post->ID, 'post_status' => 'inherit', 'post_type' => 'attachment','post_mime_type' => $mime, 'order' => 'ASC', 'orderby' => 'menu_order ID', 'posts_per_page'=>$limit) );
if ($attachments) {
echo 'Your Attachments : <br/>';
foreach ($attachments as $att) {
//$attachment = array_shift($attachments); // debug to delete
echo wp_get_attachment_url($att->ID) . '<br/>';
the_attachment_link($attachment->ID, false);}
}
return false;
}
my question is : is this the only way to get attachments that are not images ?
Is there any way to do that without another query ??
I'm using this technique for querying attachments that are not images or video files, i.e. a "negative" mime type query. It returns an array of post objects (similar to what would be returned by get_posts(), and could easily be modified to exclude other types of attachment media, or made completely generic using vsprintf().
function wpse9927425_get_downloads($post_id) {
global $wpdb;
$sql_query = $wpdb->prepare(
"SELECT * FROM $wpdb->posts
WHERE post_type = %s
AND post_parent = %d
AND post_mime_type NOT LIKE %s
AND post_mime_type NOT LIKE %s
ORDER BY menu_order, post_title ASC",
'attachment',
$post_id,
'image/%',
'video/%'
);
$files = $wpdb->get_results( $sql_query );
return $files;
}
It seems that Once again I will need to answer myself - also because I got no other input for this question
there appears to be no other way of doing that (meaning - there are a lot of ways - but not without another direct query)
I am getting non-image attachments by specifying the MIME type like so:
if ( $attachments = get_children( array(
'post_type' => 'attachment',
'post_mime_type' => array('application/doc','application/pdf', 'text/plain'),
'numberposts' => 15,
)));
foreach ($attachments as $attachment) {
echo 'Download Fact Sheet';
echo '</div>';
}

Resources