Images
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:
- Serve images from WordPress or proxy them
- Optimize images for performance
- Handle responsive images
Quick Comparison
| Approach | Best For | Setup | Optimization |
|---|---|---|---|
| Direct WordPress URLs | Prototyping, simple sites | None | None |
| Proxy with route rules | Production SSR sites | routeRules config | Via image provider |
| @wpnuxt/blocks | Sites using Gutenberg blocks | imageDomains config | NuxtImg built-in |
| Nuxt Image standalone | Custom layouts, no blocks | @nuxt/image module | Full 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
2. Proxy with Route Rules (Recommended)
Proxy /wp-content/ requests to WordPress. Images appear to come from your Nuxt domain.
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.
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
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
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.
@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
Featured Images
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:
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:
- Left as external URLs - Images load from WordPress at runtime
- Proxied at build time - Use Nitro prerender to cache images
- 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
- Check that the WordPress domain is in
imageDomainsorimage.domains - Verify CORS headers allow requests from your Nuxt domain
- Check the browser console for blocked requests
Slow Image Loading
- Use
loading="lazy"for below-the-fold images - Configure an image provider for optimization
- Set explicit
widthandheightto prevent layout shift
Mixed Content Errors
If your Nuxt site is HTTPS but WordPress is HTTP:
- Enable HTTPS on WordPress
- Or use the proxy approach to serve images from your domain
Related Pages
- Performance — Optimize image loading and Core Web Vitals
- Rendering Blocks — Image handling within Gutenberg blocks