Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create URL for nested pages #3954

Closed
jarekpelczynski opened this issue Feb 9, 2018 · 10 comments
Closed

Create URL for nested pages #3954

jarekpelczynski opened this issue Feb 9, 2018 · 10 comments
Assignees
Labels
type: question or discussion Issue discussing or asking a question about Gatsby

Comments

@jarekpelczynski
Copy link

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...

@pieh pieh self-assigned this Feb 9, 2018
@pieh pieh added the type: question or discussion Issue discussing or asking a question about Gatsby label Feb 9, 2018
@pieh
Copy link
Contributor

pieh commented Feb 9, 2018

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

@jarekpelczynski
Copy link
Author

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 :)

@pieh
Copy link
Contributor

pieh commented Feb 10, 2018

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"
            }
          }
        }
      ]
    }
  }
}

@jarekpelczynski
Copy link
Author

Perfect! That works for me :)
@pieh thank you! 👌

@batguyz
Copy link

batguyz commented Nov 29, 2018

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"
            }
          }
        }
      ]
    }
  }
}

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!!

@batguyz
Copy link

batguyz commented Nov 30, 2018

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.

@pieh
Copy link
Contributor

pieh commented Nov 30, 2018

@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

@batguyz
Copy link

batguyz commented Nov 30, 2018

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!

@braco
Copy link

braco commented Dec 10, 2018

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 – I 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.

@Digital-Odyssey
Copy link

Digital-Odyssey commented Mar 15, 2020

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,
    });
  });
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question or discussion Issue discussing or asking a question about Gatsby
Projects
None yet
Development

No branches or pull requests

5 participants