gatsby-paginate icon indicating copy to clipboard operation
gatsby-paginate copied to clipboard

Can I create a paginate for both index and other pages

Open GoChartingAdmin opened this issue 7 years ago • 11 comments

In my blog I have the following pages:

  1. Index Page
  2. Posts
  3. Category
  4. Tags

I was able to implement pagination for the Index page but I would also like to do the same for the category and tags pages. How do I do that?

GoChartingAdmin avatar Dec 13 '17 23:12 GoChartingAdmin

Hi @GoChartingAdmin

There is an undocumented feature (docs coming) that can do this for you. There is an option called pathPrefix which takes a string.

Essentially you can add any array of posts as the posts option in the options object. This function is basically a replacement for createPages() from the main Gatsby proj although it uses that function to power page creation.

if you have an object containing all your tags and an array of posts for each, you could loop through those and apply the tag name as your pathPrefix option, and 5 for your pageLength option then the plugin will create a yoursite/:tagName page containing the first 5 posts and then a yoursite/:tagName/2 page containing the next 5 etc.

Or you could add tag/${tagName} as the prefix to give yoursite/tag/:tagName etc

I have a little bit of work to do in extending this functionality and documenting.

Get back if that doesn't work/make sense.

pixelstew avatar Dec 14 '17 14:12 pixelstew

I tried the below code in gatsby-node.js

I have a 1:n mapping against category to post

  // Find unique list of categories across all posts
        const categoryBaseList = result.data.allContentfulTestBlog.edges
        .map((each)=>{return each.node.category})
        .filter(function(item, i, ar){ return ar.indexOf(item) === i; });

// Looping as per your suggestion
        categoryBaseList.forEach(category=>{
          createPaginatedPages({
            edges: result.data.allContentfulTestBlog.edges,
            createPage: createPage,
            pageTemplate: "src/templates/category.jsx",
            pageLength: 5,
            pathPrefix: `categories/${category}`
          });         
        })

Now when I tried the below in my category component available in rc/templates/category.jsx

    const { group, index, first, last } = this.props.pathContext; 
    console.log(group) //Response is undefined

What am I missing

GoChartingAdmin avatar Dec 15 '17 03:12 GoChartingAdmin

Not had a chance to test anything but try passing category to the edges arg instead of result.data....etc.

categoryBaseList.forEach(category=>{
          createPaginatedPages({
            edges: category,
            createPage: createPage,
            pageTemplate: "src/templates/category.jsx",
            pageLength: 5,
            pathPrefix: `categories/${category}`
          });         
        })

pixelstew avatar Dec 15 '17 06:12 pixelstew

It did not work

GoChartingAdmin avatar Dec 15 '17 21:12 GoChartingAdmin

What does categoryBaseList end up looking like before it is iterated over?

pixelstew avatar Dec 16 '17 09:12 pixelstew

Here's a recipe that works for me:

result.data.allContentfulCategory.edges.forEach(({ node: c }) => {
  const edges = result.data.allContentfulBlogPost.edges.filter(({ node }) => {
    return node.categories.some(category => category.permalink === c.permalink))
  })
  createPaginatedPages({
    edges,
    createPage,
    pageTemplate: './src/templates/category.js',
    pageLength: 5,
    pathPrefix: `blog/${c.permalink}`,
  })
})

If you need more details about this, let me know.

oprearocks avatar Dec 23 '17 10:12 oprearocks

I think I am close thanks to all your help. Below is my detailed code.

  1. Paginated Index page generated (as expected)
  2. Non-paginated tag pages generated (as expected)
  3. Neither paginated nor non-paginated categories pages generated (confused)
exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators;

  return new Promise((resolve, reject) => {
    const postPage = path.resolve("src/templates/post.jsx");
    const tagPage = path.resolve("src/templates/tag.jsx");
    const categoryPage = path.resolve("src/templates/category.jsx");
    resolve(
      graphql(
        `{
          allContentfulTestBlog {
            edges {
              node {
                id
                tags
                category
                date
                title
                fields{
                  slug
                  nextSlug
                  nextTitle
                  prevSlug
                  prevTitle
                }
                html{
                  id
                  html
                }
                cover {
                  resolutions {
                    base64
                    aspectRatio
                    width
                    height
                    src
                    srcSet
                  } 
                }
              }
            }
          }
        }
      `
      ).then(result => {
        if (result.errors) {
          /* eslint no-console: "off" */
          console.log(result.errors);
          reject(result.errors);
        }

        createPaginatedPages({
          edges: result.data.allContentfulTestBlog.edges,
          createPage: createPage,
          pageTemplate: "src/templates/index.jsx",
          pageLength: 5
        });
        
        const tagSet = new Set();
        const categorySet = new Set();

        result.data.allContentfulTestBlog.edges.forEach(edge => {
          if (edge.node.tags) {
            edge.node.tags.forEach(tag => {
              tagSet.add(tag);
            });
          }

          if (edge.node.category) {
            categorySet.add(edge.node.category);
          }

          createPage({
            path: edge.node.fields.slug,
            component: postPage,
            context: {
              slug: edge.node.fields.slug,
              id: edge.node.id
            }
          });
        });

        const tagList = Array.from(tagSet);
        tagList.forEach(tag => {
          createPage({
            path: `/tags/${_.kebabCase(tag)}/`,
            component: tagPage,
            context: {
              tag
            }
          });
        });

        const categoryList = Array.from(categorySet);
        categoryList.forEach(category => {
          const edges = result.data.allContentfulTestBlog.edges.filter(({ node }) => { return node.category===category });
          createPaginatedPages({
            edges,
            createPage,
            pageTemplate: "src/templates/category.jsx",
            pathPrefix: `/categories/${_.kebabCase(category)}/`,
            pageLength: 5,
            context: { category }
          });
        });
      })
    );
  });
};

GoChartingAdmin avatar Jan 03 '18 22:01 GoChartingAdmin

Do your actual posts have categories added to them? Try logging out the item count in the set, then the length of the categoryList array and then the set / array themselves.

oprearocks avatar Jan 04 '18 07:01 oprearocks

Yes. Will provide by EOD

GoChartingAdmin avatar Jan 04 '18 12:01 GoChartingAdmin

Please find the output below

categorSet_Count: undefined 
categoryList_Count: 7 
categorySet: Set {
  'Grand opening',
  'another one',
  'moar',
  'random',
  'test3',
  'tech',
  'gatsby' 
} 

categoryList: [ 'Grand opening',
  'another one',
  'moar',
  'random',
  'test3',
  'tech',
  'gatsby' ]

And a sample edges which is getting created in the forEach loop under categoryList

const categoryList = Array.from(categorySet);
        categoryList.forEach(category => {
          const edges = result.data.allContentfulTestBlog.edges.filter(({ node }) => { return node.category===category });
          createPaginatedPages({
            edges,
            createPage,
            pageTemplate: "src/templates/category.jsx",
            pathPrefix: `/categories/${_.kebabCase(category)}/`,
            pageLength: 5,
            context: { category }
          });
        });
 [ { node:
     { id: 'c392JTEW93GMaIKq20QaaIY',
       tags: [Array],
       category: 'tech',
       date: '2017-12-12T00:00+01:00',
       title: 'Bold Mage',
       fields: [Object],
       html: [Object],
       cover: [Object] } } ]

GoChartingAdmin avatar Jan 07 '18 21:01 GoChartingAdmin

Do you still stuck at here?

I solved it

graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            html
            id
            frontmatter {
              path
              title
              type
              date(formatString: "MMMM DD, YYYY")
              tags
              categories
            }
          }
        }
      }
    }
  `).then(result => {
    if (result.errors) {
      return Promise.reject(result.errors)
    }
    const edges = result.data.allMarkdownRemark.edges

    let tags = []
    let categories = []

    edges.forEach(({ node }, index) => {
      // Collect all tag, category and ignore duplicated
      tags = Array.from(new Set([...tags, ...node.frontmatter.tags]))
      categories = Array.from(new Set([...categories, ...node.frontmatter.categories]))

      createPage({
        path: node.frontmatter.path,
        component: path.resolve('src/templates/blog.js'),
      })
    })

    // Create paginated pages for homepage
    createPaginatedPages({
      edges,
      createPage,
      pageTemplate: path.resolve('src/templates/index.js'),
    })

    // With each tag, find all posts with this tag and create paginated pages
    tags.forEach(tag => {
      const tagEdges = edges.filter(({ node }) => node.frontmatter.tags.includes(tag))
      const slug = slugify(tag) // create slug for page. I need some modify so I created my own. You can use lodash.kebabCase.
      createPaginatedPages({
        edges: tagEdges,
        createPage,
        pageLength: 1, // 1 for testing. Change to your configs
        pathPrefix: `tag/${slug}`,
        pageTemplate: path.resolve('src/templates/tags.js'),
        context: {
          name: tag, // For display tag name in page.
          path: slug, // For navigation between pages
        },
      })
    })
    // Categories same as tags above
  })

trangcongthanh avatar Jul 13 '18 11:07 trangcongthanh