Skip Navigation

[Resolved] Generate a list of image IDs from multi-image field

This thread is resolved. Here is a description of the problem and solution.

Problem: I would like to generate a list of image ids from a repeating image field.

Solution: Use the following custom shortcode and utility function.

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;
}
 
add_shortcode('media-info-multi', 'media_info_multi_func');
function media_info_multi_func($atts, $content){
    global $wpdb;
    $atts = shortcode_atts( array(
        'slug' => 'photos',
        'info' => 'title',
    ), $atts);
    $res = '';
    $urls = types_render_field($atts['slug'], array('output' => 'raw', 'separator'=> ','));
    $arr = explode(',', $urls);
    $attachment_id = array();
    foreach($arr as $k => $v){
        $attachment_id[] = get_attachment_id( $v );
    }
    $res = implode(',', $attachment_id);
    return $res;
}
This support ticket is created 6 years, 7 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 - -
13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 - -

Supporter timezone: America/New_York (GMT-04:00)

This topic contains 6 replies, has 2 voices.

Last updated by neilR 6 years, 7 months ago.

Assisted by: Christian Cox.

Author
Posts
#914856

I am trying to generate a list of Image IDs from the images in a multi-image custom field. I tried Luo's solution in reply #277416 at https://toolset.com/forums/topic/image-field-id/. Has the solution changed since 2015?
I have duplicated the code and registered the shortcode in Settings, putting [media-info-multi slug='photos'] into a content template. The code is running (proven with an echo), but no list of IDs...
I am implementing on Multisite - does the solution need adjusting?
Thanks,
Neil

#914967

Hi, in a multisite I think you must specify which post table to query, based on the current site's db prefix:

add_shortcode('media-info-multi', 'media_info_multi_func');
function media_info_multi_func($atts, $content){
    global $wpdb;
    $atts = shortcode_atts( array(
        'slug' => 'photos',
        'info' => 'title',
    ), $atts);
    $res = '';
    $urls = types_render_field($atts['slug'], array('raw' => true, 'separator'=> ','));
    $arr = explode(',', $urls);
    $attachment_id = array();
    foreach($arr as $k => $v){
        $attachment_id[] = $wpdb->get_var($wpdb->prepare(
            "SELECT ID FROM " . $wpdb->prefix . "posts WHERE guid = %s", $v
        ));
    }
    $res = implode(',', $attachment_id);
    return $res;
}
#915485

Thanks - I adjusted code as show, and even hard-coded the table name, but.... Hmm. Still no list of IDs. Must confess that the code isn't transparent. Could you explain a bit, so I can try to work through the logic of what it's doing and why it's not working? Thanks,
N

#915792

Okay first try this small adjustment:

$urls = types_render_field($atts['slug'], array('output' => 'raw', 'separator'=> ','));

Apparently 'raw'=>true has been causing some problems since Types 3.0, and 'output'=>'raw' is the more effective syntax now.

Here is a breakdown of the code:

global $wpdb;
    $atts = shortcode_atts( array(
        'slug' => 'photos',
        'info' => 'title',
    ), $atts);
    $res = '';

This part gives the code access to the global database class, then grabs the attributes 'photos' and 'title' from the shortcode.

$res = '';
    $urls = types_render_field($atts['slug'], array('output' => 'raw', 'separator'=> ','));
    $arr = explode(',', $urls);
    $attachment_id = array();
    foreach($arr as $k => $v){
        $attachment_id[] = $wpdb->get_var($wpdb->prepare(
            "SELECT ID FROM " . $wpdb->prefix . "posts WHERE guid = %s", $v
        ));
    }

This part splits the string of multiple image URLs into an array by separating them at every comma. Then it loops over each item in that array and queries the database to select the post ID from the specified posts table where the guid key is equal to the image URL in the current array item. It pushes each of those post IDs into a different array.

$res = implode(',', $attachment_id);
    return $res;

This part joins the new array of attachment IDs into a single string of URLs, separated by commas. Then it returns that string.

#917404

Hi Christian,
Thanks for the explanation. I have this working fine now. But...
One interesting observation, which caused me some headaches in understanding why it apparently wasn't working...
The images supplied for an ad were sideways/upside down, so I rotated them in the back-end, using the media library functionality. This created an image reference like image2-lotsofrandomiddata.jpg, but all still showed fine in the toolset editor etc. However, when running the above shortcode, any image that had been manipulated in the image editor did not then show up in the list of IDs - the commas appeared, so there were clearly the correct number of iterations, just no image ID.
Not asking you to sort this (unless you have a very quick answer up your sleeve!) - just noting a circumstance where the above isn't a perfect solution.
And for future readers, just to be absolutely clear, the shortcode you use is

[media-info-multi slug='the-slug-of-my-custom-image-field']
#917574

I see, if you choose an image that has been rotated in the Media Library, then the guid attribute and the custom field image URL will not match. However, if you choose the original image and save the post before rotating the image, then the image URL will be maintained. To fix this, I looked for a better solution to get the attachment ID and found this post:
https://wpscholar.com/blog/get-attachment-id-from-wp-image-url/

Here's an updated example that integrates the solution from that post to retrieve the proper ID:

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;
}

add_shortcode('media-info-multi', 'media_info_multi_func');
function media_info_multi_func($atts, $content){
    global $wpdb;
    $atts = shortcode_atts( array(
        'slug' => 'photos',
        'info' => 'title',
    ), $atts);
    $res = '';
    $urls = types_render_field($atts['slug'], array('output' => 'raw', 'separator'=> ','));
    $arr = explode(',', $urls);
    $attachment_id = array();
    foreach($arr as $k => $v){
        $attachment_id[] = get_attachment_id( $v );
    }
    $res = implode(',', $attachment_id);
    return $res;
}
#917835

Wow! 🙂
Thanks.
N