Guide

Images

Handle WordPress images in your Nuxt app

WordPress images are served from your WordPress domain. WPNuxt provides utilities and patterns to handle them efficiently.

The Challenge

WordPress stores images at URLs like:

https://your-wordpress.com/wp-content/uploads/2024/01/photo.jpg

In a headless setup, you need to:

  1. Serve images from WordPress or proxy them
  2. Optimize images for performance
  3. Handle responsive images

Quick Comparison

ApproachBest ForSetupOptimization
Direct WordPress URLsPrototyping, simple sitesNoneNone
Proxy with route rulesProduction SSR sitesrouteRules configVia image provider
@wpnuxt/blocksSites using Gutenberg blocksimageDomains configNuxtImg built-in
Nuxt Image standaloneCustom layouts, no blocks@nuxt/image moduleFull NuxtImg control

Approaches

1. Direct WordPress URLs (Simple)

Use WordPress image URLs directly. Images are served from WordPress.

<script setup lang="ts">
const { data: post } = await usePostByUri({ uri: '/hello-world/' })
const imageUrl = post.value?.featuredImage?.node?.sourceUrl
</script>

<template>
  <img :src="imageUrl" :alt="post?.featuredImage?.node?.altText" />
</template>

Pros: Simple, no configuration needed Cons: No optimization, relies on WordPress hosting

Proxy /wp-content/ requests to WordPress. Images appear to come from your Nuxt domain.

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/wp-content/**': {
      proxy: 'https://your-wordpress.com/wp-content/**'
    }
  }
})

Then use relative paths:

<script setup lang="ts">
import { getRelativeImagePath } from '#imports'

const { data: post } = await usePostByUri({ uri: '/hello-world/' })
const imageUrl = getRelativeImagePath(post.value?.featuredImage?.node?.sourceUrl)
// Returns: /wp-content/uploads/2024/01/photo.jpg
</script>

<template>
  <img :src="imageUrl" :alt="post?.featuredImage?.node?.altText" />
</template>

Pros: Same-origin requests, works with image optimization Cons: Adds proxy overhead

3. Nuxt Image with @wpnuxt/blocks

@wpnuxt/blocks includes @nuxt/image and uses <NuxtImg> for optimized images.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@wpnuxt/core', '@wpnuxt/blocks'],

  wpNuxtBlocks: {
    imageDomains: ['your-wordpress.com']
  }
})

The CoreImage block component automatically uses <NuxtImg>:

<NuxtImg
  src="https://your-wordpress.com/wp-content/uploads/photo.jpg"
  alt="Description"
  width="800"
  height="600"
/>

4. Nuxt Image Standalone

Use @nuxt/image without @wpnuxt/blocks:

pnpm add @nuxt/image
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@wpnuxt/core', '@nuxt/image'],

  image: {
    domains: ['your-wordpress.com']
  }
})
<script setup lang="ts">
const { data: post } = await usePostByUri({ uri: '/hello-world/' })
</script>

<template>
  <NuxtImg
    :src="post?.featuredImage?.node?.sourceUrl"
    :alt="post?.featuredImage?.node?.altText"
    width="800"
    height="600"
    loading="lazy"
  />
</template>

Production Setup

For production, combine proxy route rules with <NuxtImg> to get both same-origin image serving and optimization in one setup.

Configuration

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@wpnuxt/core', '@nuxt/image'],

  // Proxy WordPress uploads through your domain
  routeRules: {
    '/wp-content/**': {
      proxy: 'https://your-wordpress.com/wp-content/**'
    }
  },

  // Allow NuxtImg to optimize images from your domain
  image: {
    domains: ['your-wordpress.com']
  }
})

The proxy makes images same-origin (avoiding CORS and mixed-content issues), while <NuxtImg> handles optimization, responsive sizes, and lazy loading.

Component Example

<script setup lang="ts">
import { getRelativeImagePath } from '#imports'

const { data: post } = await usePostByUri({ uri: route.path })

const featuredImage = computed(() => {
  const img = post.value?.featuredImage?.node
  if (!img) return null
  return {
    // Convert absolute WordPress URL to relative path for the proxy
    src: getRelativeImagePath(img.sourceUrl),
    alt: img.altText || '',
    width: img.mediaDetails?.width,
    height: img.mediaDetails?.height
  }
})
</script>

<template>
  <NuxtImg
    v-if="featuredImage"
    :src="featuredImage.src"
    :alt="featuredImage.alt"
    :width="featuredImage.width"
    :height="featuredImage.height"
    sizes="sm:100vw md:50vw lg:800px"
    loading="lazy"
  />
</template>

getRelativeImagePath() converts https://your-wordpress.com/wp-content/uploads/photo.jpg to /wp-content/uploads/photo.jpg. The proxy route rule then serves that path from your WordPress origin, and <NuxtImg> optimizes it with responsive sizes and lazy loading.

If you use @wpnuxt/blocks, the CoreImage block component already handles this pattern automatically — you only need to set imageDomains in the blocks config.

Utility: getRelativeImagePath

WPNuxt provides getRelativeImagePath() to convert absolute WordPress URLs to relative paths:

import { getRelativeImagePath } from '#imports'

const absoluteUrl = 'https://your-wordpress.com/wp-content/uploads/2024/01/photo.jpg'
const relativePath = getRelativeImagePath(absoluteUrl)
// Returns: /wp-content/uploads/2024/01/photo.jpg

This is useful when:

  • Using route rule proxying
  • Building static sites where you want consistent paths
  • Avoiding hardcoded domains

WordPress posts and pages can have featured images. The default fragments include featured image data:

fragment Post on Post {
  featuredImage {
    node {
      sourceUrl
      altText
      mediaDetails {
        width
        height
      }
    }
  }
}

Access in your component:

<script setup lang="ts">
const { data: post } = await usePostByUri({ uri: route.path })

const featuredImage = computed(() => post.value?.featuredImage?.node)
</script>

<template>
  <NuxtImg
    v-if="featuredImage"
    :src="featuredImage.sourceUrl"
    :alt="featuredImage.altText"
    :width="featuredImage.mediaDetails?.width"
    :height="featuredImage.mediaDetails?.height"
  />
</template>

Responsive Images

For more image optimization techniques including lazy loading and layout shift prevention, see Performance.

Use <NuxtImg> with sizes for responsive images:

<NuxtImg
  :src="imageUrl"
  sizes="sm:100vw md:50vw lg:800px"
  loading="lazy"
  placeholder
/>

Or use <NuxtPicture> for modern formats with fallbacks:

<NuxtPicture
  :src="imageUrl"
  format="avif,webp"
  sizes="sm:100vw md:50vw lg:800px"
/>

Image Providers

For production optimization, consider using an image provider:

nuxt.config.ts
export default defineNuxtConfig({
  image: {
    provider: 'cloudflare',
    cloudflare: {
      baseURL: 'https://your-site.com'
    }
  }
})

Supported providers include Cloudflare, Vercel, Imgix, Cloudinary, and more. See Nuxt Image Providers.

Static Site Generation (SSG)

For static sites, images can be:

  1. Left as external URLs - Images load from WordPress at runtime
  2. Proxied at build time - Use Nitro prerender to cache images
  3. Downloaded locally - Use a build script to fetch and store images

For most cases, keeping images on WordPress with a CDN is the simplest approach.

Troubleshooting

Images Not Loading

  1. Check that the WordPress domain is in imageDomains or image.domains
  2. Verify CORS headers allow requests from your Nuxt domain
  3. Check the browser console for blocked requests

Slow Image Loading

  1. Use loading="lazy" for below-the-fold images
  2. Configure an image provider for optimization
  3. Set explicit width and height to prevent layout shift

Mixed Content Errors

If your Nuxt site is HTTPS but WordPress is HTTP:

  1. Enable HTTPS on WordPress
  2. Or use the proxy approach to serve images from your domain
Copyright © 2026