TechEarl

ACF Image Field Returning an Array Instead of a URL?

ACF Image fields can return an array, a URL string, or just the attachment ID. The return format is a per-field setting. Here's what each option returns, when to pick which, and the cleanest pattern for responsive images.

Ishan Karunaratne⏱️ 5 min readUpdated
Share thisCopied
ACF Image field returning an array, URL, or ID? The 3 return formats explained, when to pick which, and the cleanest pattern for responsive images.

The "ACF Image field returns an array but I wanted a URL" symptom comes from a single setting on the field: the Return Format. There are three options (Image Array, Image URL, Image ID) and each returns a fundamentally different shape. Pick the wrong one and your template code does not know what to do with the value. Here is what each returns, when to pick which, and the cleanest pattern for responsive output.

Jump to:

The three return formats

In Custom Fields > Field Groups > [your field group] > [your image field] > Return Format, you see three radio buttons:

  • Image Array (default for most use cases). Returns a PHP array with the URL, alt text, all the registered image sizes, dimensions, mime type, and the attachment ID.
  • Image URL. Returns the URL of the full-size original image as a string.
  • Image ID. Returns the WordPress attachment ID as an integer.

The default is "Image Array" in modern ACF Pro versions. This is the right default for most agency work, but it is also the cause of every "I called <img src="..."> and got [object Object] looking output" ticket.

What each format actually returns

Image Array (array):

php
$image = get_field( 'hero_image' );
// $image looks like:
// [
//   'ID' => 42,
//   'id' => 42,
//   'title' => 'Hero photograph',
//   'filename' => 'hero.jpg',
//   'url' => 'https://example.com/wp-content/uploads/2026/01/hero.jpg',
//   'alt' => 'Sunset over a city skyline',
//   'caption' => '',
//   'description' => '',
//   'mime_type' => 'image/jpeg',
//   'width' => 2400,
//   'height' => 1600,
//   'sizes' => [
//     'thumbnail' => 'https://example.com/.../hero-150x150.jpg',
//     'medium' => 'https://example.com/.../hero-300x200.jpg',
//     'large' => 'https://example.com/.../hero-1024x683.jpg',
//     'thumbnail-width' => 150,
//     'thumbnail-height' => 150,
//     // ... per registered image size
//   ],
//   // ... more keys
// ]

Image URL (string):

php
$image = get_field( 'hero_image' );
// $image looks like:
// 'https://example.com/wp-content/uploads/2026/01/hero.jpg'

Image ID (int):

php
$image = get_field( 'hero_image' );
// $image looks like:
// 42

When to pick Image Array

Use Image Array when:

  • You want responsive images (different sizes for different breakpoints) without making extra database queries.
  • You need the alt text (which you almost always do, for accessibility).
  • You need image dimensions (for width/height attributes that prevent layout shift).
  • You want maximum flexibility in the template without re-querying the attachment.

This is the right default for 90% of agency work. The "extra data" is cached as part of the meta read; the cost is minimal.

php
$image = get_field( 'hero_image' );
if ( $image ) {
    printf(
        '<img src="%s" alt="%s" width="%d" height="%d">',
        esc_url( $image['url'] ),
        esc_attr( $image['alt'] ),
        intval( $image['width'] ),
        intval( $image['height'] )
    );
}

When to pick Image URL

Use Image URL when:

  • You only ever need the URL (no alt, no dimensions, no sizes).
  • You are passing the URL to a third-party library that wants a string.
  • You want the absolute minimum payload in the template variable.

Honest take: I almost never pick this. The savings over Image Array are negligible, and you eventually want the alt text or dimensions for some reason. Default to Image Array unless you have a specific reason.

When to pick Image ID

Use Image ID when:

  • You will pass the value to a WordPress function that expects an attachment ID (wp_get_attachment_image, wp_get_attachment_image_url, wp_get_attachment_metadata).
  • You want the minimal storage in the database (just the ID, not the full array reference).
  • You are storing many image references (a gallery with hundreds of items) and the cumulative meta cost matters.

This pairs well with wp_get_attachment_image, which produces a complete <img> tag with srcset attributes already filled in:

php
$image_id = get_field( 'hero_image' );
if ( $image_id ) {
    echo wp_get_attachment_image( $image_id, 'large', false, [
        'class' => 'hero-image',
        'loading' => 'lazy',
    ] );
}

This is the pattern I reach for on directory sites with thousands of listings, where minimizing meta size matters at scale.

The cleanest pattern for responsive images

The wp_get_attachment_image function (with the ID return format) produces a <img srcset> automatically based on the registered image sizes. This is the cleanest path to responsive images from an ACF Image field:

php
$image_id = get_field( 'hero_image' );
if ( $image_id ) {
    echo wp_get_attachment_image( $image_id, 'large', false, [
        'class' => 'hero-image w-full h-auto',
        'loading' => 'eager',
        'fetchpriority' => 'high',
        'sizes' => '(min-width: 1280px) 1280px, 100vw',
    ] );
}

This produces:

html
<img width="1024" height="683" src=".../hero-1024x683.jpg"
     class="hero-image w-full h-auto"
     loading="eager" fetchpriority="high"
     sizes="(min-width: 1280px) 1280px, 100vw"
     srcset=".../hero-300x200.jpg 300w, .../hero-768x512.jpg 768w, .../hero-1024x683.jpg 1024w, .../hero-2400x1600.jpg 2400w"
     alt="Sunset over a city skyline">

For agency projects I typically default to this pattern (ID return format + wp_get_attachment_image) because it gives me responsive output with one line of template code. See wp_get_attachment_image docs for full options.

For deeper coverage of responsive image patterns with ACF, see Proper Responsive Images with ACF Image Fields.

Changing return format on an existing field

If you change the Return Format on a field that already has data in production, the stored database value does not change. ACF stores the attachment ID in wp_postmeta regardless of return format; the return format only controls how get_field hydrates that ID into a value at read time. So switching formats is safe at the data layer, but you may break templates that expect the old shape.

Process for safely changing return format on a production field:

  1. Switch the return format in the field group admin.
  2. Update every template that reads this field to use the new shape.
  3. Test on staging.
  4. Deploy template changes and the field group change together.

If you do not control template code (the field is used in many templates across the codebase), it is sometimes safer to leave the existing field as-is and create a new field with the desired return format.

The honest 80/20: default to Image Array unless you have a specific reason. For high-scale sites where meta size matters, ID + wp_get_attachment_image is the cleaner pattern. For the alt-text-only case, see How to Get ALT Text from an ACF Image Field.

Sources

Authoritative references this article was fact-checked against.

TagsWordPressACFImagesDebugging

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

Why Your ACF Checkbox Field Returns an Array

ACF Checkbox fields return arrays because they support multiple selections. The shape varies by Return Format. Here's what each option returns, the patterns for rendering and querying, and when to switch to a Select or Radio field instead.

ACF Field Naming Conventions That Actually Scale

A few naming conventions for ACF field groups, field names, and field keys keep a multi-year codebase navigable: snake_case names, hierarchy-encoded keys, post-type prefixes, sub-field consistency. The cost is zero; the benefit compounds.