Get attachment/image info in JS

Long story short, you can get info about an attachment by using wp.media.attachment() function. This will give you complete data as long as this attachment is already loaded by another script or an wp.media() popup.

If the data is not yet loaded, you can load it using .fetch() method on attachment, which works because it is a Backbone.Collection. It is a Collection because an attachment may have multiple selected files in it.

// preload your attachment
wp.media.attachment(ID).fetch().then(function (data) {
  // preloading finished
  // after this you can use your attachment normally
  wp.media.attachment(ID).get('url');
});

Easy way of doing preloading:

function preloadAttachment(ID, callback) {
  // if it doesn't have URL we probably have to preload it
  if (wp.media.attachment(ID).get('url')) {
    wp.media.attachment(ID).fetch().then(function () {
      callback(wp.media.attachment(ID);
    });

    return;
  }

  callback(wp.media.attachment(ID));
}

// USAGE:
preloadAttachment(10, function (attachment) {
  console.log(attachment.get('url'));
  console.log(wp.media.attachment(10).get('url')); // this also works
})

And that’s how you will want to go about preloading more than one attachment, in a single AJAX request.

// An array of attachments you may want to preload
var attachment_ids = [10, 11, 12, 13];
wp.media.query({ post__in: attachment_ids })
  .more()
  .then(function () {
    // You attachments here normally
    // You can safely use any of them here
    wp.media.attachment(10).get('url');
  })

Note the fact that the AJAX request performed by wp.media.query() is paginated. If you need a robust solution for loading lots and lots of attachments you should go about parsing each page with hasMore() and more() methods.

Disclaimer:

I have used this method before finding out about wp.media.query but it has the penalty of making one request per preloaded attachment. But it also has a nice feature — it doesn’t make any request if all of the attachments that need to be preloaded are already in the fetched state.

function preloadMultipleAttachments(attachment_ids) {
    // I'd rather use Promise.all() here but they do not work with
    // jQuery deferreds :/
    if (jQuery.when.all===undefined) {
        jQuery.when.all = function(deferreds) {
            var deferred = new jQuery.Deferred();
            $.when.apply(jQuery, deferreds).then(
                function() {
                    deferred.resolve(Array.prototype.slice.call(arguments));
                },
                function() {
                    deferred.fail(Array.prototype.slice.call(arguments));
                });

            return deferred;
        }
    }

    return jQuery.when.all(
        attachment_ids.filter(function (attachment_id) {
            return ! wp.media.attachment(attachment_id).get('url');
        }).map(function (id) {
            return wp.media.attachment(id).fetch();
        })
    );
},

Leave a Comment