Integrating WordPress on App Service with Azure Static Web Apps
Published Feb 13 2024 06:45 AM 2,514 Views

Azure Static Web Apps is the ideal service to host static content sites on Azure. Many static sites are built using content from content management systems (CMS) into static assets and then deployed to Azure Static Web Apps. In this article, we take a look at using Wordpress on App Service as a headless CMS for a static site hosted on Azure Static Web Apps.

 

Evolution of traditional CMS's to headless CMS's

 

A content website generally involves 2 artifacts: the website code itself, and the articles that make up the website content. To build such websites, content management systems (CMS) are ideal tools to provide purpose-built editing experiences for content editors.

 

Traditional CMS's such as WordPress provide both the ability to edit content and the website code itself. They provide a what-you-see-is-what-you-get (WYSIWYG) editor to design the website itself, multiple pre-built themes and plugins that allow you to design how the final website will look, in addition to a rich editing interface to write and review content.

 

Over time however, headless CMS's have increased in popularity, decoupling the content management experience from the website building experience. For instance, headless CMS's such as Contentful and Strapi focus solely on the content editing experience, and provide APIs and configurations for frontend web developers to use to include the content in their custom-built frontends.

 

Pro's & Con's of Headless CMS's

 

Headless CMS's provide a similar content editing experience as traditional CMS's, but leave the website design and hosting as the development team's responsibility. This provides a decoupled architecture, allowing greater flexibility with how the content is used and accessed, whether that be from various devices, sites or channels. This also provides more flexibility with hosting architectures. This additional flexibility does mean additional development, and this tradeoff must be considered.

 

In contrast, traditional CMS' monolithic structure enable rapid development with their WYSIWYG website editors and themes, a simpler deployment, but may be more limited in terms of flexibility, configuration, and hosting depending on your requirements.

 

As always, the tradeoffs of each will help you decide which is most appropriate for your scenario. Luckily, today, many traditional CMS's can also be used as a headless CMS, such that you can start by using the rapid development enabled by a traditional CMS, and migrate to a headless mode with a custom frontend when your requirements grow beyond what a WYSIWYG editor can offer.

 

Using Azure WordPress on App Service as a headless CMS

 

Many teams today use Azure's WordPress on App Service as a traditional CMS. It's also possible to use WordPress on App Service as a headless CMS, thereby decoupling the content layer (the written articles, pages) from the presentation layer (the actual website, HTML/CSS/JS, etc.) of the content website. This can be a convenient option in the case where a team wants to have more flexibility regarding the presentation layer and write their custom frontend for their content website.

 

thomasgauvinmsft_0-1702147868541.png

 

In this article, we'll detail how a WordPress on App Service instance can be configured as a headless CMS and show how it can be used as a content source for a sample frontend website, in this case, built with NextJS and hosted on Azure Static Web Apps. By the end of the article, we'll have built a custom frontend site that uses the content from our WordPress instance, hosted on Azure Static Web Apps: Azure Static Web Apps + WordPress (4.azurestaticapps.net)

 

Here are the steps required to use WordPress on App Service as a headless CMS for a Static Web Apps-hosted site:

  1. Create a WordPress on App Service instance
  2. Create a Static Web Apps instance with a sample NextJS project and consume the content provided by the headless CMS
  3. Configure the WordPress on App Service to trigger new builds of your Static Web App

Let's jump into it!

 

Step 1: Create a WordPress on App Service instance (if it does not exist yet)

 

This guide was written to enable anyone to create such an architecture. If you already have a WordPress on App Service instance, you may skip this step.

 

We’ll start by creating our WordPress on App Service instance, which will provide our content in the form of blog articles, posts, and pages.

 

thomasgauvinmsft_1-1702147868549.png

 

To create a WordPress on App Service instance, navigate to the Azure Portal and search for 'WordPress on App Service'. This will show up in the Azure Marketplace as a Microsoft service.

 

thomasgauvinmsft_2-1702147868559.png

 

 

thomasgauvinmsft_3-1702147868565.png

 

thomasgauvinmsft_4-1702147868573.png

 

Once the WordPress on Azure instance is created, we can access our site by clicking on the "Browse" button, or the default domain. In my case, that's demo-headless-wordpress-for-swa.azurewebsites.net. This takes us to the sample template that has been pre-deployed to our WordPress instance when we created the WordPress on App Service resource.

 

thomasgauvinmsft_5-1702147868577.png

 

We can now access the WordPress Admin Dashboard by appending /wp-admin/ to our URL and providing our login credentials. The WordPress Admin Dashboard will provide the content editing interface that a headless CMS provides. From this dashboard, we can create new posts, and add media. When WordPress is used as a traditional CMS, the dashboard also enables editing the website, but we won't be using this functionality as the website will be built in a separate frontend code project.

 

thomasgauvinmsft_6-1702147868586.png

 

Now that we have created our WordPress instance, we have a place where we can edit posts and the media of our website. This will be our headless content management system.

 

By default, the WordPress instance provides API access to all the content contained within our WordPress instance. This API access will enable us to pull the data from WordPress into our static website project. For instance, we can access all posts at the https://demo-headless-wordpress-for-swa.azurewebsites.net/wp-json/wp/v2/posts URL, and we can access specific posts with the https://demo-headless-wordpress-for-swa.azurewebsites.net/wp-json/wp/v2/posts/1 URL. In addition, we can access our images and media via the https://demo-headless-wordpress-for-swa.azurewebsites.net/wp-json/wp/v2/media URL. For full reference on the available API endpoints, refer to the WordPress developer documentation on REST APIs.

 

thomasgauvinmsft_7-1702147868596.png

 

Step 2: Update your frontend web app to pull content from the WordPress CMS

 

Now is the fun part: the main objective in decoupling the presentation layer from our WordPress instance is to have full flexibility to build and host the website using the technology of our choice. In this case, I'll demonstrate how we can build a sample frontend web app that pulls content from the WordPress instance to demonstrate how to use the WordPress REST API. This will be just a simple example of what can be done using WordPress as a headless CMS, but the potential to develop a tailored solution goes well beyond this.

 

 

thomasgauvinmsft_8-1702147868601.png

 

For this sample frontend web app, we'll be building a static site using Next.js, a frontend JavaScript framework. In this project, we'll be pulling the written content from the WordPress instance via the REST API, treating the WordPress instance as a headless CMS. Note that while we’re demonstrating Next.js, this could be achieved with any other frontend framework or static site generator. Our Next.js content website will be decoupled and hosted separately from our WordPress instance, in this case, hosted on Azure Static Web Apps.

 

To make it easier to follow along, we've published a template of the Next.js application that we built for this article which can be accessed here: thomasgauvin/swa-with-headless-wordpress: Sample Static Web Apps site with headless Wordpress on App.... Types are omitted from the below code snippets for simplicity, though they are present in the template.

 

Since this article focuses on the integration with WordPress, the styling is omitted from this tutorial. All styling can be accessed in the Next.js template GitHub repository.

 

Step 2.1: Create a new Next.js project

 

To create a new Next.js project, we'll run the following command in a terminal:

 

 

npx create-next-app@latest

 

 

After this, we can open our project with a code editor (such as VSCode) and start consuming the REST APIs made available by our WordPress content. To run the development server, we can run the following command:

 

 

npm run dev

 

 

We'll now add the code to pull the content from the WordPress instance. Before we start, we'll add the URL of your WordPress site as an environment variable. We'll create a .env in the root of our project, and add the following line. With this, we'll be able to easily access our WordPress URL throughout our project.

 

 

WORDPRESS_URL = "<ENTER YOUR WORDPRESS URL HERE>"

 

 

For this sample, we'll commit the .env file into our repository as it does not represent a secret. However, if you use your .env file to store secrets, set your environment variables securely within your GitHub Actions/build configurations instead of relying on the .env file. 

 

Step 2.2: List all posts in the homepage

 

We'll first start by listing all posts in the homepage of our website. In the /app/page.tsx file, we'll add the following fetch call to get the posts from our WordPress instance in our Home component, and then render them in the page.

 

 

import Link from 'next/link';

export default async function Home() {

  const wordpressUrl = process.env.WORDPRESS_URL;
  const response = await fetch(`${wordpressUrl}/wp-json/wp/v2/posts?_embed`);
  const posts: any = await response.json();

  return (
    <main className="w-full max-w-4xl m-auto">
      {posts.map((post: any) => (
          <Link href={`/post/${post.slug}`} key={post.slug}>
            <div>
              slug: {post.slug}
              title: {post.title.rendered}
              excerpt: {post.excerpt.rendered}
              imageUrl: {post._embedded ? post._embedded['wp:featuredmedia'] ? post._embedded['wp:featuredmedia'][0].source_url : '' : ''}
            </div>
            <br />
          </Link>
      ))}
    </main>
  )
}

 

 

We can then add some styling to show a card of the post, which can be clicked to access the full post.

Since this article focuses on the integration with WordPress, the styling is omitted from this tutorial. All styling can be accessed in the Next.js template GitHub repository.

 

 

thomasgauvinmsft_9-1702147868641.png

 

 

Step 2.3: Create a page for individual posts

 

Now, we'll create a new file /app/post/[slug]/page.tsx which will contain a component for pages of individual posts. In this file, we'll access the slug of the WordPress post from the URL parameters, fetch the post from the WordPress REST API, and then display it.

 

Note: Next.js uses a file-system based router, such that the actual file path represents the routing of our site. In this case, the /app/post/[slug]/page.tsx file will represent the /post/some-sample-slug page, where some-sample-slug will be accessible as a page parameter in our Next.js component.

 

 

const wordpressUrl = process.env.WORDPRESS_URL;

export default async function BlogPage({ params }: { params: { slug: string } }) {  
    const response = await fetch(`${wordpressUrl}/wp-json/wp/v2/posts/?slug=${params.slug}&_embed`);
    const post: any = (await response.json())[0];

    return (
      <div>
        title: {post.title.rendered}
        <br />
        content: {post.content.rendered}
      </div>
    );
};

 

 

Adding a bit of styling , we can now display the full contents, the authors, any attached images and more.

 

thomasgauvinmsft_10-1702147868674.png

 

We can also replicate steps 2.2 and 2.3 for WordPress pages and other elements of our WordPress site we want to surface in our custom site. In the template repository that accompanies this blog, we’ve added more styling to the site and surfaced the pages of our WordPress site, to obtain the following:

 

thomasgauvinmsft_11-1702147868704.png

 

thomasgauvinmsft_12-1702147868714.png

 

Step 2.4: (Next.js-specific) Configure static output for Next.js

 

Since we're using Next.js with static output to get optimal performance for our content site, we can configure a static export of our site by editing next.config.js as such:

 

 

const nextConfig = {
    output: 'export',
    …
}

module.exports = nextConfig

 

 

For the static site export, we’ll need to indicate each of the potential paths of our site at build time. We can do so by using the generateStaticParams function to return an array of all possible paths for our post pages. This function will then be called by the Next.js build action, which will use these paths in order to pre-generate the static HTML for each of these pages. Add the following code to the /app/post/[slug]/page.tsx file.

 

 

export async function generateStaticParams(){
  const response = await fetch(`${wordpressUrl}/wp-json/wp/v2/posts?_fields[]=slug`);
  const posts = await response.json();
  const paths = posts.map(post => ({
    slug: post.slug
  }));
  return paths;
}

 

 

We will do the same for the /app/page/[slug]/page.tsx file.

Now, when running npm run build, we'll get an out folder with the static files that make up our website.

 

Step 2.5: (Next.js-specific) Configure images for Next.js

 

If you use images in your Next.js project, you will need to specify the remotePatterns needed to allow Next.js to access the images from your WordPress instance. Also, if you plan to use the Next Image feature, you will need to specify that images are unoptimized or use a custom handler. Here's what our next configuration will look like:

 

 

const nextConfig = {
    output: 'export',
    images: {
        unoptimized: true,
        remotePatterns: [
            {
                protocol: 'https',
                hostname: <ENTER HOSTNAME FOR YOUR WORDPRESS CMS SITE>,
                port: '',
            },
            {
                protocol: 'https',
                hostname: 'secure.gravatar.com',
                port: '',
            }
        ]
    }
}

module.exports = nextConfig

 

 

 

Step 3: Deploy your frontend web app to Azure Static Web Apps

 

thomasgauvinmsft_13-1702147868719.png

 

 

Step 3.1: Create a GitHub repository for your project

 

Now, we'll create a GitHub repository for our Next.js project. This will make it convenient for deploying to Static Web Apps and allow us to leverage GitHub Actions to have new builds & deployments of the website when WordPress content changes. For instance, for this project, I've created this sample repository:

 

thomasgauvinmsft_14-1702147868746.png

 

Step 3.2: Create a Static Web Apps resource for this repository

 

With this repository, we can create a Static Web Apps resource from the Azure Portal or by following another method mentioned in the Azure Static Web Apps documentation. For our build details, we’ll specify that this is a Next.js project.

 

Step 3.3: (Next.js-specific) Configure the Next.js project and GitHub Actions workflow for the Static Web Apps deploy action

 

With Next.js 14, NodeJS 18 is required to build the project. To specify the Node version needed for the build action configured for Static Web Apps, we can add the following engines specification to the package.json file of our Next.js project:

 

 

{
   …
   "engines": {
    "node": ">=18.17.0"
  }
…
}

 

 

Since we are exporting our Next.js project to a static site, we'll configure our GitHub Actions to indicate this in the Build and Deploy step for Static Web Apps. We'll add the environment variable IS_STATIC_EXPORT: true, and output_location: “out” to the build and deploy job as such:

 

 

[...]

jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') || github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
          lfs: false
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PURPLE_WATER_0F95B5510 }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: "upload"
          ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
          # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
          app_location: "/" # App source code path
          api_location: "" # Api source code path - optional
          output_location: "out" # Built app content directory - optional
          ###### End of Repository/Build Configurations ######
        env: # Add environment variables here
          IS_STATIC_EXPORT: true
[...]

 

 

We now have a deployed Next.js project on Azure Static Web Apps, that is fetching its content at build time from our WordPress on App Service instance. Excellent! Your site should look like Azure Static Web Apps + WordPress (4.azurestaticapps.net).

 

Step 4: Configure your WordPress instance and GitHub Actions to trigger new builds for WordPress changes

 

 

thomasgauvinmsft_15-1702147868751.png

 

Our last step will be to configure our WordPress instance to trigger new builds & deployments of our Next.js project when changes on our WordPress CMS require these. For instance, we want to ensure that when a content writer publishes edits to a post of new posts, our GitHub Actions is retriggered to build and deploy our Next.js project to the Static Web Apps resource.

To do so, we can make use of a WordPress plugin that allows us to use the GitHub API in order to trigger new workflow runs for our GitHub Actions.

 

Step 4.1: Add & configure a plugin to your WordPress instance that will trigger new GitHub Actions upon edits

 

While you can use any plugin that allows you to trigger new GitHub Actions builds, we’ve written a custom WordPress plugin that requires minimal setup and will trigger new builds on edits to published or new posts or pages for the sake of this tutorial. For this tutorial, you can download the custom plugin as a zip file from thomasgauvin/trigger-github-action-plugin-for-wordpress: This WordPress plugin can trigger a GitHub ... If you want further productionize and customize the behavior of this plugin, you can do so by making edits to the source code of this plugin.

 

In our WordPress admin dashboard, we can now upload the zip file of this plugin.

 

thomasgauvinmsft_16-1702147868769.png

 

After installation, we can activate the plugin and configure it. To configure this project, we’ll need to indicate the GitHub repository URL of the project containing GitHub Actions we want to trigger on new changes. Moreover, we’ll need to provide a GitHub Personal Access Token that has access to trigger GitHub Actions runs for our repository.

 

thomasgauvinmsft_17-1702147868780.png

 

At this point, if you`ve configured your Trigger GitHub Action plugin correctly, you’ll receive a success message indicating that your GitHub Personal Access Token and repository are valid. Manually triggering the workflow, you’ll see an error message indicating that we must allow workflow dispatch for our repository. We’ll do that in the next step.

 

thomasgauvinmsft_18-1702147868793.png

 

Step 4.2: Configure your Static Web Apps GitHub Actions workflow to accept manual deployments

 

Our GitHub Actions workflow for Azure Static Web Apps deployment is currently only configured to execute on pushes or pull requests to specific branches. In the /.github/workflows/<default-SWA-domain-hash>.yml, we’ll edit the `on` section to indicate that our workflow should be triggered on `workflow_dispatch:`. We’ll also edit the build_and_deploy_job to run if the github.event_name is equal to  'workflow_dispatch'.

 

 

name: Azure Static Web Apps CI/CD

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - main
  workflow_dispatch:

jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') || github.event_name == 'workflow_dispatch'
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
          lfs: false
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
…

 

 

Once we’ve made these changes, we’ll once again commit & push to our repository. To validate these edits are correctly working, we can validate once again by clicking on the Manual trigger button and noticing that the message indicates our workflow trigger successfully.

 

thomasgauvinmsft_19-1702147868804.png

 

Now, when we make creates or edits to published posts or pages, the Trigger GitHub Action plugin will activate and trigger the GitHub Action workflow to build and deploy a new version of our Next.js static site to our Azure Static Web Apps resource. During the build process, the Next.js site will use the newly updated posts or pages such that these changes will be made visible when the deployment finishes.

 

Conclusion

 

In this article, we demonstrated how to use WordPress as a headless CMS for an Azure Static Web Apps-hosted site. We first created a WordPress on App Service instance to be used as a headless CMS, and investigated how we can use the APIs of our WordPress instance to access the content. We also created a custom frontend site with Next.js to demonstrate how to use the content from the WordPress instance to create our site, with the demo application hosted here: Azure Static Web Apps + WordPress (4.azurestaticapps.net). We also installed a custom WordPress plugin to automatically trigger new builds and deployments of the Next.js site whenever the WordPress content is updated. By using WordPress as a headless CMS, we can take advantage of its rich editor experience for content teams, while having full flexibility over the frontend code and the presentation layer.

 

Get started with WordPress on App Service and Azure Static Web Apps for free

 

Co-Authors
Version history
Last update:
‎Mar 10 2024 08:14 PM
Updated by: