Am getting double names in the url
davidkartuzinski opened this issue · 4 comments
Thank you very much for your plugin. Coming from WordPress and SEO in general, I find breadcrumbs to be vital in my battle with our friend Mr. Google. So, thank you for this plugin. (However, I am relatively new to JavaScript and React.)
Having said that, I am getting a weird issue.
For my page that lists all blog posts with a specific tag (or a specific Category), I am expecting:
home/tags/green-tea
I am getting
home/tags/tags/green-tea
Same for categories. I am getting home/categories/categories/health
This is the repo: https://github.com/davidkartuzinski/1001teafacts
Please forgive the look, if you clone, as it's a bit naked (no CSS) until I get all the functionality in place.
I have looked through the issues here that seemed possibly related and found nothing.
I also tried to make it it's own component but failed miserably. (I saw some stuff in this repo that will help, once this below issue is taken care of.)
--
Below is the relevant code:
src/templates/tags.js
import React from "react"
import PropTypes from "prop-types"
import SiteMetaData from "../components/site-metadata"
import { IoIosPricetags } from "react-icons/io"
import { Link, graphql } from "gatsby"
import { Breadcrumb } from "gatsby-plugin-breadcrumb"
const Tags = ({ pageContext, data, location }) => {
const { tag } = pageContext
const { edges, totalCount } = data.allMdx
const tagHeader = `${totalCount} post${
totalCount === 1 ? "" : "s"
} tagged with "${tag}"`
const {
breadcrumb: { crumbs },
} = pageContext
const customCrumbLabel = location.pathname.toLowerCase().replace("-", " ")
return (
<div>
<SiteMetaData />
<h1>
<IoIosPricetags />
{tagHeader}
</h1>
<div>
{" "}
You are here:
<Breadcrumb
crumbs={crumbs}
crumbSeparator=""
crumbLabel={customCrumbLabel}
/>
</div>
<ul>
{edges.map(({ node }) => {
const { slug } = node.fields
const { title } = node.frontmatter
return (
<li key={slug}>
<Link to={slug}>{title}</Link>
</li>
)
})}
</ul>
<Link to="/tags">See all tags</Link>
</div>
)
}
Tags.propTypes = {
pageContext: PropTypes.shape({
tag: PropTypes.string.isRequired,
}),
data: PropTypes.shape({
allMdx: PropTypes.shape({
totalCount: PropTypes.number.isRequired,
edges: PropTypes.arrayOf(
PropTypes.shape({
node: PropTypes.shape({
frontmatter: PropTypes.shape({
title: PropTypes.string.isRequired,
}),
fields: PropTypes.shape({
slug: PropTypes.string.isRequired,
}),
}),
}).isRequired
),
}),
}),
}
export default Tags
export const pageQuery = graphql`
query($tag: String) {
allMdx(
limit: 2000
sort: { fields: [frontmatter___date], order: DESC }
filter: { frontmatter: { tags: { in: [$tag] } } }
) {
totalCount
edges {
node {
frontmatter {
title
}
fields {
slug
}
}
}
}
}
`
gatsby-node.js
const path = require(`path`)
const _ = require(`lodash`)
const { createFilePath } = require(`gatsby-source-filesystem`)
const { paginate } = require(`gatsby-awesome-pagination`)
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if (node.internal.type === `Mdx`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
}
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
// create variable to use for each type of templates
const blogPostTemplate = path.resolve(`./src/templates/blog-post.js`)
const tagTemplate = path.resolve(`./src/templates/tags.js`)
const categoriesTemplate = path.resolve(`./src/templates/categories.js`)
// const blogListTemplate = path.resolve(`./src/templates/blog.js`)
const result = await graphql(`
query {
postsRemark: allMdx(
sort: { order: DESC, fields: [frontmatter___date] }
limit: 2000
) {
edges {
node {
fields {
slug
}
frontmatter {
tags
categories
}
}
next {
frontmatter {
slug
title
}
}
previous {
frontmatter {
slug
title
}
}
}
}
tagsGroup: allMdx(limit: 2000) {
group(field: frontmatter___tags) {
field
fieldValue
}
}
categoriesGroup: allMdx(limit: 2000) {
group(field: frontmatter___categories) {
field
fieldValue
}
}
}
`)
// handle errors
if (result.errors) {
reporter.panicOnBuild(
`Error while running GraphQL query. Check gatsby-node.js file.`
)
return
}
const posts = result.data.postsRemark.edges
posts.forEach(({ node, next, previous }) => {
createPage({
path: node.fields.slug,
component: blogPostTemplate,
context: {
// Data passed to context is available
// in page queries as GraphQL variables.
slug: node.fields.slug,
// https://toripugh.com/blog/gatsby-blog--next-and-previous-links
next,
previous,
},
})
})
// http://codekarate.com/daily-dose-of-drupal/gatsby-pagination-gatsby-awesome-pagination
paginate({
createPage,
items: posts,
itemsPerPage: 2, // number of pages
pathPrefix: "/blog",
component: path.resolve(`./src/templates/blog.js`),
})
// extract tag data from the query
const tags = result.data.tagsGroup.group
// make the tag pages
tags.forEach(tag => {
createPage({
path: `/tags/${_.kebabCase(tag.fieldValue)}/`,
component: tagTemplate,
context: {
tag: tag.fieldValue,
},
})
})
// extract category data from the query
const categories = result.data.categoriesGroup.group
// make the category pages
categories.forEach(category => {
createPage({
path: `/categories/${_.kebabCase(category.fieldValue)}/`,
component: categoriesTemplate,
context: {
category: category.fieldValue,
},
})
})
}
Again, thank you very much for your attention and help.
-DK
@davidkartuzinski thanks for the issue! I'll take a look and get back to you!
@davidkartuzinski well, the issue is you are trusting my example of a customCrumbLabel from the docs to work with your app :)
and this line:
https://github.com/davidkartuzinski/1001teafacts/blob/8a647f9f3f890d0832edadf43e05daccbfa10314/src/templates/categories.js#L20
In your situation on this template, that is getting you the full path instead of the last section (crumb) of the path.
Try something like this instead, note: this will only get the last crumb section of the path in this template situation. (ie path of /tags/ginger-tea)
const [, , customCrumbLabel] = location.pathname.split("/")
// you can now manipulate customCrumbLabel here ex: customCrumbLabel.replace('-', ' ')
If this fixes you up (it should) feel free to close the issue or let me know and I can close it up.
I'll review those docs and see if I can tweak them to make them better. Any suggestions welcome on that if you have any ideas to clear things up.
thanks!
@sbardian Thank you. This code definitely solved the issue. I would love to try and make a pull request on the docs, however, I am not sure if I fully understand why the solution works, and therefore not sure if I can do a good job. Could you confirm my understanding below? and then I can propose something to you for the docs.
Looking at this snippet:
const [, , customCrumbLabel] = location.pathname.split("/")
From what I understand, the plugin is using the location
object to create the customCrumbLabel
. The location from the gatsby.node.js file is reporting this object:
{
href: "http://localhost:8000/tags/digestion/", ancestorOrigins: DOMStringList, origin: "http://localhost:8000", protocol: "http:", host: "localhost:8000", …}
href: "http://localhost:8000/tags/digestion/"
ancestorOrigins: DOMStringList {length: 0}
origin: "http://localhost:8000"
protocol: "http:"
host: "localhost:8000"
hostname: "localhost"
port: "8000"
pathname: "/tags/digestion/"
search: ""
hash: ""
assign: ƒ assign()
reload: ƒ reload()
toString: ƒ toString()
replace: ƒ replace()
state: null
key: "initial"
__proto__: Object
}
The "problem" is that the breadCrumb is then created from pageContext
, which returns as:
{
tag: "digestion", breadcrumb: {…}}
tag: "digestion"
breadcrumb: {location: "/tags/digestion/", crumbs: Array(3)}
__proto__: Object
}
... and we want only "digestion".
So by splitting the location/pathname /tags/digestion
at the "/" the value of customCrumbLabel becomes digestion". Which we then add the existing "crumbs" and get the correct value. (The array becomes
["", "tags", "digestion", ""]```.
Which is why later in the component it works for crumbLabel={customCrumbLabel}
.
--
After typing all this out, it seems correct to me. And really just about understanding JavaScript. I would dare say that maybe the docs don't need to be changed and if anyone has this issue, they will probably just find this issue?
I am closing the issue as the issue is closed and will see what you want me to do. Thank you very much.
@davidkartuzinski no problem. I'll look into removing or just making that line in the example a note, that might help. thanks!