I've created nested pages in Wordpress (eg. example.com/parent_page/child_page) and I want to reflect same structure using Gatsby.
Want is a proper solution for that? I've tried to create a complex query but without success...
I've added this piece of code to my wordpress instance:
function custom_rest() {
register_rest_field(array('page'), 'path', array(
'get_callback' => function ($post) {
return get_page_uri($post['id']);
}
));
}
add_action('rest_api_init', 'custom_rest');
This will add field path
to Your wordpress pages data you can use to construct gatsby paths - using your example it will return parent_page/child_page
I want to avoid adding additional code to my Wordpress instance.
I've wanted to do it with one query but I gave up. I will try use regexp to get a path from link
field.
Nevertheless, thank you for your help :)
If You want to do it entirely on gatsby side of things - you can:
in your gatsby-node.js
add:
const _ = require(`lodash`);
exports.sourceNodes = ({ getNodes, boundActionCreators }) => {
const { createNodeField } = boundActionCreators;
const pageNodes = getNodes().filter(
node => node.internal.type === "wordpress__PAGE"
);
pageNodes.forEach(pageNode => {
let pathFragments = [];
let tmpNode = pageNode;
do {
pathFragments.push(tmpNode.slug);
tmpNode = pageNodes.find(
node => node.wordpress_id === tmpNode.wordpress_parent
);
} while (tmpNode);
const path = pathFragments.reverse().join("/");
createNodeField({
node: pageNode,
name: `path`,
value: path
});
});
};
and then you can query:
query allPosts {
allWordpressPage {
edges {
node {
slug
title
fields {
path
}
}
}
}
}
which will give you:
{
"data": {
"allWordpressPage": {
"edges": [
{
"node": {
"slug": "test",
"title": "Test",
"fields": {
"path": "sample-page/test"
}
}
},
{
"node": {
"slug": "sample-page",
"title": "Sample Page",
"fields": {
"path": "sample-page"
}
}
}
]
}
}
}
Perfect! That works for me :)
@pieh thank you! 馃憣
If You want to do it entirely on gatsby side of things - you can:
in yourgatsby-node.js
add:const _ = require(`lodash`); exports.sourceNodes = ({ getNodes, boundActionCreators }) => { const { createNodeField } = boundActionCreators; const pageNodes = getNodes().filter( node => node.internal.type === "wordpress__PAGE" ); pageNodes.forEach(pageNode => { let pathFragments = []; let tmpNode = pageNode; do { pathFragments.push(tmpNode.slug); tmpNode = pageNodes.find( node => node.wordpress_id === tmpNode.wordpress_parent ); } while (tmpNode); const path = pathFragments.reverse().join("/"); createNodeField({ node: pageNode, name: `path`, value: path }); }); };
and then you can query:
query allPosts { allWordpressPage { edges { node { slug title fields { path } } } } }
which will give you:
{ "data": { "allWordpressPage": { "edges": [ { "node": { "slug": "test", "title": "Test", "fields": { "path": "sample-page/test" } } }, { "node": { "slug": "sample-page", "title": "Sample Page", "fields": { "path": "sample-page" } } } ] } } }
Hi @pieh thanks for the example above. Maybe I'm missing something but I'm facing some problem in that the query returns all pages/nodes. What If I want to display children of a particular page and so on. Example Page A {child a, b c..}, Page B {child a, b, c}. How do I make this happen when a page is generated to show only the child pages associated to it? Thanks!!
I figured a way to achieve this. For anyone interested, here's what you do:
You need to have ACF Pro installed,
Use either the Relationship or the Post Object field type.
In your pages or posts you can then make the relationship in there. One note of caution, do not reference the parent page in the relationship, use just the child pages you need.
@batguyz maybe you could use something like this:
childrenPages: allWordpressPage(filter: {fields: {path: {glob: "sample-page/**"}}}) {
edges {
node {
fields {
path
}
frontmatter {
title
date
}
}
}
}
which should only return children of sample-page (if you have paths setup like that)
edit: you would probably need to create and pass that glob in gatsby-node
when calling createPage
so you could use variable in graphql query
Thanks @pieh I'll try that out.
Although in my current method works in returning parent/child concept, I've run into a little issue with getting the slug or url. I can only use the guid which is not ideal.
I'll keep you posted, thanks a lot!
Related, why doesn't this work?:
query IndexQuery {
allWordpressPage(filter: { wordpress_parent: {eq: 123} } ) {
I would expect this query, which doesn't seem to be the case:
/wp-json/wp/v2/pages?parent=123
edit: nevermind, that did work 鈥撀營 needed to rebuild the site. Leaving up for posterity.
Tangential, but you can also build a tree with something like the following:
siblings: allWordpressPage(filter: { wordpress_parent: { eq: $wordpress_parent } } ) {}
children: allWordpressPage(filter: { wordpress_parent: { eq: $wordpress_id } } ) {}
It would be nice if there was an out of box solution for querying the entire tree in one go.
boundActionCreators is now deprecated - I've modified the code with the new actions parameter
exports.sourceNodes = ({ getNodes, actions }) => {
const { createNodeField } = actions;
const pageNodes = getNodes().filter(
node => node.internal.type === "wordpress__PAGE"
);
pageNodes.forEach(pageNode => {
let pathFragments = [];
let tmpNode = pageNode;
do {
pathFragments.push(tmpNode.slug);
tmpNode = pageNodes.find(
node => node.wordpress_id === tmpNode.wordpress_parent
);
} while (tmpNode);
const path = pathFragments.reverse().join("/");
createNodeField({
node: pageNode,
name: `path`,
value: path,
});
});
};
Most helpful comment
If You want to do it entirely on gatsby side of things - you can:
in your
gatsby-node.js
add:and then you can query:
which will give you: