Headless CMSs with Next.js

Navigation Collection

Scott Moss

Scott Moss

Superfilter AI
Headless CMSs with Next.js

Check out a free preview of the full Headless CMSs with Next.js course

The "Navigation Collection" Lesson is part of the full, Headless CMSs with Next.js course featured in this preview video. Here's what you'd learn in this lesson:

Scott demonstrates how to add content to a webpage and control its order using a headless CMS. He shows how to create a navigation collection in Contentful, add buttons to the navigation, and then query and display the navigation links on the webpage.


Transcript from the "Navigation Collection" Lesson

>> Scott Moss: Let's work on adding some content to the page in which we can control the order. So there's many different places in which we can do that, one really cool place is down here on the spots Issues faster feature section where you can see, you can do this carousel type thing.

That's pretty cool, we could do it there. Another way is really just like the links up top. I think it's just probably useful to be able to control these links and create these NAV bars that you can pass around. So let's try that, so let's try to create these links up top.

We'll create a NAV bar, try to move those around, and we'll go from there. So, what I'm gonna do is I'm gonna look at the code to see what is the structure of that. So I believe that's in the component called header. So in the header we have, right here we have a UL with some hard coded links.

So it looks like there is an href, there's an about. It sounds very similar to what we already have with the button type. So we can just reuse the button type, we just need to make a collection in which we can put all these on one field so we can sort them.

So we'll make a collection and we'll make a type called navigation, so that way you can make different navigation which is actually quite common for LCMSs. So for instance, you might have many different places in which you have navigation. So you might have one here, right? You might have one down here, so this is like a footer navigation, this is like a header navigation.

This might also have something on mobile, I'm guessing. Let me see, yep, so you have like a mobile navigation, right? So these are all different navigations you can control and let someone else have the responsibility of maintaining so you don't have to. So let's do that, go back to our Contentful, our content model.

Let's make a new model, we'll call this navigation.
>> Scott Moss: We'll add a field and it really just needs a name, what is the name of this navigation? That's pretty much gonna act as the ID, so we'll say short text. It will be the entry title, it will be required and it will be unique.

So I'm treating these names like the ID, so that way you can have two navigations with the same name. So, treating that as like an ID, and it's just a simple field, that's easy and then the next field is really just gonna be the buttons that go in it.

So we'll just say, I'll call these links, and it's gonna be many references,
>> Scott Moss: And I'm gonna say, except only specific entry type, so that'll be button.
>> Scott Moss: And there we go, we'll allow bulk editing and all this stuff.
>> Scott Moss: Cool, so we got our links, we got our buttons.

Now we can save. Now we have our navigation type, let's go make a new navigation. So we go here, add a new entry, make a new navigation, we'll call this one the header, this the header navigation.
>> Scott Moss: And as far as the body buttons go we'll make some new ones.

So what do we have so far? We have, not this, we have about integrations, pricing, customers change log. So I'll just write those, for now, I'll write those five and then we can change them and see, wow, what the vibe is. So about Integrations pricing customers change log.

Let's do that, so add this, so no, pick a new one. There we go, so I'll say /about, easy. And then, what was the other one? Integration or something? Integrations,
>> Scott Moss: About that, we have pricing
>> Scott Moss: We have customers, I think.
>> Scott Moss: Customers.
>> Scott Moss: And last one is change log.

>> Scott Moss: Oops,
>> Scott Moss: There we go, hope this does work. All right, so now we have our, navigation, cold header, and we got some buttons. I'm gonna publish this. Easy, I'm now gonna go to my explorer. Wipe all this out, and I'm going to query for that. This thing busted.

>> Scott Moss: There it is. So here we go, I have navigation, the navigation collection. I'm gonna say, find me a navigation where the name and an exact match on the name. So I'm gonna do that, I don't know what this title thing is. Get rid of that, it's from the last one.

And then I wanna get the items, of course, and I want to get the name. But specifically, I wanna get the links, that's the important part and get the items of that and then get the label and the link. So if I run that and then put a name here of header, there we go.

Get our navigation header, get our links and the labels, good to go.
>> Scott Moss: Using a LSCMS to manage links is actually a really great use case because if you write a lot of blog content and you have links that are going out it's really hard to keep track of whether or not, if those things are dead.

If they link to something that is no longer published on the internet, you wanna know about that. So keeping track of the links, and some collection on the headless CMS allows you to change them once, and have it propagate throughout your whole site if that link is dead.

I'm surprised a lot of CMSs just don't have features which if there's a special type called a link, and then on some interval, it can try to like, it'll tell you if that link is dead, it'll be like, this thing is like 400 or 500, you should probably change this link.

That'd be really cool, so I think that's, that's a really big thing when it comes to like, people who are actually making serious money off of the content that they write. Links are very important for SEO, so it could be pretty cool. Let's go ahead and copy this, gonna head over to our queries file, make a new query.

>> Scott Moss: GetContentForHeaderNav.
>> Scott Moss: Okay,
>> Scott Moss: Got my query here.
>> Scott Moss: Paste this in, there we go, one more. There we go, so we got that, make a call to our little helper functions. I'm gonna just copy this, since it's pretty much the same everywhere, just the types are different.

So we'll do that, we'll go make a new type, obviously that's not gonna work. Our variables are going to be name and the value is gonna be header. At least that's what I called mine, yours might be different.
>> Scott Moss: And then I just need to go make a new type, that's not gonna work here, so I'm gonna grab this.

>> Scott Moss: Go to my types.
>> Scott Moss: Make a new one, export type, this will be HeaderNavQuery.
>> Scott Moss: Okay, this is an object type, this is an object of arrays.
>> Scott Moss: This is a string, this is an object, this is an object of arrays. This is a string, and this is a string.

>> Scott Moss: There we go, got our HeaderNavQuery, gonna bring that in.
>> Scott Moss: From our types import and just put that down here [INAUDIBLE] now, we are good to go. Got the same thing that we had in Apollo.
>> Scott Moss: All right, so now what we need to do is, this is a server component, so we should be able to run an async function here.

>> Scott Moss: So we'll say data = await getContentForHeaderNav. And let's actually scope this down. So content equals data.navigationcollection.items, grab the first one, that's what we want.
>> Scott Moss: And really, we just want the links, so I'm just gonna say, give me the links. This will be linkscollection.items. That's what I want the links.

>> Scott Moss: Cool, now I got the links. I'm gonna just keep just this one and get rid of all the other ones. So I command x that, so it's in my paste bin or my copy buffer. Just need one, put this one back. And do this, so links.map, get a link and then we put that in there.

>> Scott Moss: Link.label.
>> Scott Moss: Link.label, so this should at least make the call. I think we're gonna run into an issue if you haven't saved it already, you might have ran into one. Let's see, I think this one, I've been saying, there's gonna be issue, I actually think this is the one.

Well, I guess I gotta start the server first, no.
>> Scott Moss: Try that.
>> Scott Moss: Yes, thank you, okay. Did it show it? I'm gonna actually see the error.
>> Scott Moss: Okay, maybe the error is in the console, there it is. Okay, that's all I was looking for. So, couple things, I'm glad we ran into this error.

So first of all, if we're getting content on the server side, why is the error on the browser console?
>> Speaker 2: Trying to run in both or something.
>> Scott Moss: Yeah, for some reason the code that we just wrote to get the content for the nav is being executed on the client, even though it's a server component.

So what we can do is we can make an enforcement right quick, so if we go into our queries, this isn't gonna fix the error but this is going to give us a better error and then I'll show you how we fix the error. But this is important because this is something that you run into a lot with next year.

So, one of the things we want to install or should already be installed, but the thing we wanna use is something called server only. So if you import that at the top of the queries, this, whenever this file is imported in a client file, it's not going to throw an error saying, you cannot use this file on the client.

And that's, we don't want this file, this is useful cuz now we'll be able to figure out who's trying to import this file? Why is it throwing an error? There's the error that I was trying to get. It's now you can see that like it tells you one of these Is marked as a client entry with used client.

It's either this file, and I know it's not that file, I'll just put it server only at the top, so it's not that. It's the header file, I know it's not that file. That's where we just made the call to get the query and I said that's a server component, so it's gotta be this file.

It's gotta be this layout file, right? And as you would know, it is the layout file is a use effect. So, the reason this layout file has a use effect in it from the creator of this template was specifically just to initialize this, which has a lot to do with the animations.

It just literally just does animations. So we'll fix this by doing something that's gonna not really change the behavior, but it will fix this. So, all we're gonna do is make another component, and I'm just gonna call it animate.tsx like this and I'm just gonna say animate.
>> Scott Moss: It's gonna export default, animate.

>> Scott Moss: It's gonna be a client component, so use client. And all I'm gonna do is go back to that layout, I'm gonna take this code that it's using here, so it's importing from AOS. I'm gonna take that, I'll put that in here, it wants a use effect, I'll import that.

I'm just gonna take this use effect out, so it's no longer in the layout. I'm gonna put it here in the animate and just have the animate return null.
>> Scott Moss: Doesn't return anything on the page, it just runs this use effect. And then now, when I go down here, above my header, I'll just,
>> Scott Moss: Bringing in this anime like that.

>> Scott Moss: So If we go back, let's see if this fixes anything.
>> Speaker 3: I use client for the layout.
>> Scott Moss: Okay, yeah and then take that off, there you go. Cool, cool, and there we go, it works just fine. So just moving that out of the layout allowed us to make the layout a server component, so then we did just make that one component a client component.

This just strategy that the next day's team recommends you take going forward is just like, don't make an entire page or layout a client component because there's one piece that needs to be a client. Just move that specific thing to its own component and let everything else be a server.

So just push the client stuff down the tree as far as you can. So you have, in reality, you should have like these bigger server components and these tiny little client components. And that's how it should be, so,
>> Scott Moss: All right, we did that, now let's check to see if this is working the way we thought it was.

So what we'll do is we'll go to our CMS and we have about integrations, pricing, customers change law. Is that the order that we see there? About integrations, it is, okay, let's change the order. And let's see what happens if I want to put about down here, I hit publish changes.

I go back to here, I do a heart refresh and yeah, about is over here now. So that's how you can move things around the page, you can sort them in any order you want. If you want to give that person the power to do that, that's how you would do it.

And this is just for links in a navigation, you could do whole sections like that. You could say, all right, I'm gonna make each one of these sections, they don't even have to be the same type, cuz you can make an array of multiple different types of things.

But each one of these sections is gonna be on a field somewhere on the home page that's a list type and then that way the person can drag and drop the sections in whatever order they want them to be. You would need tons of coordination with your designer because you would have to make sure those sections as far as their layout and design aren't dependent on something else.

Like for instance, there's a lot of dependent design on this app, like how things bleed into each other and how they don't. Like for instance, these right here like kinda bleed into each other. So like moving it and putting it somewhere else might mess up the design that was intended.

So you have to like really think about that, but it's definitely a possibility.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now