Top view, looking down at a spiral staircase

Gridsome Custom Paths with Wordpress

A while back I needed to include a “dynamic” term within my path.

With the help of @travis, I was going to post the answer, then totally forgot. Shame on me because years later I needed to revisit that same scenario.

I had set up a Wordpress custom taxonomy called galleries. (Think of galleries as Wordpress’ own categories.) Like any other taxonomy, it allowed for multiple terms, so I wanted my path to include the first term associated with the post.

The path would render something like this: /artwork/originals/the-artwork-title, where originals is the actual term. In Gridsome, it would be represented as galleries[0].slug.

I was confused for a couple reasons. For one, Templates - Gridsome states it’s possible to use the templates path as seen below.

// gridsome.config.js
module.exports = {
  templates: {
    WordPressArtworks: "/artwork/:galleries__0__slug/:slug",
  },
};

or

// gridsome.config.js
WordPressArtworks: [
  {
    path: (node) => {
      return `/artwork/${node.galleries[0].slug}/${node.slug}`;
    },
  },
];

Neither of above code examples work – at least for Wordpress – or to my knowledge. Maybe there’s a different approach? There’s a benefit of using templates as it will add a path node to the schema. However, simply injecting :galleries__0__slug will not render correctly.

Instead, galleries-0-slug was literally being rendered. Otherwise, it might be returned as undefined. Regardless, the galleries term will not be displayed properly.

Wordpress uses references and returns the id of the term, not the actual slug name.

@travis did a better job at explaining –

Gridsome just stores references to other nodes, and the GraphQL layer actually ‘links’ them together. So each object in categories will contain an id, and typeName (of the related node/s)

An example record when running console.log(node.galleries):

[{ typeName: "WordPressGalleries", id: "8" }];

The workaround (or solution?)

Use createPages (Pages API - Gridsome)

// gridsome.server.js
module.exports = function (api) {
  api.createPages(async ({ graphql, createPage }) => {
    const { data } = await graphql(`
      {
        allWordPressArtworks {
          edges {
            node {
              id
              slug
              galleries {
                id
                slug
              }
            }
          }
        }
      }
    `);

    data.allWordPressArtworks.edges.forEach(({ node }) => {
      createPage({
        path: `/artwork/${node.galleries[0].slug}/${node.slug}`,
        component: "./src/templates/WordPressArtworks.vue",
        context: {
          id: node.id,
        },
      });
    });
  });
};

Within the WordPressArtwork.vue template, the id needs to be specified. For clarity, here is an abbreviated page-query:

query WordPresArtworks($id: ID!) {
  wordPressArtworks(id: $id) {
    id
    slug
    galleries {
      id
      slug
    }
  }
}

Now within one my Vue pages, like Originals.vue, I can link to one of my single WordPressArtworks posts following this example:

<g-link
  :to="'/artwork/' + element.node.galleries[0].slug + '/' + element.node.slug"
></g-link>

Maybe the g-link component can be written more elegantly?

Unfortunately, I don’t get to use Vue often so I can’t answer that question. Although, I’ve been using Vue via Gridsome for a couple years, my learning has slowed down due to work and non-work. Perhaps, once Gridsome adopts Vue 3 it will rev me back up.

Article Credits

Photo by Himal Rana on Unsplash