Skip to content

How to Get the Featured Image URL in WordPress (5 Ways + REST API)

How to get the featured image URL in WordPress with one line of PHP, plus image dimensions, the REST API for headless sites, and a no-code option.

Sunny Kumar
Sunny Kumar7 min read
TL;DR

For most cases, one line does it: get_the_post_thumbnail_url( get_the_ID(), 'full' ) returns the featured image URL as a string. Use wp_get_attachment_image_src() when you also need width and height, the REST API with _embed for headless or JavaScript apps, and always wrap it in has_post_thumbnail() so a post with no image does not break your layout.

Which method to use
MethodReturnsBest for
get_the_post_thumbnail_url()URL stringThe simple, everyday answer
wp_get_attachment_image_src()URL + width + heightWhen you need dimensions
wp_get_attachment_image_url()URL stringFrom an attachment ID
get_post_meta() + _thumbnail_idAttachment IDCustom and advanced workflows
REST API (_embed)JSON with all sizesHeadless and JavaScript apps

You came for one line of code. Here it is.

Inside the loop, this returns the featured image URL as a string:

php
$url = get_the_post_thumbnail_url( get_the_ID(), 'full' );

That one line covers about nine cases out of ten.

The rest of this guide is the variations you reach for when your case is the tenth: when you also need the width and height, when the site is headless and you are pulling the URL in JavaScript, and when a post has no image at all and you cannot let that break the page.

Every snippet below is current WordPress core. No plugin, nothing to install, and each function links to its official reference.

Tip

Featured image, post thumbnail, image tag: the naming, sorted

WordPress calls it the "featured image" in the editor, but the code all uses the older word thumbnail: get_the_post_thumbnail_url(), get_post_thumbnail_id(), and the _thumbnail_id meta key. Same image, two names, so a search for "get post thumbnail URL" lands in the right place.

One more split: if you want the full <img> tag, use the_post_thumbnail(). This guide is about getting the URL by itself, which is what you need for backgrounds, Open Graph tags, and JavaScript.

Featured images only exist if the active theme has declared support for them. Almost every modern theme does.

But if get_the_post_thumbnail_url() keeps returning nothing, this is the first thing I check.

Add this to your theme's functions.php, inside an after_setup_theme hook:

php
add_theme_support( 'post-thumbnails' );

With that in place, the "Featured image" panel appears in the editor and the functions below have something to return.

And if your problem is the reverse, the theme printing the image where you do not want it, I have covered hiding the featured image separately.

The WordPress block editor with the Set featured image panel in the post settings sidebar
Where it all starts: the 'Set featured image' panel in the editor sidebar. The functions below just read whatever you set here.

Method 1

get_the_post_thumbnail_url(): the simple one

Best for: The everyday case: you want the URL and nothing else.

This is the function to reach for first. get_the_post_thumbnail_url() takes a post ID and an image size, and returns the URL as a plain string, or false if the post has no featured image.

php
if ( has_post_thumbnail() ) {
    $featured_url = get_the_post_thumbnail_url( get_the_ID(), 'full' );
    echo esc_url( $featured_url );
}

The has_post_thumbnail() check matters. Without it, a post with no image returns false, and you end up printing an empty src or a broken background.

The official WordPress developer reference page for get_the_post_thumbnail_url showing its signature and string-or-false return type
The official signature: get_the_post_thumbnail_url() takes a post and a size, and returns a string or false. Always handle the false.

Using it as a CSS background

A common reason to want the URL rather than the image tag is to set a hero background:

php
<?php if ( has_post_thumbnail() ) : ?>
    <div class="hero" style="background-image: url('<?php echo esc_url( get_the_post_thumbnail_url( get_the_ID(), 'large' ) ); ?>');">
        <h1><?php the_title(); ?></h1>
    </div>
<?php endif; ?>

Note the size is large, not full. A hero rarely needs the original file, and serving a 4000px image as a background is a quick way to wreck your Core Web Vitals. Compressing and sizing the files themselves is a separate job, covered in my guide to optimizing images in WordPress.

Method 2

wp_get_attachment_image_src(): when you need dimensions

Best for: Open Graph tags, srcset, or anything that needs width and height.

When you need the image's width and height alongside the URL, wp_get_attachment_image_src() is the one. It takes the attachment ID, so you first grab that with get_post_thumbnail_id(), and it returns an array.

php
$thumbnail_id = get_post_thumbnail_id( get_the_ID() );
$image        = wp_get_attachment_image_src( $thumbnail_id, 'large' );

if ( $image ) {
    $url    = $image[0]; // the URL
    $width  = $image[1]; // width in pixels
    $height = $image[2]; // height in pixels
}

The Open Graph use case

This is the cleanest way to output correct og:image tags, which want the dimensions so social platforms can render the preview without a reflow:

php
function tgx_og_image_tags() {
    if ( is_singular() && has_post_thumbnail() ) {
        $img = wp_get_attachment_image_src( get_post_thumbnail_id(), 'large' );
        if ( $img ) {
            printf( '<meta property="og:image" content="%s">' . "\n", esc_url( $img[0] ) );
            printf( '<meta property="og:image:width" content="%s">' . "\n", esc_attr( $img[1] ) );
            printf( '<meta property="og:image:height" content="%s">' . "\n", esc_attr( $img[2] ) );
        }
    }
}
add_action( 'wp_head', 'tgx_og_image_tags' );

Method 3

wp_get_attachment_image_url(): a clean one-liner from an ID

Best for: When you already have the attachment ID and just want the URL.

If you already hold an attachment ID and only want the URL, not the dimensions, wp_get_attachment_image_url() is the tidy version of Method 2. It returns a string instead of an array.

php
$thumbnail_id = get_post_thumbnail_id( get_the_ID() );
$image_url    = wp_get_attachment_image_url( $thumbnail_id, 'large' );

if ( $image_url ) {
    echo '<img src="' . esc_url( $image_url ) . '" alt="' . esc_attr( get_the_title() ) . '">';
}

Use this over Method 2 whenever you do not need width and height. It reads cleaner, and there is no array index to remember.

Method 4

get_post_meta() with _thumbnail_id: the manual route

Best for: Custom workflows where you want the raw attachment ID yourself.

Under the hood, the featured image is just a post meta value: the attachment ID stored against the _thumbnail_id key. You can read it directly, which is handy in custom queries or migrations where the helper functions are awkward.

php
$thumbnail_id = get_post_meta( get_the_ID(), '_thumbnail_id', true );

if ( $thumbnail_id ) {
    $image_url = wp_get_attachment_url( $thumbnail_id );
    echo esc_url( $image_url );
}

This is the most low-level approach, and you rarely need it. But it is worth knowing what the helpers actually do under the hood. get_post_thumbnail_id() is really just a friendly wrapper around this exact meta lookup.

Method 5

The REST API: for headless and JavaScript

Best for: Headless WordPress, a React or Next front end, or any external app.

If your front end is not PHP, you fetch the featured image over the REST API. The whole trick is one parameter: _embed. It pulls the linked media into the response, so you skip the second request.

js
async function getFeaturedImageUrl( postId ) {
  const res  = await fetch(
    `https://yoursite.com/wp-json/wp/v2/posts/${postId}?_embed`
  )
  const post = await res.json()

  const media = post._embedded?.['wp:featuredmedia']?.[0]
  if ( ! media ) return null

  return {
    full:   media.source_url,
    medium: media.media_details?.sizes?.medium?.source_url,
  }
}

The source_url is the full-size image. The media_details.sizes object holds every registered size, so you can pick medium, large, or a custom size by name and serve the right file for the layout.

Getting the featured image URL by post ID (outside the loop)

Here is the mistake I see most often: the snippets that use get_the_ID() only work inside the loop. Outside it, in a widget, a sidebar, or a custom query, just pass the post ID directly.

php
// Featured image URL for post 42, from anywhere
$url = get_the_post_thumbnail_url( 42, 'large' );

For a list of posts, loop over the IDs and call it for each:

php
$recent = get_posts( array( 'numberposts' => 5 ) );

foreach ( $recent as $post ) {
    $img = get_the_post_thumbnail_url( $post->ID, 'medium' );
    if ( $img ) {
        echo '<img src="' . esc_url( $img ) . '" alt="' . esc_attr( $post->post_title ) . '">';
    }
}

Handling a post with no featured image

Every method above returns false or nothing when there is no image. And on a real site, some posts always slip through without one. Plan for it, do not hope around it.

The cleanest pattern is a small helper that falls back to a default image in your theme:

php
function tgx_featured_or_fallback( $post_id = null, $size = 'large' ) {
    $url = get_the_post_thumbnail_url( $post_id, $size );

    if ( ! $url ) {
        $url = get_template_directory_uri() . '/assets/default-featured.jpg';
    }

    return esc_url( $url );
}

Now you can call tgx_featured_or_fallback() anywhere and never worry about an empty src again.

Getting the URL without code

If you only need the URL once, you do not have to touch any PHP. Open the post in the editor, click the featured image, and the media panel shows the file URL on the right, ready to copy.

For a published page, open it in your browser, right-click the featured image, and choose "Copy image address". That is the live URL of whatever size the theme rendered. It is the fastest route when you just want to paste one image link somewhere, not build it into a template.

A quick note on image sizes

Every method takes a size name, and picking the right one is the difference between a fast page and a slow one. These are the defaults:

SizeDimensionsCroppedUse for
thumbnail150 x 150YesSmall grids, avatars
medium300 x 300NoSidebars, cards
medium_large768 wideNoResponsive content
large1024 x 1024NoMain content images
fullOriginalNoDownloads, print

Request the smallest size that still looks right. You can register your own with add_image_size( 'hero', 1920, 600, true ) and ask for it by name. Serving oversized featured images is one of the most common, and most fixable, drags on WordPress site speed.

Which method should you use?

For nine cases out of ten, Method 1 is the answer: get_the_post_thumbnail_url(), wrapped in has_post_thumbnail().

Reach for Method 2 when you need width and height, the REST API method when the front end is headless or JavaScript, and the fallback helper on any site where some posts will not have an image. The meta route in Method 4 is good to understand but rarely the one you actually pick.

Want this kind of WordPress work done right?

Custom theme code, headless builds, and Core Web Vitals, handled end to end. Tell us what you are building and the first reply comes from Sunny, not a sales team.

See WordPress development

Final take

The featured image URL is one line of PHP for almost everyone: get_the_post_thumbnail_url( get_the_ID(), 'full' ).

Everything else here is for the edges, dimensions, headless, and missing images, that turn a quick snippet into something that holds up on a real site.

Always check the image exists before you print it, and always request a sensible size. Those two habits prevent the broken layouts and slow pages that the one-liner alone can quietly cause.

Common questions

What is the easiest way to get the featured image URL in WordPress?

Use get_the_post_thumbnail_url(). Inside the loop, get_the_post_thumbnail_url( get_the_ID(), 'full' ) returns the URL as a string. Wrap it in has_post_thumbnail() so a post without an image does not output an empty URL.

How do I get the featured image URL by post ID, outside the loop?

Pass the ID directly: get_the_post_thumbnail_url( 42, 'large' ) returns the URL for post 42 from anywhere, including a widget, a custom query, or a separate template. It does not need to run inside the loop.

How do I get the featured image URL with the WordPress REST API?

Request the post with _embed, then read post._embedded["wp:featuredmedia"][0].source_url. The query is /wp-json/wp/v2/posts/{id}?_embed, and the media_details.sizes object holds the URL for every registered image size.

How do I get the width and height of the featured image too?

Use wp_get_attachment_image_src( get_post_thumbnail_id(), 'large' ). It returns an array where index 0 is the URL, 1 is the width, and 2 is the height, which is exactly what Open Graph image tags need.

What happens if a post has no featured image?

get_the_post_thumbnail_url() returns false, which can output a broken or empty image. Always check has_post_thumbnail() first, or write a small helper that returns a default fallback image URL when none is set.

What image sizes can I request?

By default: thumbnail (150x150, cropped), medium (300x300), medium_large (768 wide), large (1024x1024), and full (the original). You can register your own with add_image_size() and request it by name.

Written by
Sunny Kumar
Sunny KumarSEO Specialist & product builder

SEO Specialist and product builder with 10+ years in search. The notes come from the work, not the theory.

Work with TheGuideX

Reading about it is the easy part.

Send us the site and the problem. Your first reply comes from Sunny Kumar — not a sales team — and tells you if it is a fit.