> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Going headless during your Gatsby builds

> Recently, Platform.

export const PostMeta = ({data = {}}) => {
  const {author, date, image} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (!image && authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
      {image && <img src={image} alt="" className="post-meta-image" aria-hidden="true" />}
    </div>;
};

<PostMeta data={{ author: ["chadwcarlson"], date: "2020-05-13", image: "/images/posts/unknown/headless-strapi-and-wordpress-content-with-gatsby-builds/headless-strapi-and-wordpress-content-with-gatsby-builds.webp" }} />

<Tip>
  This post was originally published on the Platform.sh blog and reflects information from the time of publication.
</Tip>

Recently, Platform.sh hosted a live stream on our [Deploy Friday](https://www.youtube.com/playlist?list=PLn5EpEMtxTCmLsbLgaN3djvEkRdp-YmlE) Q & A series called [Gatsby & headless CMS, including Strapi, Drupal, and Oracle Content & Experience](https://www.youtube.com/watch?v=H1WNHVXJiUg\&list=PLn5EpEMtxTCmLsbLgaN3djvEkRdp-YmlE). Robert Douglass and I met with representatives from Gatsby, Strapi, and Oracle to talk about one thing: the headless CMS and its relation to the static site generator, Gatsby.

So what's a "headless CMS?" It’s a development pattern that, inline with developing microservices, places importance on decoupling services from your primary application (i.e., Gatsby) to build your sites. That's the "headless" bit—some service serves something (e.g., ecommerce capabilities or authentication)—and a Gatsby site connects to that service and leverages its data when building the final app.

As for the CMS part of "headless CMS," the content your app is going to serve—articles and blog posts, for example—are actually edited and reside on a separate service. The content is served from that service and, in the case of Gatsby, is called upon during builds to fill out the main site, however you designate it to be displayed.

There’s an ecosystem of [source plugins](https://www.gatsbyjs.org/docs/plugins/) for Gatsby that can be configured to pull in this content at build time, delivering pre-rendered HTML as a result. Instead of pushing API calls to those servers client-side, they’re placed at build time, decreasing users’ page load time considerably. At the cost of a slightly longer build time, that's a pretty good advantage, and content only lags behind the backend CMS as far as the last build.

We can separate our content from our Gatsby application: engineers can focus on the site itself; creative contributors can add content to the backend easily; and users experience greater performance when they visit the site.

But will it deploy (on Platform.sh)? Of course!

## Deploying the headless CMS to Platform.sh

Platform.sh is the superior way to [deploy a headless application](https://upsun.com/blog/web-application-deployment-best-practices/). Why? Because with Platform. sh, you can run both the head (Gatsby) and the CMS (for example, WordPress or Strapi) with the same tools, the same development process, and the same SLAs—without additional vendor relationships or costs.

Let’s get started with our [multiapp](https://docs.platform.sh/configuration/app/multi-app.html) project. First, we'll go into a little detail about how we can configure a two-application Gatsby project with either [Strapi](https://strapi.io/) or [WordPress](https://wordpress.org/) as the backend.

### Overview

For both Strapi and WordPress backends, we're going to use the same multiapp project structure:

```
.platform/
gatsby/
  .platform.app.yaml
  <application code>
  gatsby-config.js
<backend>/
  .platform.app.yaml
  <application code>
```

Our Gatsby application is isolated to the `gatsby` subdirectory, and either backend code we use will also be located in its own subdirectory. Each app will have its own <a href="https://docs.platform.sh/overview/yaml/what-is-yaml.html">`.platform.app.yaml`</a> file to describe its `type`, `name`, `build` process and how to start it.

<div class="emphasize">
  <div class="inner">
    <p>
      <strong>Note:</strong>
      <p>This post focuses primarily on deploying Gatsby with a connected backend CMS, rather than the details specific to writing new `components` and `templates` in Gatsby to display content. Both templates—<a href="https://github.com/platformsh-templates/gatsby-strapi">Gatsby with Strapi</a> and <a href="https://github.com/platformsh-templates/gatsby-wordpress">Gatsby with WordPress</a>—are based on separate tutorials from <a href="https://strapi.io/blog/build-a-static-blog-with-gatsby-and-strapi">Strapi</a> and <a href="https://www.gatsbyjs.org/tutorial/wordpress-source-plugin-tutorial/">Gatsby</a> that, respectively, go into much more detail—if you’re interested in building those pages from scratch.</p>
    </p>
  </div>

  <div class="accent" />
</div>

The primary file we'll be concerned with modifying for both of our backends is the `gatsby/gatsby-config.js`. Inside that file, we can define all of the [source plugins](https://www.gatsbyjs.org/docs/plugins/) that will actually add our backend content to the Gatsby data layer using GraphQL. That file has the following structure:

```js theme={null}
module.exports = {
  siteMetadata: {
    title: "My site",
    description: "Description of site",
    author: "Chad Carlson",
  },
  plugins: [
    "gatsby-plugin-without-settings",
    {
      resolve: `gatsby-plugin-with-settings`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    ...
  ],
}
```

We’re going to add a source plugin to this `plugins` attribute for each backend:

* [`gatsby-source-strapi`](https://www.gatsbyjs.org/packages/gatsby-source-strapi/)
* [`gatsby-source-wordpress`](https://www.gatsbyjs.org/packages/gatsby-source-wordpress/)

During builds, Gatsby will use these modules to place queries against the backend app, making content accessible to display on the site. We're also going to use the [Node.js Config Reader library](https://github.com/platformsh/config-reader-nodejs) to access the backend relationship within our `gatsby-config.js` file, by adding it to the `options` for each of the source plugins listed above. So, we need to add it to our dependencies:

```sh theme={null}
yarn add platformsh-config
```

and import it in the first line of `gatsby-config.js`:

```js theme={null}
const config = require("platformsh-config").config();
```

Finally, we're going to modify how our [Gatsby template](https://github.com/platformsh-templates/gatsby) typically builds on Platform.sh for both backends:

```yaml theme={null}
name: gatsby

type: "nodejs:12"

hooks:
  post_deploy: |
    npm run build

relationships:
  <backend>: "<backend>:http"

web:
  locations:
    "/":
      root: "public"
      index: ["index.html"]
      scripts: false
      allow: true

disk: 1024

mounts:
  "/.cache":
    source: local
    source_path: cache
  "public":
    source: local
    source_path: public
```

The above file includes a relationship to the backend application; we’ll use this relationship to provide content to Gatsby. Notice that we've moved Gatsby's build process from the `build` hook to the `post_deploy` hook. Now that we’ve granted access to the backend with a relationship, it won’t be available until after the deploy hook. We still need to get that content to Gatsby, so we've moved `npm run build` to the `post_deploy` hook to get around this, and given write access to the `.cache` and `public` directories that will be created.

### Pulling Strapi content into Gatsby

For Strapi, we're going to place all of our code inside a `strapi` subdirectory, and name the application `strapi` in its `.platform.app.yaml` file.

If you haven't already tried Strapi, I’d recommend you do. Strapi is a headless CMS that provides a simple UI that makes building APIs super simple. If you compare our [Strapi template](https://github.com/platformsh-templates/strapi) to the contents of the `strapi` subdirectory of the [Gatsby-Strapi template](https://github.com/platformsh-templates/gatsby-strapi), you'll see that the code is identical except for a single line.

Namely in the build script `build.sh`, we've added the following:

```sh theme={null}
yarn strapi install graphql
```

This line installs the GraphQL plugin, allowing GraphQL queries to be placed on the API Strapi automatically builds out.

In our `routes.yaml` file, we define three routes for our two applications. Two upstreams and a redirect:

```yaml theme={null}
"https://www.{default}/":
  type: upstream
  upstream: "gatsby:http"

"https://{default}/":
  type: redirect
  to: "https://www.{default}/"

"https://backend.{default}/":
  type: upstream
  upstream: "strapi:http"
```

Our installation of Strapi is going to use PostgreSQL to store its data, so we also add that service definition to our projects `services.yaml` file:

```yaml theme={null}
dbpostgres:
  type: postgresql:12
  disk: 256
```

Okay, those are all the changes we need to make to Strapi to set this up. What about Gatsby?

First, we can modify the `relationships` block of Gatsby's `.platform.app.yaml` file now that we've named the Strapi app:

```yaml theme={null}
relationships:
  strapi: "strapi:http"
```

Second, we need to add the source plugin for Strapi ([`gatsby-source-strapi`](https://www.gatsbyjs.org/packages/gatsby-source-strapi/)) to our dependencies with the following command:

```sh theme={null}
yarn add gatsby-source-strapi
```

So that we can add the following block to the `plugins` attribute of our `gatsby-config.js` file:

```js theme={null}
// gatsby-config.js
  plugins: [
    ...
    {
      resolve: "gatsby-source-strapi",
      options: {
        apiURL: `http://${config.credentials("strapi")["host"]}`,
        contentTypes: [
          "article",
          "category",
        ],
        queryLimit: 1000,
    },
    ...
  ]
```

Here, instead of providing a static URL for the Strapi backend, we're using the [Node.js Config Reader library](https://github.com/platformsh/config-reader-nodejs) to look up the `strapi` relationship and build a string for that URL.

We've also defined the two primary `contentTypes` we want Gatsby to be concerned about: `articles` and `categories`. All calls to Strapi will be concerned with these two endpoints, so we’ll need to add them to Strapi for this to work (more on this later).

In Gatsby, we can control how our Strapi content is displayed by templating GraphQL queries in our `pages`, `components`, and `template` scripts. The tutorial our template is based on goes into much greater detail about these changes, but we can look at one example from our `src/pages/index.js` file, which lists all of the articles or blog posts served from Strapi:

```js theme={null}
import React from "react";
import { StaticQuery, graphql } from "gatsby";

import Layout from "../components/layout";
import ArticlesComponent from "../components/articles";

import "../assets/css/main.css";

const IndexPage = () => (
  <Layout>
    <StaticQuery
      query={graphql`
        query {
          allStrapiArticle {
            edges {
              node {
                strapiId
                title
                category {
                  name
                }
                image {
                  publicURL
                }
              }
            }
          }
        }
      `}
      render={data => (
        <div className="uk-section">
          <div className="uk-container uk-container-large">
            <h1>Strapi blog</h1>
            <ArticlesComponent articles={data.allStrapiArticle.edges} />
          </div>
        </div>
      )}
    />
  </Layout>
);

export default IndexPage;
```

This file builds the index page by placing a `StaticQuery` on Strapi, retrieving all of its articles and using the `ArticlesComponent` defined in `components/articles.js` to display their images, title, and a snippet of their content.

<div class="emphasize">
  <div class="inner">
    <p>
      <strong>Note:</strong>
      <p>You can find all the `components` and `templates` updates either in the original <a href="https://strapi.io/blog/build-a-static-blog-with-gatsby-and-strapi">tutorial</a> or in our <a href="https://github.com/platformsh-templates/gatsby-strapi">template</a>.</p>
    </p>
  </div>

  <div class="accent" />
</div>

Now, we can deploy our repository to Plaform.sh. When we do so, however, our primary route for our `Master` environment is going to give us a 403 response; this is expected. Gatsby is trying to pull content from Strapi, when Strapi hasn't been set up with any content to serve. So let's add some.

If we visit the `backend.<generated-url>` URLfor our environment, Strapi will prompt us to first create an admin user. Once we do that, we'll have access to the admin dashboard and begin creating our content types.

In our Gatsby app, we specified that we wanted two content types: `article` and `category`. We create an `article` collection so that every article we post contains the required fields `title`, `content`, `image`, and `published_at` for the publish date. Then create a `category` collection with only the single field `name`. Finally, we add a "Relation" field to `article` to `category`, such that a category contains many articles.

<div class="emphasize">
  <div class="inner">
    <p>
      <strong>Note:</strong>
      You can find more detailed information about these steps in the <a href="https://github.com/platformsh-templates/gatsby-strapi/blob/master/README.md">template's README</a>.
    </p>
  </div>

  <div class="accent" />
</div>

We save our changes and add a test article that belongs to some test category. Once we do, we can modify our permissions to make the `articles` and `categories` endpoints public.

Now that we have content being served from our Strapi backend, we can redeploy the project with the command `platform redeploy`, and our Gatsby app will pull that content when it builds.

### Pulling WordPress content into Gatsby

Setting up WordPress to deploy with Gatsby is very similar to Strapi. We're going to put all of our WordPress code in a `wordpress` subdirectory. Then name the app `wordpress`, and modify the backend route we described previously to match:

```yaml theme={null}
"https://backend.{default}/":
  type: upstream
  upstream: "wordpress:http"
```

Our standard WordPress template uses MariaDB instead of PostgreSQL, so we'll need to update our `services.yaml` file as well:

```yaml theme={null}
db:
  type: mariadb:10.4
  disk: 512
```

Now, let's update our Gatsby application. First, the `relationships` block needs to match WordPress in its `.platform.app.yaml`:

```yaml theme={null}
relationships:
  wordpress: "wordpress:http"
```

Then we'll need to update `gatsby-config.js` to use the `gatsby-source-wordpress` plugin, instead, by first installing it

```sh theme={null}
yarn add gatsby-source-wordpress
```

and including it in `gatsby-config.js`:

```js theme={null}
// gatsby-config.js
  plugins: [
    ...
    {
      resolve: `gatsby-source-wordpress`,
      options: {
        baseUrl: config.credentials("wordpress")["host"],
        protocol: `http`,
        hostingWPCOM: false,
        useACF: true,
      },
    },
    ...
  ]
```

Just like Strapi, we define the URL for the backend, this time with the `wordpress` relationship. We don’t need to include the `http://` with that URL, because `gatsby-source-wordpress` provides a separate `protol` attribute to include it. We don’t need to specify `contentTypes` in this case, either.

If we take a look at our `pages/index.js` as its modified for WordPress, we can see that it looks very similar to Strapi, but has been modified to the specific queries that need to be placed on the built-in Wordpress's GraphQL, using `allWordpressPost` instead:

```js theme={null}
import React from "react";
import { Link, graphql } from "gatsby";
import Layout from "../components/layout";
import SEO from "../components/seo";

export default ({ data }) => {
  return (
    <Layout>
      <SEO title="home" />
      <h1>My Gatsby Blog (using a Wordpress backend)</h1>
      <h4>Posts</h4>
      {data.allWordpressPost.edges.map(({ node }) => (
        <div key={node.slug}>
          <Link to={node.slug}>
            <p>{node.title}</p>
          </Link>
          <div dangerouslySetInnerHTML={{ __html: node.excerpt }} />
        </div>
      ))}
    </Layout>
  );
};

export const pageQuery = graphql`
  query {
    allWordpressPost(sort: { fields: [date] }) {
      edges {
        node {
          title
          excerpt
          slug
        }
      }
    }
  }
`;
```

<div class="emphasize">
  <div class="inner">
    <p>
      <strong>Note:</strong>
      To find the detailed changes made to Gatsby's components and templates to display WordPress content, either consult the original <a href="https://www.gatsbyjs.org/tutorial/wordpress-source-plugin-tutorial/">tutorial</a> or deploy our <a href="https://github.com/platformsh-templates/gatsby-wordpress">template</a> directly.
    </p>
  </div>

  <div class="accent" />
</div>

Now that our code has been set up, we push to Platform.sh, and run into the same 403 response we did with Strapi. In this case, it's because WordPress has not been fully installed on that container yet. We just need to visit the `backend.<generated-url>` URL for our environment, and complete the installation.

When the install has completed, WordPress already comes with a starter "Hello world" post, so there’s no need to create any additional content. After, we once again `platform redeploy`, and our Gatsby WordPress app is off and running!

## Simple, straightforward headless CMS pattern deployment

Deploying the headless CMS pattern on Platform.sh is simple and straightforward once you define your cluster. The great thing is that your team can focus on developing the app itself, leveraging best-in-class source plugins, rather than reinventing the wheel for each added feature. Same goes for content.

With a few changes, we got Gatsby talking to both a Strapi and a WordPress backend, pulling in content to build the final application. I invite you to try it out yourself with the resources below. Take care!

<div class="emphasize">
  <div class="inner">
    <p>
      Our webinar that explores Gatsby and the headless CMS pattern is now available on demand. Be sure to check it out below, and click on through to the YouTube playlist to see the rest of the series.

      <iframe width="100%" height="585" src="https://www.youtube-nocookie.com/embed/iHJZIWnv-2s" frameborder="0" allowfullscreen />
    </p>
  </div>

  <div class="accent" />
</div>

## Resources and references

* [Platform.sh multiapp documentation](https://docs.platform.sh/configuration/app/multi-app.html)
* [Deploy Friday: E02 Gatsby & headless CMS, including Strapi, Drupal, and Oracle Content & Experience](https://www.youtube.com/watch?v=H1WNHVXJiUg\&list=PLn5EpEMtxTCmLsbLgaN3djvEkRdp-YmlE)
* [Gatsby + Strapi template](https://github.com/platformsh-templates/gatsby-strapi)
* [`gatsby-source-strapi` documentation](https://www.gatsbyjs.org/packages/gatsby-source-strapi/)
* [Blog: Build a static blog with Gatsby and Strapi](https://strapi.io/blog/build-a-static-blog-with-gatsby-and-strapi)
* [Gatsby + WordPress template](https://github.com/platformsh-templates/gatsby-wordpress)
* [`gatsby-source-wordpress` documentation](https://www.gatsbyjs.org/packages/gatsby-source-wordpress/)
* [WordPress Source Plugin Tutorial](https://www.gatsbyjs.org/tutorial/wordpress-source-plugin-tutorial/)
