How to fetch Menu from wordpress?

Hi, I have exposed my site menus and now i want to fetch the menu in my front end.
My menu is exposed at http://localhost:8080/wp-json/wp/v2/menu/primary

1 Like

Hey @aeyzazkhan, welcome to the community :smile:

What plugin are you using to expose the menus?

I am not using any plugin but exposing using custom code in theme functions.php

You can create a custom handler to fetch the content of that endpoint and assign that data to a name to access it later, for example "primaryMenu".

Something like:

libraries.source.handlers.push({
  name: "primaryMenu",
  priority: 10,
  // This pattern is the name you can later use in "actions.source.fetch"
  // to fetch the content or "state.source.get" to get the data.
  pattern: "primaryMenu", 
  // This is the function triggered when you use:
  // actions.source.fetch("primaryMenu");
  func: async ({ state, libraries }) => {
    // Fetch endpoint.
    const response = await libraries.source.api.get({
      endpoint: "menu/primary"
    });

    // Extract data from response object.
    const data = await response.json();

    // Assign data to be consumed later.
    // This is the data returned when you use:
    // state.source.get("primaryMenu");
    Object.assign(state.source.data["primaryMenu"], {
      data,
      isMenu: true,
    });
  }
});

You should add that handler in both beforeSSR and beforeCSR:

const before = ({ libraries }) => {
  libraries.source.handlers.push(menuHandler);
};

export default () => ({
  state: { ... },
  actions: {
    beforeSSR: before,
    beforeCSR: before,
  },
});

Finally, fetch it. If you are going to need it on each route, you can fetch it in the before action:

const before = async ({ libraries, actions }) => {
  libraries.source.handlers.push(menuHandler);
  // This will wait until the primaryMenu data is fetched.
  await actions.source.fetch("primaryMenu");
};

That will ensure that the primaryMenu data is available before the React rendering.

You can consume it like this in your React components:

const Menu = ({ state }) => {
  // Use "state.source.get" to access the data:
  const { data } = state.source.get("primaryMenu");

  return (
    <div>{... use `data` somehow ...}</div>
  );
}

export default connect(Menu);
1 Like

By the way, we will add support for WP menus once this plugin is merged with the core:

1 Like

Hi @luisherranz thanks for your awesome project! I’m just checking this out and playing with the mars and 2019 themes to see if Frontity would fit for my client’s needs. The first thing my client would ask for is if they can change the menu so I’m trying to figure out where to implement this code inside the theme structure to make this possible. I’m using the menu plugin you’ve linked (https://github.com/WP-API/wp-api-menus-widgets-endpoints).

Regards from Tallinn,
Kris

These are our plans for wp-source:

  • Phase 0 (finished): custom handlers support
  • Phase 1 (finished): default handlers for common WP urls (home, categories, tags, posts, pages)
  • Phase 2 (in progress, almost finished): handlers for other URLs (custom post types, custom taxonomies) and settings for common WP configurations (subdirectory, page as homepage…). These things need to be configured in the frontity.settings.js file.
  • Phase 3 (not started): handlers for non-URL data, like menus, comments, attachments, widgets…

Our idea for the design of phase 3 is that non-URL data work with the same APIs than the URL data. It just doesn’t start with “/”.

For example, comments will be something like:

// Fetch comments for post 123:
actions.source.fetch("comments/123")
// Get data for those comments
const data = state.source.get("comments/123")
// Iterate over the comments
data.items.map(item => {
  const comment = state.source.comments[item.id]
  // Do stuff
})

Similar for menus, with something like:

// Fetch all menus
actions.source.fetch("menus")
// Fetch specific menu
actions.source.fetch("menus/my-top-menu")

We will open a RFC (request for comments) here in the forum to gather feedback before the final implementation.

In the meantime, you can create your own custom handler to get your menus using any name you want linked to an API endpoint as explained here in this topic. And if you have any question let us know and we’ll help you out :slight_smile:

3 Likes

Thanks for the in-depth explanation! :ok_hand:

1 Like

@luisherranz, I am very interested in this method and tried myself to implement menu on mars theme. But it’s not working. When fetching, it returns null object. I think it is due to the api endpoint.

Can you please let me know how to set endpoint to get menu? For instance, I am going to get all menus and REST API entrypoint is: http://localhost/wp-json/wp/v2/menus/. Then how should I set the endpoint.

I hope to get response from you asap.

Regards,

@luisherranz

My case is that I have bilingual site (czech, english). Default language is czech I have a frontpage handler ( “/” ) and other handlers ("/:slug"). These pages read from state.lang = “cs” and fetch everything according to this setting.

I bumped into a trouble when user goes for routes “/en/” or “/en/:slug”. Where this time handlers change state.lang property to “en”. But my navigation (menu) stays prefetched in czech language.

How can I fetch the menu from WITHIN a component (navigation.js), which is loaded from index.js > header.js ?

This is what I have now: https://ibb.co/cLv37hZ
This is what I would like to have, but it does not work that way:
https://ibb.co/tPPFGwz

What PHP plugin are you using?