Complete guide to Wordpress menu sourcing in Gatsby

11 Jul 19

Using the Gatsby plugin gatsby-source-wordpress we can fetch almost everything from a Wordpress website. There are only two things that were not there by default, the menus and the custom options. This blog post is about menus.

1. Preparing the menu

As I have just mentioned, the Wordpress menu are, by default, not available on the Wordpress REST api, so the first step is to make them visible.

We can make this easily with a Wordpress plugin WP REST API Menus that you can't find when you want to install it directly from your website.

You need to download it and use WordPress Admin Plugin Upload, here's a link to a tutorial if you don't know how the. Now that you have installed the plugin, your menus are available on the rest api.

WP-REST-API V2 Menus is not the good plugin to install.

2. The request:

After installing the plugin if you run gatsby develop a new GraphQL request will be available:

  • allWordpressWpApiMenusMenus to get the menus available
  • allWordpressWpApiMenusMenusItems to get the item of the menus
  • allWordpressWpApiMenusMenuLocations to get the available menu location

3. Useful request:

There are a lot of useful requests but in our case we just need to retrieve the menus and their items "content", and this is the request for that.

{
  allWordpressWpApiMenusMenusItems {
    edges {
      node {
        slug
        name
        items {
          title
          url
        }
      }
    }
  }
}

If your menu contains sub-menus use the wordpress_childer attribute

{
  allWordpressWpApiMenusMenusItems {
    edges {
      node {
        slug
        name
        items {
          title
          url
          wordpress_children {
            title
            url
          }
        }
      }
    }
  }
}

If you want to retrieve a specific menu use filters like this

{
  allWordpressWpApiMenusMenusItems(filter: { slug: { eq: "sidebar-menu" } }) {
    edges {
      node {
        slug
        name
        items {
          title
          url
          object_slug
          wordpress_children {
            title
            url
          }
        }
      }
    }
  }
}

4. Getting the menu

The complete code in a Gatsby component: Now that we have all what we need, this is a small component to display the Wordpress menu

import React from "react"
import { StaticQuery, graphql } from "gatsby"

export default () => (
  <StaticQuery
    query={graphql`
      query {
        allWordpressWpApiMenusMenusItems(
          filter: { slug: { eq: "sidebar-menu" } }
        ) {
          edges {
            node {
              slug
              name
              items {
                title
                url
                object_slug
                wordpress_children {
                  title
                  url
                }
              }
            }
          }
        }
      }
    `}
    render={data => {
      return (
        <nav className="menu">
          <ul className="nav flex-column">
            {data &&
              data.allWordpressWpApiMenusMenusItems &&
              data.allWordpressWpApiMenusMenusItems.edges &&
              data.allWordpressWpApiMenusMenusItems.edges[0] &&
              data.allWordpressWpApiMenusMenusItems.edges[0].node &&
              data.allWordpressWpApiMenusMenusItems.edges[0].node.items &&
              data.allWordpressWpApiMenusMenusItems.edges[0].node.items.map(
                prop => {
                  return (
                    <li className="nav-item">
                      <a
                        className="nav-link active"
                        href={prop.url}
                        alt={prop.title}
                      >
                        {prop.title}
                      </a>
                      <div className="sub-menu">
                        {prop &&
                          prop.wordpress_children &&
                          prop.wordpress_children.map(child => {
                            console.log("child ", child)

                            return (
                              <a
                                className="dropdown-item"
                                href={child.url}
                                alt={child.title}
                              >
                                {child.title}
                              </a>
                            )
                          })}
                      </div>
                    </li>
                  )
                }
              )}
          </ul>
        </nav>
      )
    }}
  />
)

5. The correct url

If your Wordpress domain name is not the same as your Gatsby website don't forget to replace them. In gatsby-config.js put this in the plugin declaration

searchAndReplaceContentUrls: {
    sourceUrl: "http://localhost:8080",
    replacementUrl: "http://localhost:8000",
}

here's the complete example:

{
  "resolve": "gatsby-source-wordpress",
  "options": {
    "baseUrl": "http://localhost:8080/",
    "protocol": "http",
    "hostingWPCOM": false,
    "useACF": false,
    "excludedRoutes": ["**/settings", "**/themes", "**/users/me"],
    "verboseOutput": true,
    "searchAndReplaceContentUrls": {
      "sourceUrl": "http://localhost:8080",
      "replacementUrl": "http://localhost:3000"
    }
  }
}

6. Conclusion

This is not always the good approach and sometime it's overkill, but it's nice to know everything about Wordpress's menus and their use in Gatsby. You might have another opinion or a different method. Please share your point of view with me in comment.