How to fetch Menu from wordpress?

Hey @david1,

Appreciate the thorough response! I see - I was confused in looking at the docs and didn’t read closely enough that beforeSSR is just a function triggered at a certain time by Frontity that you can tap into. I read the examples as method signatures, my fault. Again greatly appreciate the help!

1 Like

Hi @mburridge,
Thank you for the quick feedback. I was actually watching a video with you in it last night where you were delving into what Frontity objects you can inspect in the console, very helpful! Thank you!

2 Likes

Hi Michael @mburridge,
Ok more questions :grinning:
Also please let me know if I should be creating new posts for these or if there is a specific protocol. My next questions are related to my WP data source. I’m using a locally run version of WordPress. Here is the code from my frontity.settings.js

{
“name”: “@frontity/wp-source”,
“state”: {
“source”: {
“url”: “https://ripple-web.lndo.site/”,
}
}
},

With this setup I get an error on the server console like this:

`FetchError: request to https://ripple-web.lndo.site/wp-json/wp/v2/posts?_embed=true&slug=footer-about-us failed, reason: unable to verify the first certificate`

I can use a locally run version of the site with a non https url:

`http://ripple-web.lndo.site/`

When I do this my frontity site loads the header and footer but in the middle of the page I get the ’ Oops! Something went wrong message. The error in the browser console is:

GET http://ripple-web.lndo.site/wp-json/wp/v2/posts?_embed=true&page=1 401 (Unauthorized)

Obviously these are 2 separate issues but either way I’m not able to connect to my data source. Any help or direction greatly appreciated! Thanks!

Hi @sattley

I’m not an expert on web security, but I found this answer about adding the root certificate to your application.

This may guide you in the right direction, or alternatively turn off https for that site on your local host. As it’s just local on your dev machine you don’t necessarily need https/ssl unless you’re specifically developing something that depends on it.

Hi @mburridge,
Thanks for the quick response. I fear I’m getting pretty despondent with development so far, seem to be so many errors, though I feel like the majority of it is because its WordPress :slight_smile:

I’d love any help, so here is where I’m at currently. I’m trying to output some menu content like other people in this thread.

  • I’ve set my state.source.url to my locally running wordpress site which uses http. So I’m no longer getting that error about the certificate.

  • In the beforeSSR action I have this code:

    beforeSSR: async ({actions}) => {
    await actions.source.fetch('http://ripple-web.lndo.site/wp-json/menus/v1/menus/footer-about-us') // this invokes our footerMenuHandler
  }
  • The resource at this address:
    …/wp-json/menus/v1/menus/footer-about-us returns the correct JSON I need.

  • I get this error:

ServerError: post type from endpoints “posts,pages,media” with slug “footer-about-us” not found
at Object.eval (webpack-internal:///./node_modules/@frontity/wp-source/src/libraries/handlers/postType.ts:37:21)
at runMicrotasks ()
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at eval (webpack-internal:///./node_modules/@frontity/wp-source/src/actions.ts:24:1) {
status: 404,
statusText: ‘post type from endpoints “posts,pages,media” with slug “footer-about-us” not found’
}

I’d love any help on this, thanks!

Hi @sattley

Enter the URL http://ripple-web.lndo.site/wp-json/menus/v1/menus/footer-about-us into a browser address bar. Do you get anything? i.e. do you know that’s the correct endpoint?

Hi @mburridge,
Yep, it’s the correct endpoint - it returns me the JSON I need for my menu. Here is a partial screen grab of what’s returned in the browser. I cropped it since I’m guessing it’s enough to show it’s working.

Hi @sattley

Could you provide a link to a repo please. How have you implemented your handler? Funnily enough the next episode of Frontity Talks is going to be about this very topic, i.e. fetching menus from WP. It should be available at the end of next week.

const { data } = state.source.get(“primaryMenu”);
undefined!

Hi @mburridge,
Apologies for not getting back sooner. I was determined to get this working and I finally got everything did! I couldn’t share a repo because it’s a private company project. Tbh me figuring it out was more a result of just diving into the code more to understand what was really happening.

A few things did help me though, I’ve listed them below in case others read this:

I used this plugin to expose the menus:


This plugin exposes the following routes and it’s important to be mindful of these paths.
  • /menus/v1/menus list of every registered menu.
  • /menus/v1/menus/<slug> data for a specific menu.
  • /menus/v1/locations list of every registered menu location in your theme.
  • /menus/v1/locations/<slug> data for a specific menu location.

Handler Code
In my handler when I was fetching the data from the source:

const response = await libraries.source.api.get({ 
  endpoint: `/menus/v1/menus/${slug}`
});

I initially had the endpoint starting without a /. I later read on another post the following:

If the "endpoint" value doesn’t start with "/", it will add "/wp/v2" first. So when my endpoint should have been:

https://ripple-web.lndo.site/wp-json/menus/v1/menus/footer-about-us

it was actually:

https://ripple-web.lndo.site/wp-json/wp/v2/menus/v1/menus/footer-about-us

Which was incorrect.

Handler Code and beforeSSR action

Lastly I think I had the path / route in my actions.source.fetch call incorrect in the theme actions. Here is my handler code and my beforeSSR call in my marsTheme config that works.

> actions: {
>     theme: {
>       // special Frontity action fired to prepare the state for the React render made in the server
>       beforeSSR: async ({actions}) => {
>         await actions.source.fetch('menus/footer-menu') // /menus/v1/menus/<slug> data for a specific menu location.
>       },
>       toggleMobileMenu: ({ state }) => {
>         state.theme.isMobileMenuOpen = !state.theme.isMobileMenuOpen;
>       },
>       closeMobileMenu: ({ state }) => {
>         state.theme.isMobileMenuOpen = false;
>       },
>     },
>   },

// handler

export const footerMenuHandler = {
  name: "footerMenu",
  priority: 10,
  pattern: "menus/:slug",
  func: async ({ route, params, state, libraries, force }) => {

    console.log(params.slug);
    console.log("Route: " + route);

    const { slug } = params;
    console.log("Slug: " + slug);
    // 1. fetch the data you want from the endpoint page
    const response = await libraries.source.api.get({ 
      endpoint: `/menus/v1/menus/${slug}`
    });

    // this is where we get the actual data
    // 2. get our menu object in json format
    const menu = await response.json();

    console.log(menu);
    // this is a reference to the state object for this link currently, get this and it wil be the target object which
    // we assign our data from items to in object.assign
    // 3. add data to source
    const currentPageData = state.source.data[route];

    Object.assign(currentPageData, {
      slug,
      items: menu.items, // @ni.bonev figured this one out because the "items" property contains an array of items
      isMenu: true
    });

  }
};

I believe the pattern in the handler and the route in my actions.source.fetch need to coordinate or match if you will. The menu I’m fetching is a menu created in WordPress however I had to register it in php with the register_nav_menu WordPress function in order to register it with the slug I wanted, in this case footer-menu

php code to register the menu with the slug I wanted. Though I don’t think I had to do this . . .

//add footer menu
function register_footer_menu() {
  register_nav_menu('footer-menu',__( 'Footer Menu'));
}
add_action( 'init', 'register_footer_menu');

Anyway long and short of it is that now it’s working like a charm and I’ve built my sites footer :slight_smile: Thanks again!

2 Likes

Awesome work @sattley. The solution you’ve come up with is very similar to the one we’ll be presenting in the next episode of Frontity Talks.

Thanks for sharing your solution in the community forum. Others will benefit, I’m sure.

2 Likes

@mburridge Looking forward to the video!! Definitely could not have gotten my code working without the countless other comments on this thread :facepunch: :smiley: I also very much appreciate your help and the rest of the Dev Rel team!

2 Likes