Skip to content

mohatt/gatsby-plugin-advanced-pages

Repository files navigation

Gatsby Advanced Pages

Gatsby Advanced Pages is a wrapper around Gatsby's createPage API, making it easier to create pages with advanced features like pagination and custom routing.

Installation

Install using npm:

npm install gatsby-plugin-advanced-pages

Or with Yarn:

yarn add gatsby-plugin-advanced-pages

Demo

Check out the example directory for sample implementations.

A live demo is available at: mohatt.github.io/gatsby-plugin-advanced-pages.

Usage

To enable the plugin, add it to your gatsby-config.js:

plugins: [
  {
    resolve: 'gatsby-plugin-advanced-pages',
    options: {
      // Plugin options goes here
    },
  },
]

TypeScript

The plugin is fully type-safe and provides comprehensive TypeScript typings for all its exports.

if you’re using Typescript, add it to your gatsby-config.ts like this:

import type { PluginOptions as AdvancedPagesOptions } from 'gatsby-plugin-advanced-pages/node'

plugins: [
  {
    resolve: 'gatsby-plugin-advanced-pages',
    options: {
      // Plugin options goes here
    } as AdvancedPagesOptions,
  },
]

Creating pages

To create a new page, define your routes in pages.config.yaml (or JSON/JS) at the root of your project:

# pages.config.yaml
- title: Hello, World
  template: hello.js
  routes:
    hello: /hello

Next, create the corresponding template file under src/templates:

// src/templates/hello.js
import * as React from 'react'
import { graphql } from 'gatsby'

const HelloPage = ({ data }) => (
  <div>
    <h1>{data.page.title}</h1>
    <p>Welcome to Gatsby Advanced Pages!</p>
  </div>
)

export const query = graphql`
  query HelloPageQuery($id: String!) {
    page(id: { eq: $id }) {
      title
    }
  }
`

export default WelcomePage

Run gatsby develop, then visit http://localhost/hello to see your new page.

Page helpers

For more advanced pages, define a page helper function that runs in Gatsby’s createPage lifecycle.

For example, to create a blog index page with pagination, first update pages.config.yaml:

Note: You will need gatsby-transformer-remark plugin installed for this example to work

# pages.config.yaml
- title: Blog
  routes:
    blog: /blog
  template: blog-template.js
  helper: blog-helper.js

Next, create the page helper under gatsby/pages

// gatsby/pages/blog-helper.js
module.exports = async function ({ graphql, page, createAdvancedPage }) {
  const result = await graphql(`
    {
      allMarkdownRemark(filter: { frontmatter: { type: { eq: "post" } } }) {
        totalCount
      }
    }
  `)

  if (result.errors) {
    throw result.errors
  }

  createAdvancedPage({
    route: 'blog',
    pagination: {
      count: result.data.allMarkdownRemark.totalCount,
      limit: 3,
    },
  })
}

Finally, create the template file under src/templates:

// src/templates/blog-template.js
import * as React from 'react'
import { graphql } from 'gatsby'
import { Pagination } from 'gatsby-plugin-advanced-pages'

const BlogTemplate = ({ data }) => (
  <div>
    <h1>{data.page.title}</h1>
    <div>
      {data.allMarkdownRemark.edges.map(({ node }) => (
        <div key={node.frontmatter.slug}>
          <h2>{node.frontmatter.title}</h2>
          <p>{node.excerpt}</p>
        </div>
      ))}
    </div>
    <Pagination route='blog' pageInfo={data.allMarkdownRemark.pageInfo} ui='simple' />
  </div>
)

export const query = graphql`
  query BlogQuery($id: String!, $limit: Int!, $offset: Int!) {
    page(id: { eq: $id }) {
      title
    }
    allMarkdownRemark(
      limit: $limit
      skip: $offset
      filter: { frontmatter: { type: { eq: "post" } } }
    ) {
      edges {
        node {
          frontmatter {
            title
            slug
          }
          excerpt(pruneLength: 200)
        }
      }
      pageInfo {
        ...Pagination
      }
    }
  }
`

export default BlogTemplate

Now assuming you have 12 blog posts (stored as Markdown files), the plugin will create the following pages:

  • /blog
  • blog/page/2
  • blog/page/3
  • blog/page/4

if you want to customize the paginated paths, you can include a route in your pagination object that's being passed to createAdvancedPage(). See below:

