Fetching Content
Fetch posts, pages, and media from WordPress via the REST API.
Fetching WordPress Content
PhantomWP connects to your WordPress site's REST API to fetch content dynamically. Your WordPress site serves as the CMS backend while Astro provides a fast, modern frontend.
How It Works
┌─────────────────┐ REST API ┌─────────────────┐
│ WordPress │ ◄─────────────────► │ Astro Site │
│ (Your CMS) │ /wp-json/wp/v2/ │ (PhantomWP) │
│ │ │ │
│ • Posts │ │ • Static pages │
│ • Pages │ │ • Blog │
│ • Media │ │ • SSR routes │
│ • Custom Types │ │ • Fast delivery│
└─────────────────┘ └─────────────────┘
WordPress remains your content management system—you write, edit, and manage content there. PhantomWP fetches this content via the WordPress REST API and renders it on your Astro site.
Connecting Your WordPress Site
Step 1: Enter Your Site URL
In PhantomWP, open the WordPress Settings:
- Click the WordPress button in the toolbar
- Enter your WordPress site URL (e.g.,
https://yourblog.com) - Click Test Connection
Step 2: Verify REST API Access
PhantomWP will verify:
- ✅ REST API is accessible
- ✅ Posts and pages are available
- ✅ Media can be fetched
Step 3: Browse Your Content
Once connected, you can:
- Browse posts, pages, and media from the Data Panel
- Create pages that fetch specific content
- Use the WordPress client library in your Astro components
Using the WordPress Client
PhantomWP generates a src/lib/wordpress.ts client for your site:
// Fetch all posts
const posts = await getPosts();
// Fetch a single post by slug
const post = await getPost('my-post-slug');
// Fetch pages
const pages = await getPages();
// Fetch categories
const categories = await getCategories();Example: Blog Index Page
---
import { getPosts } from '../lib/wordpress';
import Layout from '../layouts/Layout.astro';
const posts = await getPosts({ perPage: 10 });
---
<Layout title="Blog">
<h1>Latest Posts</h1>
<ul>
{posts.map(post => (
<li>
<a href={`/blog/${post.slug}`}>
{post.title.rendered}
</a>
</li>
))}
</ul>
</Layout>Example: Single Post Page
---
import { getPost, getAllPosts } from '../lib/wordpress';
import Layout from '../layouts/Layout.astro';
export async function getStaticPaths() {
const posts = await getAllPosts();
return posts.map(post => ({
params: { slug: post.slug },
}));
}
const { slug } = Astro.params;
const post = await getPost(slug);
---
<Layout title={post.title.rendered}>
<article>
<h1 set:html={post.title.rendered} />
<div set:html={post.content.rendered} />
</article>
</Layout>What's Available via REST API
Posts
- Title, content, excerpt
- Publication date, modified date
- Author information
- Featured image (via
_embed) - Categories and tags
- Custom fields (meta)
- SEO data (if using Yoast/Rank Math)
Pages
- Title, content
- Page template
- Parent page
- Menu order
- Custom fields
Media
- Images with all sizes
- Alt text and captions
- File metadata
- Source URLs
Taxonomies
- Categories
- Tags
- Custom taxonomies
Custom Post Types
- Any registered post type with
show_in_rest: true - WooCommerce products
- Portfolio items
- Events
- etc.
Handling Featured Images
WordPress embeds featured images when you add _embed to your request:
const posts = await getPosts({ perPage: 10 });
// Access featured image
const featuredImage = post._embedded?.['wp:featuredmedia']?.[0];
if (featuredImage) {
const imageUrl = featuredImage.source_url;
const altText = featuredImage.alt_text;
}The WordPress client includes helper functions:
import { getFeaturedImageUrl } from '../lib/wordpress';
const imageUrl = getFeaturedImageUrl(post, 'large');SEO Data
If your WordPress site uses an SEO plugin, that data is available:
Yoast SEO
const seoData = post.yoast_head_json;
// { title, description, robots, og_title, og_image, schema, ... }Rank Math
const title = post.rank_math_title;
const description = post.rank_math_description;Build-Time vs Runtime Fetching
Static Generation (Recommended)
Fetch content at build time for best performance:
---
// This runs at build time
const posts = await getPosts();
---Rebuild your site when content changes (or use incremental builds).
Server-Side Rendering
For frequently updated content, use SSR:
---
// astro.config.mjs: output: 'server'
// This runs on each request
const posts = await getPosts();
---Caching Strategies
Build-Time Caching
Content is fetched once at build time and cached as static HTML.
ISR (Incremental Static Regeneration)
With Vercel or similar platforms:
- Pages are regenerated on a schedule
- Stale content is served while fresh content builds
On-Demand Revalidation
Trigger rebuilds when content changes:
- Webhook from WordPress on post save
- Manual "Publish" button in PhantomWP
Handling Private Content
For private posts or authenticated requests:
// In your WordPress client
const headers = {
'Authorization': 'Basic ' + btoa('username:application_password')
};Set up Application Passwords in WordPress (Users → Edit → Application Passwords).
Custom Post Types
Access any custom post type registered with REST API support:
// Fetch WooCommerce products
const products = await getCustomPostType('products');
// Fetch portfolio items
const portfolio = await getCustomPostType('portfolio');Performance Tips
- Use
_fieldsparameter — Only fetch the fields you need - Paginate large collections — Don't fetch 1000 posts at once
- Cache responses — Implement response caching
- Use
_embed— Get related data in one request
Example optimized request:
const posts = await getPosts({
perPage: 10,
fields: ['id', 'slug', 'title', 'excerpt', 'date'],
embed: true,
});Troubleshooting
REST API Not Accessible
- Check your site URL is correct
- Ensure REST API isn't disabled by a plugin
- Verify permalinks are not set to "Plain"
CORS Errors
Add to your WordPress .htaccess or use a plugin:
Header set Access-Control-Allow-Origin "*"
Or install the PhantomWP WordPress plugin which handles this.
Missing Featured Images
Ensure you're using _embed in requests:
const posts = await getPosts({ embed: true });Next Steps
- SEO Integration — Preserve your SEO data
- WordPress Settings — Configure your connection
- Deployment — Deploy your headless site