How to fetch Menu from wordpress?

Hello @joppe could you provide a public repo or a codesandbox reproducing the error? This way it will be easier for the community to help you.

The code I got working doesnā€™t assign data but rather pulls items.items to an items property and that works well.

Hello Pablo,

Sorry I cannot provide a public repo or sandbox.

Maybe I can rephrase my question a bit.

The method Object.assign expects two properties. The first one is the target property where the key/values will be copied to. In the example state.source.data["primaryMenu"] is provided. In my case this property is undefined, so the assign wonā€™t work. Should the property be created by the framework? Is there a setting I should add, so it will be generated?

This is the code I use

import * as React from 'react';

import Theme from './Theme';

const menuHandler = {
    name: 'primaryMenu',
    pattern: 'primaryMenu',
    priority: 10,
    func: async ({ libraries, state }): Promise<void> => {
        const response = await libraries.source.api.get({
            endpoint: 'menu/all',
        });

        const items = await response.json();

        Object.assign(state.source.data['primaryMenu'], {
            items,
            isMenu: true,
        });
    },
};

export default {
    name: 'zimpa',
    roots: {
        theme: Theme,
    },
    actions: {
        theme: {
            beforeSSR: async ({ actions }): Promise<void> => {
                await actions.source.fetch('primaryMenu');
            },
        },
    },
    libraries: {
        source: {
            handlers: [menuHandler],
        },
    },
};

Hey @joppe,

I am going to try to answer this, but please someone correct me if I am wrong.
When you use actions.source.fetch('primaryMenu') that will use the primaryMenu handler to fetch a certain endpoint. In your case I can see the endpoint is 'menu/all'.
As far as I understand, when get request is performed, the response is placed in state.source.data[link]. The idea is to then wait for the reposnse to resolve and get the items from it and add them to that object in state.source.data[link].

I believe in your case you need to look at state.source.data['menu/all']. The easiest way to test this is just open the browser console, type frontity.state.source.data and review what you have there. This will help you find the solution.

Good luck and hopefully this was helpful in 1 way or another.

1 Like

I quick suggestion (not sure if it is the solution) in addition to what was explained by @ni.bonev

const menuHandler = {
    name: 'primaryMenu',
    pattern: 'primaryMenu',
    priority: 10,
    func: async ({ link, libraries, state }): Promise<void> => {
        const response = await libraries.source.api.get({
            endpoint: 'menu/all',
        });

        const items = await response.json();

        Object.assign(state.source.data[link], {
            items,
            isMenu: true,
        });
    },
};

What Iā€™m doing here is using the param link from the function, because if I remember correctly, the link will be primaryMenu/. Thatā€™s the reason you get undefined, because the link is being modified to always have a / at the end.

2 Likes

Using the link works indeed :tada:
Thanks for explaining @orballo and @ni.bonev!

3 Likes

Hi,
I followed your example and I can call the menus, but I have an issue; I canā€™t access the resources of these different menus;
Could you please help me?

Hi @eudeskouassi :wave:
In order to get help most efficiently itā€™s essential that you provide a bit more details about your problem: :slight_smile:

What specific errors are you getting in the terminal?
What specific errors are you getting in the browserā€™s console?
If you could provide a repository with the code of your project, the community (or any member of the Frontity team) would be able to clone your project and try to reproduce the issue youā€™re having
With this info, itā€™ll be much easier to help you with your issue

If you canā€™t share your whole project, please create a CodeSandbox (you can start with this template) or a GitHub repository with the minimal amount of code to reproduce the issue.

Hi @SantosGuillamot
Pleqse, how to install this plugin https://github.com/WP-API/menus-endpoints ?

You can download the zip from the GitHub repo and upload it to your WordPress as any other plugin -> https://www.wonderplugin.com/wordpress-tutorials/how-to-manually-install-a-wordpress-plugin-zip-file/#:~:text=This%20tutorial%20will%20guide%20you,click%20the%20button%20Install%20Now.

Thank you !
Itā€™s okay

Is it possible to use Console.logs in the index.js files? I followed the instructions here and I have written the code correctly to get the menus using the WP-REST-v2 Menus plugin but I am getting items undefined in the Nav.js component.

The code in my index.js file.


const menuHandler = {

  name: 'menus',

  priority: 10,

  pattern: '/menus/:slug', // You can use something shorter here, you don't need to use the endpoint

  func: async ({ route, params, state, libraries }) => {

    const { api } = libraries.source

    const { slug } = params

    // 1. fetch the data you want from the endpoint page

    const response = await api.get({

      endpoint: `/menus/v1/locations/${slug}` 

    });

    // 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, {

      slug,

      items: items.items, // @ni.bonev figured this one out because the "items" property contains "items" that are the menu items we are after

      isMenu: true

    })

  }

}
beforeSSR: async ({ actions }) => {

      // Adding both menu location menus to beforeSSR

      await actions.source.fetch('/menus/primary')

      await actions.source.fetch('/menus/footer-menu')

  }
source: {

      handlers: [menuHandler]

    }

Hi @chinomsojohnson,

Welcome to the Community!

Can you please provide a repo or code-sandbox with your code? This is especially helpful to find solutions of technical issues with specific code

Regarding the use console.log in your code maybe this Frontity Talk we recently published about debugging may help you

Hi @mmczaplinski,
I was looking over these 3 options to create a menu myself. I initially went with option 3 using the plugin and custom handler. Subsequently I watched this talk from @SantosGuillamot - Connecting Gutenberg and Frontity ā€¦
It seems to me that creating the menu from a CPT or template part and using Gutenberg blocks and a processor is an easier way to go. Am I missing something? Iā€™m looking to use Frontity on a project at work and am wondering if there is a sort of list of best practices as it pertains to these common dev tasks.

Hi @sattley

Welcome to the Frontity community. Great to hear that youā€™re thinking of using Frontity for your work project.

Any of the 3 solutions proposed by @mmczaplinski will work fine and could be considered good practice. However, as with many technical decisions human considerations need to be factored in.

So, for example, if the people doing the content are already familiar with the WordPress admin pages and with working with WordPressā€™ menus then the plugin and custom handler would be the best option as the content creators/editors wonā€™t need to be taught a different way to do things.

On the other hand, if the content people are not already familiar with the WordPress admin then you could create the menu as a CPT and tell the content people that that is how it works for this site.

And then, as @mmczaplinski says, if the menu is unlikely to ever change or will change infrequently you could hard code it into frontity.settings.js and the developers can change it as and when it needs to be changed.

As I said earlier, itā€™s not always simply a technical decision. Take into account the users, and how theyā€™re going to work with and interact with the final technical solution.

Hi @mburridge,
Thanks for the quick response. Iā€™m going to use the solution that others have used since Iā€™d like to have the menus in WordPress still configurable by some non technical folks.

A few other questions if you donā€™t mind. Iā€™m learning Frontity and have been reading all of the docs first.
Right now Iā€™m just trying to console.log from the beforeSSR action, but it doesnā€™t seem to work. As I type this I just realized my error -> it logs to the terminal if I do npx frontity dev since thatā€™s the server, doh!

More questions to come Iā€™m sure, thanks!

Hi @david1,
Thanks for this solution. Rookie question for you but I noticed that your beforeSSR property it is not the same syntax as the Frontity documentation of:

{
beforeSSR: ({ state, libraries }) => {
console.log(ā€˜Gonna SSR this pageā€™);
}
}

but rather you have:

beforeSSR: async ({ actions }) => {}

How did you know to do this, ie the async and different parameter?
Thanks in advance!

Hi @sattley

Good approach! :ok_hand:

Well done on figuring that out - the clue is in the name: SSR! :grinning:

Feel free to ask. I look forward to helping wherever I can. Good luck with your project.

Hey @sattley,

So basically, the beforeSSR: ({actions}) is destructuring the object passed to it. The different parameter is what I need from the whole object, so I use the destructuring syntax {actions} to access it, instead of (object) and then later object.actions. Itā€™s just a shorthand of sorts in the new ECMAscript spec. In your case, you donā€™t need anything in your beforeSSR: () because you arenā€™t using anything. However, if you needed state or libraries, you would write what you did. Javascript functions donā€™t require a parameter be sent through if the function is provided one, you just want to pass the parameter if youā€™ll be using it.

As far as the async, I need it because Iā€™m using await in the function for await actions.source.fetch('/menus/primary-menu') and await actions.source.fetch('/menus/footer-menu'). Thatā€™s because the actions.source.fetch needs to wait for a response from the WordPress API before. If I donā€™t use await, the actions.source.fetch() calls will result in undefined data. Without async, await will through a Javascript error and the code will break.

1 Like

Just to add to what @david1 has said above, the frontity object has four properties, each of which is itself an object. The four properties are:

You can examine the object by entering frontity in the browser console, as you can see in this screenshot: