It really depends on the plugin you use.
I’ll make an example for the one that is supposed to be the one WP will use, but it’d be similar for others.
Btw, we are going to work in a Frontity package for this but it doesn’t mean it’ll be like this example, it is an implementation you could try meanwhile.
- First you have to install this plugin (or the one you want) to show the menus on the REST API
https://github.com/WP-API/menus-endpoints
- You have to create a handler to fetch this data pointing to the new endpoints.
For doing so you have to create it at the index.js
file of your theme, or create a new package exclusively for this. At this file you should fetch the data and populate the state as you want, something similar to this:
const menuHandler = {
name: "menus",
priority: 10,
pattern: "menus/:id",
func: async ({ route, params, state, libraries }) => {
const { api } = libraries.source;
const { id } = params;
// 1. fetch the data you want from the endpoint page
const response = await api.get({
endpoint: "menu-items",
params: {
menus: id,
per_page: 100 // To make sure we get all elements
}
});
// 2. get an array with each item in json format
const items = await response.json();
// 3. add data to source
const currentPageData = state.source.data[route];
Object.assign(currentPageData, {
id,
items,
isMenu: true
});
}
};
const marsTheme = {
name: "@frontity/mars-theme",
roots: { ... },
state: { ... },
actions: { ... },
libraries: {
...
source: {
handlers: [menuHandler]
}
}
};
export default marsTheme;
This way, we have already created our handler. In order to access the data we first have to fetch it using actions.source.fetch("menus/:id")
, the state would be populated and we can access it with state.source.get("menus/:id")
.
This implementation allows you to select by id the menu you want to fetch. For example, if you want to get the data from menu 54, you have to use actions.source.fetch("menus/54")
and state.source.get("menus/54")
.
- If you want to fetch a menu for all pages, you can fetch it from your theme too, adding it to actions. This way, the data will be accessible from the beginning. If you want to do so, you have to include it also at
index.js
file. It should be something like this:
const menuHandler = {
name: "menus",
priority: 10,
pattern: "menus/:id",
func: async ({ route, params, state, libraries }) => {
const { api } = libraries.source;
const { id } = params;
// 1. fetch the data you want from the endpoint page
const response = await api.get({
endpoint: "menu-items",
params: {
menus: id,
per_page: 100 // To make sure you fetch all the elements
}
});
// 2. get an array with each item in json format
const items = await response.json();
// 3. add data to source
const currentPageData = state.source.data[route];
Object.assign(currentPageData, {
id,
items,
isMenu: true
});
}
};
const marsTheme = {
name: "@frontity/mars-theme",
roots: { ... },
state: { ... },
actions: {
...
theme: {
beforeSSR: ({ actions }) => async () => {
await actions.source.fetch("menus/54");
}
}
},
libraries: {
...
source: {
handlers: [menuHandler]
}
}
};
export default marsTheme;
- Once you have fetched your menu and it’s available in the state, you just have to consume its data as you want. For example, you could adapt the
<Nav />
component of mars-theme
:
const Nav = ({ state, libraries }) => {
const { items } = state.source.get("menus/54");
return (
<Container>
{items.map(item => {
const name = item.title.rendered;
const link = libraries.source.normalize(item.url);
return (
<Item key={name} isSelected={state.router.link === link}>
<Link link={link}>{name}</Link>
</Item>
);
})}
</Container>
);
};
export default connect(Nav);
With all of these, you should have your menu working fetching the data from WordPress. I hope you find this useful and please, let us know if you have any questions