Astro is a new Static Site Generator, that focuses on shipping less front-end JavaScript. It’s also very simple to use and connect with different APIs. That’s why in this tutorial I’m going to show how to connect WordPress REST API together with Astro.
Installation
Astro installation is very simple. First, we have to run:
npm init astro
and than:
npm install
npm start
We can also use specific templates during the init
phase by using the --template
parameter. You can read more about it in the official documentation.
.env file
Astro has a built-in way of handling variables set in a .env
file.
Just create a .env
file, place your variables inside like this:
PUBLIC_API_URL = https://domain.com/wp-json/wp/v2
The only tricky part is to remember to start them with PUBLIC_
.
Then we can use them anywhere in our code with something like this:
import.meta.env.PUBLIC_API_URL
And that’s it 🙂 You don’t have to install any additional library or anything.
WordPress API
As I mentioned – we’re going to use the REST API. That’s why we’re going to create some helper functions that will make everything simpler.
const API_URL = import.meta.env.PUBLIC_API_URL;
export async function fetchAPI( query='' ) {
const res = await fetch( `${API_URL}/${query}` );
if ( res.ok ) {
return res.json();
} else {
const error = await res.json();
throw new Error(
'❗ Failed to fetch API for ' + query + "\n" +
'Code: ' + error.code + "\n" +
'Message: ' + error.message + "\n"
);
}
}
export async function getArticles() {
const data = await fetchAPI( 'articles/?per_page=50' );
return data;
}
The fetchAPI
returns either the data from the API or an error. We can also pass the $query
parameter.
The second function is getArticles
– it’s just a helper, so we don’t have to write fetchAPI('articles/?per_page=50')
each time.
Layout and components
Because we don’t want to repeat ourselves with writing some parts of our code all the time, we are going to create a template first.
Let’s create a src/layouts/Base.astro
:
---
import Header from '../components/Header.astro'
const {pageTitle = 'Hello world'} = Astro.props
---
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>{pageTitle}</title>
<link
rel="stylesheet"
type="text/css"
href={Astro.resolve( '../styles/global.css' )} />
</head>
<body>
<div>
<Header/>
<slot />
</div>
</body>
</html>
The most important here is the <slot/>
component. Every time we will use <Base>some content</Base>
the <slot/>
component will be replaced with “Some content”.
We also used a Header component here:
<nav class="text-center p-6 mb-6 bg-green-500 shadow-lg">
<a href="/" class="cursor-pointer p-4 ml-2 text-white">WP Owls</a>
</nav>
Let’s also create an Article component, that we will use on all the archive pages:
---
const { post } = Astro.props
---
<div>
<h2>{post.title.rendered}</h2>
<a href={`/` + post.slug}>Read more</a>
</div>
With these components, we have all the foundations prepared.
Structure
Because Astro has a file-based routing we will have to create a few pages first:
pages
-- page
---- [...page].astro
-- [slug].astro
-- index.astro
the page/[page].astro
will be used for pagination, the [slug].astro
will be used to generate single articles and the index.astro
is the homepage.
Fetching articles
Let’s start with the homepage. It’s time to edit pages/index.astro
---
import {fetchAPI} from '../lib/api.js';
import Article from '../components/Article.astro';
import Base from '../layouts/Base.astro';
const data = await fetchAPI('articles?per_page=4');
---
<Base>
<article class="prose lg:prose-xl mx-auto">
<h1>Articles archive</h1>
<div>
<ul>
{data.map(post => <li><Article post={post}/></li>)}
</ul>
</div>
<div class="text-center mt-20">
<div>
<a href="/page/" class="w-full bg-blue-500 px-4 py-3 rounded text-white font-semibold hover:bg-blue-600 transition duration-200 each-in-out">See more articles</a>
</div>
</div>
</article>
</Base>
It’s quite obvious what we are doing here – we are fetching the latest 4 articles and there is also a button that links to the full archive.
We also used the <Article />
. As you can see – it has the post
props, thanks to which we can pass the post data.
Generating single pages
Time to open the [slug].astro
file:
---
import Base from '../layouts/Base.astro';
import {getArticles} from '../lib/api.js';
export async function getStaticPaths() {
const data = await getArticles();
return data.map((post) => {
return {
params: { slug: post.slug },
props: { post } };
});
}
const {post} = Astro.props;
---
<Base>
<article class="prose lg:prose-xl mx-auto">
<h1>{post.title.rendered}</h1>
<div>
{post.content.rendered}
</div>
</article>
</Base>
The most important thing that happens here is using the getStaticPaths
function. It lets us create single pages based on some dynamic data. In this case, we are traversing through all the fetched data and returning the object with params
(that we are using as the page slug) and props
(additional data that we will use during the page generation).
Pagination
In the end, we have to open the page/[...page].astro
:
---
import {getArticles} from '../../lib/api.js';
import Article from '../../components/Article.astro';
import Base from '../../layouts/Base.astro';
export async function getStaticPaths( { paginate } ) {
const data = await getArticles();
return paginate(data, { pageSize: 4 });
}
const {page} = Astro.props;
---
<Base>
<article class="prose lg:prose-xl mx-auto">
<h1>Articles archive</h1>
<div>
<ul>
{page.data.map(post => <li><Article post={post}/></li>)}
</ul>
</div>
{page.url.prev && <a href={page.url.prev}>Previous page</a>}
{page.url.next && <a href={page.url.next}>Next page</a>}
</article>
</Base>
This time in the getStaticPaths
function we are using the paginate
function. It has two parameters data
and a number of posts per page.
You can find all the code in this repository.
Wrapping up
We just scratched the surface here, but it should help you start your adventure with Astro and WordPress. Next, you can try adding more Custom Post Types and adding the navigation.
As you see – Astro is very straightforward to use and connecting it with WP is very simple.
Further reading
- The official documentation
- Building an Astro Website with WordPress as a Headless CMS
- A crash course in Jamstack with Headless WP, Astro, and Buddy