# pages.config.yaml
- title: Blog
  routes:
    blog: /blog
    blog.paginated: /blog/what/ever/:page
  template: blog-template.js
  helper: blog-helper.js
// gatsby/pages/blog-helper.js
// [...]
createAdvancedPage({
  route: 'blog',
  pagination: {
    route: 'blog.paginated',
    count: result.data.allMarkdownRemark.totalCount,
    limit: 3,
  },
})

Now the plugin will create the following pages:

  • /blog
  • /blog/what/ever/2
  • /blog/what/ever/3
  • /blog/what/ever/4

Passing data to templates

You can pass structured data from your pages.config.yaml to your template component by setting the data field. See below

# content/pages/skills.md
- title: My skills
  template: skills.js
  routes:
    skills: /skills
  data:
    skills:
      - name: HTML
        level: Excellent
      - name: Javascript
        level: Intermediate

Then, you can use that data in your template

// src/templates/skills.js
import * as React from 'react'
import { graphql } from 'gatsby'

const SkillsTemplate = ({ data: { page } }) => (
  <div>
    <h1>{page.title}</h1>
    <ul>
      {page.data.sills.map(({ name, level }) => (
        <li key={name}>
          <strong>{name}:</strong> {level}
        </li>
      ))}
    </ul>
  </div>
)

export const query = graphql`
  query SkillsQuery($id: String!) {
    page(id: { eq: $id }) {
      title
      data
    }
  }
`

export default SkillsTemplate

Generating paths

You can generate paths for the routes defined in your pages.config.yaml using two methods:

Link component (recommended)

The Link component is a wrapper around Gatsby's Link component that allows passing route names and params in addition to regular paths.

Assuming you have a route named blog.post with a value of /blog/posts/:post, you can render a link to a specific blog post using the following:

import { Link } from 'gatsby-plugin-advanced-pages'

// inside your component JSX
;<Link to='blog.post' params={{ post: 'some-post-slug' }} />

generatePath() function

Alternatively, you can use generatePath() function to generate paths. see below:

import { generatePath } from 'gatsby-plugin-advanced-pages'

// Returns: /blog/posts/some-post-slug
const postUrl = generatePath('blog.post', { post: 'some-post-slug' })

Components

The plugin exposes a set of components and functions that allow building advanced pages with minimal code.

Link component

Wrapper around Gatsby's core Link component that allows passing route names and params in addition to regular paths.

Props

Name Type Description
to String Required. The name of the route to link to or a regular path
params Object Route parameters
scope String Route scope. Available scopes: pagination
... [...] All props supported by Gatsby Link component

Usage

import { Link } from 'gatsby-plugin-advanced-pages'

// Route: about = /about-me
// Output: <GatsbyLink to="/about-me" />
;<Link to='about' />

// Route: blog.post = /blog/:post
// Output: <GatsbyLink to="/blog/some-post-slug" />
;<Link to='blog.post' params={{ post: 'some-post-slug' }} />

// Route: blog = /blog
// Output: <GatsbyLink to="/blog/page/4" />
;<Link to='blog' scope='pagination' params={{ page: 4 }} />

// You can pass any prop supported by GatsbyLink
// Output: <GatsbyLink to="/about-me" activeClassName="active" partiallyActive={true} />
;<Link to='about' activeClassName='active' partiallyActive={true} />

// If no valid route is supplied, a regular link will be rendered
// Output: <GatsbyLink to="/some/path" />
;<Link to='some/path' />

Pagination component

Renders a pagination UI to paginate a set of results fetched using a GraphQL query.

Props

Name Type Description
route String Required. The name of the route to paginate
params Object Route parameters
pageInfo Object Required. pageInfo object fetched from GraphQL using Pagination fragment
ui String UI mode (Defaults to full). Available options: mini, simple, full
range Number Maximum number of pages displayed (Defaults to 6)
className String Class name applied to the pagination container
labels Object Navigation items labels. Available keys: prev, next, first, last
theme Object Elements class names (Defaults to Bootstrap 4 classes). Available keys: inner, item, item.next, item.prev, item.first, item.last, link, active, disabled
renderDisabled boolean Render disabled navigation items (Defaults to true)

Usage

import { Pagination } from 'gatsby-plugin-advanced-pages'

const BlogTemplate = ({ data }) => {
  // ...
  ;<Pagination ui='simple' route='blog' pageInfo={data.allMarkdownRemark.pageInfo} />
  // ...
}

export const query = graphql`
  query BlogQuery($limit: Int!, $offset: Int!) {
    allMarkdownRemark(limit: $limit, skip: $offset){
      edges {
        node {
          ...
        }
      }
      pageInfo {
        ...Pagination
      }
    }
  }
`

export default BlogTemplate

Hooks

The plugin exposes two hooks for getting and checking for the currently activated route.

useRoute

(): Route

Gets the current active route based on @reach/router location history.

useIsRoute

(route: string): boolean

Checks whether a given route is currently active.

Functions

These are the functions exposed by the plugin.

createAdvancedPage

({ route: string, params?: object, pagination?: object, ...context: any[] }): void

Creates page(s) based on given input parameters. Note: This function can only be called within Page helpers.

generatePath

(route: string, params?: object, scope?: string, ignorePrefix?: boolean): string

Generates a path for a specific route based on the given parameters.

getPathGenerator

(route: string, scope?: string, ignorePrefix?: boolean): Function

Returns a function to be used to generate paths for a specific route.

navigate

(to: string, params?: object, scope?: string, options?: object): void

Extends Gatsby's navigate to allow passing route names and params.

getMatchingRoute

(path: string, ignorePrefix?: boolean): Route

Gets the route that matches a given path.

getRoutes

(parent?: string): Route[]

Gets an array of all routes or routes nested under a given parent route.

getRoute

(route: string): Route

Gets the Route object of a given route name.

routeExists

(route: string): boolean

Checks if a route is defined with the given name.

Configuration

Pages

Pages configuration defines your site’s pages and routes. It should be defined in one of two ways:

Inline definition

You can define it alongside other plugin options in your gatsby.config.js file like this:

plugins: [
  {
    resolve: 'gatsby-plugin-advanced-pages',
    options: {
      // plugin options goes here
      pages: [
        {
          title: 'Hello, World',
          template: 'hello.js',
          routes: {
            hello: '/hello',
          },
        },
      ],
    },
  },
]

Separate config file

This file should be in the root of your Gatsby site and should be in one of these formats:

YAML

pages.config.yaml or pages.config.yml

- title: Hello, World
  template: hello.js
  routes:
    hello: /hello
JSON

pages.config.json

[
  {
    "title": "Hello, World",
    "template": "hello.js",
    "routes": {
      "hello": "/hello"
    }
  }
]
JavaScript (ESM is supported)

pages.config.js, pages.config.cjs or pages.config.mjs

// CJS Syntax
module.exports = [
  {
    title: 'Hello, World',
    template: 'hello.js',
    routes: {
      hello: '/hello',
    },
  },
]
// ESM Syntax
export default [
  {
    title: 'Hello, World',
    template: 'hello.js',
    routes: {
      hello: '/hello',
    },
  },
]

Plugin options

Defaults

Here is the full list of options with their default values.

// gatsby-config.js
plugins: [
  {
    resolve: 'gatsby-plugin-advanced-pages',
    options: {
      basePath: '/',
      pages: [],
      template: null,
      directories: {
        templates: 'src/templates',
        helpers: 'gatsby/pages',
      },
      pagination: {
        limit: 10,
        suffix: '/page/:page',
      },
      typeNames: {
        page: 'Page',
      },
    },
  },
]

basePath

Type: String Default: "/"

Root url for all pages created through the plugin

pages

Type: Array Default: []

Inline pages configuration to use instead of a separate pages.config.js file

template

Type: String Default: null

Default template to be used for pages with no template metadata defined. It could be a file name located under {directories.templates} or a path relative to your project's root directory.

directories.templates

Type: String Default: "src/templates"

Location of template components used to render pages. The path could either be relative to your project's root directory or an absolute path

directories.helpers

Type: String Default: "gatsby/pages"

Location of page helpers. The path could either be relative to your project's root directory or an absolute path

pagination.limit

Type: Number Default: 10

Default page size to be used when no limit parameter is passed to createAdvancedPage()

pagination.suffix

Type: String Default: "/page/:page"

Suffix to be added to the original route to generate a paginated route. This is only used when no paginated route is passed to createAdvancedPage()

typeNames.page

Type: String Default: "Page"

Name of the page object type

License

MIT

About

A Gatsby plugin that makes it easy to create pages with dynamic features like pagination and custom routing.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •