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!
Well done on figuring that out - the clue is in the name: SSR!
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.
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:
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!
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!
Hi Michael @mburridge,
Ok more questions
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
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.
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 Thanks again!