How to Manage SEO in Headless WordPress with Yoast SEO and WPGraphQL

SEO is a critical part of any website or application. Without it, Google might not be able to find your page or it might not look right in search results or social platforms. How can we leverage popular WordPress plugin Yoast SEO using a headless WordPress instance with Next.js and WPGraphQL?

What's Inside 🧐

What is SEO?

SEO, or Search Engine Optimization, is the mixture of a variety of strategies to try to get your website or application to the top of the search results as well as generally making those results look more appealing.

Part of the technical aspects of SEO are things like using semantic HTML that represent the different parts of your page, such as defining your content in an outline using headers like h1 through h6 and using markup to help Google and other search engines understand your content better.

It also refers to some content strategies like keyword usage and trying to get people to link to your site, but we’re going to stick to the technical parts fo this post.

What are the challenges of SEO and headless WordPress?

Out of the box, you get a decent amount of content management with WordPress, where you can set a title, slug, the content of course, and categories, but unless you install a plugin, you’re limited for how those details are used on your page.

You can customize how that information is pulled into your page, but you’re programmatically making guesses as to the best way to display that content without the context of the post or page itself, leading to sometimes awkward metadata or things that don’t work.

While not every plugin works in a headless WordPress ecosystem, we fortunately have some options.

How can Yoast SEO and WPGraphQL help?

The two plugins that are going to help us out for being able to more carefully manage and craft our SEO experience are Yoast SEO and WPGraphQL.

While we’ll technically need a third plugin to integration Yoast with WPGraphQL at this time, those two are the primary plugins that we’ll actually interact with.

Yoast SEO is an extremely popular plugin for WordPress that adds a variety of custom fields and a rich experience into the WordPress dashboard that can help analyze some of the content SEO. We’ll be able to get a better handle on how our content is working, but also make sure each of our posts are performing as great they can and look as great as they can in the search engine results page (SERP). For our purposes, we’ll make use of the free version!

WPGraphQL is a another plugin for WordPress that allows us to use GraphQL to hook right into the WordPress data stores giving us the ability to query for complex relationships that prove to be challenging or just a pain when using the default REST API.

Finally, we’ll use a third plugin WPGraphQL Yoast SEO Addon that simply allows us to query our Yoast SEO data with WPGraphQL!

What are we going to build?

To get started, we’re going to use a very basic Next.js Starter that I created for bootstrapping a new project with basic WPGraphQL configurations.

Note: you’ll need to already have a WordPress instance with WPGraphQL available and ready to work with whether locally running or publicly available. You’ll also need to be able to install plugins or have someone else install them for you.

What this will allow us to do is skip over the basic installation process and get right into managing our SEO.

Once we have our basic project set up, we’ll walk through all of our plugins, how we can use those plugins to enhance our SEO, and customize our on-page metadata.

Note: if you want to skip all of this and get started with headless WordPress, WPGraphQL, and Yoast built right in, check out my Next.js WordPress Starter and a tutorial to get started!

Step 0: Starting a new Next.js project with Next.js WPGraphQL Basic Starter

We’ll get our project started by spinning up a new Next.js project with my Next.js WPGraphQL Basic Starter.

If you already have a Next.js project with WPGraphQL, you could alternatively use that to walk through the tutorial.

Reminder: make sure your WordPress instance is available to query with WPGraphQL installed!

In your terminal, run:

yarn create next-app -e https://github.com/colbyfayock/next-wpgraphql-basic-starter my-wp-seo-app
# or
npx create-next-app -e https://github.com/colbyfayock/next-wpgraphql-basic-starter my-wp-seo-app

This will go through and clone the starter project and install all of the dependencies.

Note: feel free to change my-wp-seo-app to the directory and project name of your choice!

Once everything is installed, navigate to that new directory:

cd my-wp-seo-app

And before we try to start off the project, create a new file in the root of the project called .env.local with the following:

WORDPRESS_GRAPHQL_ENDPOINT="http://yourhost.com/graphql"

You’ll want to replace http://yourhost.com/graphql with your WordPress instance’s GraphQL endpoint. After installing WPGraphQL, the endpoint is available at /graphql by default.

Now, you can start up the new project by running:

yarn dev
# or
npm run dev

Which will start up a local development server at http://localhost:3000 where you can now access your new Next.js WordPress project!

Headless WordPress and Next.js
New Next.js WordPress site using content from spacejelly.dev

If you head over to the GraphiQL IDE provided by the WPGraphQL plugin, you can also see we can now query our data.

GraphiQL in WordPress
Querying WordPress post data in WPGraphQL

And we’re ready to get started with SEO!

Follow along with the first commit!

Step 1: Installing and configuring Yoast SEO to use with WordPress and WPGraphQL

In order to use Yoast SEO to manage our on page metadata and SEO, we’ll need to install our two plugins: Yoast SEO and the WPGraphQL Yoast SEO Addon.

You can find both of these plugins right inside of the WordPress plugin marketplace by searching for “yoast” to find the primary plugin:

Yoast SEO plugin in WordPress
Yoast SEO plugin in WordPress marketplace

And “yoast wpgraphql” to find the addon:

WPGraphQL Yoast SEO Addon plugin in WordPress
WPGraphQL Yoast SEO Addon in WordPress marketplace

Once both are installed, make sure to also activate both of them in the Plugins panel!

Note: the first time you install Yoast SEO, it will ask you to also go through it’s configuration wizard. Feel free to jump into that now or save it for later, it doesn’t take too much time.

Now, if you head back over to your GraphiQL IDE inside of WPGraphQL, we can now add a new seo field to our query, and we get a big list of new options available to use.

GraphiQL querying SEO data
Querying SEO data for WordPress posts from Yoast

Here’s the example query if you want to follow along:

query MyQuery {
  posts {
    edges {
      node {
        title
        slug
        uri
        seo {
          canonical
          metaDesc
          title
          fullHead 
        }
      }
    }
  }
}

The cool thing if you notice in the above, we’re querying for both our individual fields, but we’re also querying for fullHead which includes the HTML. In the next step, we’ll first learn how to use each individual tag to add our metadata, but in Step 3, we’ll learn how we can alternatively render everything straight from Yoast.

Step 2: Adding Yoast SEO metadata tags to a Next.js project from WPGraphQL

Now that our SEO data is flowing through GraphQL, let’s pick it up and use it inside of our project.

If we open back up our code, inside of src/pages/posts/[postSlug].js , we’ll find getStaticProps at the bottom of the page which is where we query WordPress for our post data with GraphQL.

query PostBySlug($slug: String!) {
  generalSettings {
    title
  }
  postBy(slug: $slug) {
    id
    content
    title
    slug
  }
}

In this query, we’re capturing an individual post by it’s slug, so that we can target only that data. We’re also grabbing some general site metadata, but that’s not important for our context.

Because we can now query for our SEO data, we can add the seo field similar to the last step, right to our existing query:

query PostBySlug($slug: String!) {
  generalSettings {
    title
  }
  postBy(slug: $slug) {
    id
    content
    title
    slug
    seo {
      metaDesc
      title
    }
  }
}

In addition to the rest of our content, we’re now going to grab the Yoast SEO generated meta description and the title.

To see if our data is coming through, we can add a console log statement at the top of our Post page component:

export default function Post({ post, site }) {
  console.log('post', post);

If we navigate to one of our blog posts and open up the web console, we can now see we get our SEO data right along with our post object!

Web console showing SEO data
SEO data inside of the post object

We can now use that data right inside of our post’s page:

<Head>
  <title>{ post.seo.title }</title>
  <meta name="description" content={post.seo.metaDesc} />

We can see this work by using the View Source option inside of our browser, or by using the inspect tool, where we can see our title and meta description rendered straight from the value from Yoast.

Chrome inspector showing rendered title tag
Yoast SEO data rendered in Next.js

You’ll notice though that we don’t have any description, but that’s simply because we haven’t set one yet.

If I go ahead and add my description.

Yoast SEO meta description input
Adding a meta description to a post with Yoast SEO

Once I reload the page, I can now see my description!

Chrome inspector showing updated meta description
Updated meta description from Yoast SEO in Next.js

Follow along with the commit!

Step 3: Rendering a Yoast SEO generated head in Next.js

Finally, maybe you don’t want toplace have to actually manage all of those tags individually. Luckily, Yoast SEO and WPGraphQL include a fully rendered HTML snippet that we can drop right in the Head component of our page.

There’s a caveat though, because we’re using WordPress headless, some of the URLs are not pointed to the right place, such as the canonical link. You may be able to change this with the WordPress site URL and URL scheme, but you’ll need to verify that before relying on it, or you can customize it as it’s simply a string.

To get this snippet, the first thing you’ll want to do is add the fullHead field to the GraphQL query:

seo {
  metaDesc
  title
  fullHead
}

Just like before, if you console log out the seo object, you’ll now see a full string of HTML inside of the fullHead property.

Web console showing fully rendered Yoast SEO head html
HTML head rendered from Yoast SEO

The trick though is rendering this HTML. We can’t simply drop it in to the page because it’s a string. We also can’t use something like dangerouslySetInnerHTML because it’s full of elements and we’re using the Next.js Head component, which doesn’t support that.

Instead, we’re going to parse that HTML, transform it into React, and then add it right into our Head.

First, let’s install html-react-parser:

yarn add html-react-parser
# or
npm install html-react-parser --save

Next, import it into the src/pages/posts/[postSlug].js page:

import parse from 'html-react-parser';

Then at the top of the page component, transform that fullHead property into react:

const fullHead = parse(post.seo.fullHead);

And finally, replace all of the content with our new head:

<Head>{ fullHead }</Head>

When we load back up our page and check out our source, we can now see we have a ton of tags, where Yoast automatically is managing everything right for us.

Rendered HTML head from Yoast SEO
Yoast SEO full head HTML inside of Next.js

And just as reminder, we can also see that Yoast is using the WordPress host and URL scheme from the headless WordPress instance, so we’ll want to make sure we resolve that issue, otherwise we may negatively impact this page’s SEO!

Chrome inspector showing rendered HTML head with links using headless WordPress host
Yoast SEO using headless WordPress host for metadata tags

Follow along with the commit!

What’s next?

Take some time to explore Yoast SEO. There are a ton of features included with the free plugin that can help you customize what your website or application looks like on Google and other platforms.

There are also a ton of features like adding your social profiles and website verifications that allow you to manage those things right inside of WordPress instead of hard coding them into your project.

SEO is a critical part of helping your project grow, and whether managing the tags individually like Step 2 or with a fixed version of Step 3, we can take advantage of Yoast SEO and WPGraphQL to take our SEO to another level!