Build a blog using Contentful headless CMS and NextJs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to build a blogging site using contentful headless CMS and next.js hey friends welcome back to the channel if you're new here my name is Hamed I'm a full stack JavaScript developer and here on this channel we mainly talk about modern web dev topics like react and xjs so let's go before we get started I have a quick announcement to make so I've gone ahead and created a brand new nexjs course if you're interested in learning how to build full stack apps using react on xjs and like the way that I teach this might be the course for you we'll cover everything there is to learn about xjs all the way from the basics to the more advanced stuff we're going to be building three projects throughout this course together and learning these Concepts by building these projects it's currently on sale until the end of February the course will launch by the end of March or beginning of April so if you're interested check it out okay so let's get started with our project let me show you what we're going to build in this blogging site using contentful and next.js we're going to have a simple nexjs app like the one that you're seeing over here with a simple layout and a posts endpoint or page that kind of indexes all of our blog posts and when we click on each individual post will be taken to that post where we have different assets different content different content type or Rich text if you will and then we're going to take it to more advanced stuff like links to you know internal content like the first post or external links like linking to google.com so going outside of our site and also you know putting stuff like code blocks images assets or embedding videos we're going to manage all of this content in contentful so we're going to create an account and build the content models necessary to create this together then we're going to start the next JS application kind of fetch our content from contentful and then kind of glue these two together so let me just close this off and also that page and let's get started with this okay so if you don't have a Content full account you can just go ahead and create one I already have created One account once you create an account for the first time it would kind of uh instruct you on an onboarding flow where you can build uh a an organization and then a space to create your content and content models so let me just try and see if we could do this together so you know how to go ahead so let's say we're creating this from the ground up I'm going to create a new organization so this is going to be our kind of YouTube tutorial so once you create a new organization or your first organization it will ask you will prompt you to create a new space you can give your space a name for example Myspace and then select to start from an empty space You could also select to start with an example this comes with some templates from contentful but we're going to build everything from describe so you can select the empty space you hit continue confirm and create and this will create your brand new space so in this space you can see it right now we don't have any content or any content models defined now the content model is a way to describe a specific piece of content whether it's a section on your site or it's representing a page it's a Content model now content model is a combination of different fields that allows you to Define what a specific section is so let's start by defining a new content type let's say for this example we're going to build a blogging site so we're going to need a let's say post content type so I'm going to create our first first content type now that we have created that content type we can start adding fields to it for example we can have a title field that's the title of our post that's going to be a short text let me just uh go back for a second so once you create or try to add a new field you could select different field types as you can see here in contentful you have a an option for a rich text field where you can put in text that are rich for example they have bolts and italics and links in them we're going to see this in a second you can have a simple text which is titles names you know text on a button and shorter text in general you can have numbers you can have date and time you can have a location which is geo coordinates you could have media Fields where would hold images videos PDFs and other files we can have a Boolean field a Json object or a reference which is a link to another document so we started with the text for the title so let's just put in the name is titled the ID is automatically generated for us and we're going to leave this at Short text it gives us the option for having a long text we're going to use the long text text in a second but for this let's just create and config this title field here you can have some validation rules set for example we can say this is a required field we need this title to be required to be put in anytime that there is a post created and you can select different appearances for this specific field so I'm okay with the way that it looks let's just now add add another one let's put this as a slog this is the path that shows up in the URL we also would use this to uniquely identify the posts so we're going to have a short text create and config and we're going to select the appearance for this to be a slug and then we're going to say generate this log automatically from the title so create and now that I have these two fields for my content model if I save this I cannot go back to my content Tab and add an entry now this entry is automatically going to be from a post type because that's the only content type we have I just wanted to show you that this automatically gets created so if I say my first blog post you see this slug is automatically created for us and that's kind of what we need so if I publish this now we have generated our first content which is of post type or article with these two fields so if I come back to my content right now I can see in the content model I have the post and also this first post now let's create another content model or content type let's name this an author so this is the person who have actually written this article for this let's uh select a text that says name and we want to make this to be required appearances single line should be fine and I want to add another field that says maybe we want to include an image so we're going to name this picture so this is the author's picture you're allowed to uh select one file creating config so validation it's a required field let's say and let's only accept image file types so these are the validation rules you could set for these fields here I only want to accept images because it's a an avatar confirm so now I have this content type set for an author so let's just go ahead to our contents and create one author let's say add an entry now the last time that I hit add entry it automatically took me to the page to add an entry because I only had one content type which is the post and that was the only thing we could create from but now that we have two condom models an author and a post uh when I actually go to my content and select to add an entry which is an instance built from that content type it asks me what type of content I need to I want to create is it a post that I want to create or is an author so I select an author we'll just name it after myself and for this picture or media I can either add existing Media or add a new media so let's just go to the media Tab and see right now we don't have any media selected here if I hit add asset I can I can either add a single asset or multiple assets so I can say single asset title let's say homage um picture and let's just see if I have an image of myself here just bear with me for a second okay I found an image and now I want to publish this asset so I've created an asset by uploading an image and giving it a title so if I go now to my media I can see there is this one image so I go back to my content and I have lost the author that I was creating for whatever reason so I'm going to add an entry an author and I'm going maybe I didn't publish it the last time so I'm going to say home at bahram and then in the media I'm going to select add existing media I could have just selected add new media from here and add it here but I just wanted to show you where in the tabs you could find the Medias that you have so I have created a new author I'm going to publish this okay now I can see this newly created author which is from content type author it has a name and my image um and if I just go back in my posts content type I can now include a field to say hey I want to include a reference field and I'm going to call this author and I want to link into one reference creating config so in the validation it's a required field and then accept only specific or specified entry types I can select this and say hey I want to be able to only link or reference an author to this field because this is specifically an author link the default value there is no default value and appearance we could just have a simple entry link right now that I have this author I can go back to my content sorry back to editing let's save this uh edit or addition let's save this update now if I go back to my content and my blog post right now I could see there is this author field added to my content so I can add an existing content here and because I selected to only be able to include author entries it's just showing me this one author that I have created so I can link to say hey this blog post has has this title that Slug and this is the guy who has written this article okay so let's publish changes go back to content model and add some more field to our post what else do we need here maybe we need a slug for this lock I'm going to select I'm sorry some X excerpt so it's a little summary for this I'm going to create I'm going to include long task text because we may have you know multiple lines or longer text here so it's still a text field not the rich text but I have created I have chosen the long text uh kind of option over here create a config you could again say hey let's just make this also required the shape can be this which is you know where you would put marks down or you know multiple lines up to you um we may want to have a featured image so I'm going to select the media I'm going to call this cover image one file sure creating config validation let's make it required only a specific specific types let's only allow images here so I'm going to confirm so as you can see we can build different fields that are going to shape this specific uh piece of content or content type which is a blog post so imagine that this is representing a an article page where you would have your cover image title you know the author and then some content so what do we do for the content itself we're going to put in a rich text which allows us just to have Rich Text inside of it we're going to see in a second so I will name it content and as you can see here all these options are the options that that the user or the editor or the content uh Creator or author can select when they're actually creating their content and we'll do this together so you can have H1 tags to H6 bold italics links underlines list elements you can also have hyperlinks linking to external URLs or linking to internal entries or internal documents linking to assets like images and PDFs you can also embed entries and assets like embedding and other blog posts inside a different blog post embedding maybe a video inside of a blog post which we're going to create as an entry or as another content type or custom type and you can just select whatever you want to allow the editor to use maybe you say hey I don't want them to be able to choose H1 because that's only one for every page they can select from the rest in validation you could say this is required they need to put in something and the appearance there's only one that you can select so right now you have the content too so if I save this and go back to my content tab go back to that first blog post that I created I could see all of those fields that we added to our data model show up in my editor over here so except this is the summary um of my first blog post I'm going to select I can select the cover image and I can write content and this is where we can have Rich Text for example this is a regular paragraph I can include a heading maybe over here to say heading 3 sure this is a heading maybe we can include a list so we can include a list to say item one item two and as you can see here we have different options even for a link so let's let's actually see this in action uh we can link to an external URL right so let's make this a link and then we can select different link types it's URL that's an external site or page entry is an internal document in our own content an asset would be an image PDF or video so let's go URL and let's say we want to just go to google.com right so we've inserted the link there to be shown okay I'm going to pause the video and create some content over here and we're going to continue together okay I gone ahead and created uh two blog posts first one is this guy I added some image added some rich text some headings some italic and bold text and a block code over here and I have selected myself as the author and I actually also added a date date field to our content type post so that we can select a date that be published or have kind of created this article now I also created a second blog post and here I have included more stuff inside of the content I have a link to the first blog post I have linked to an external site Google in this case as you can see we have list items I've included a block of code that you could do with this if you click on this Ellipsis there's three kind of dots there is a code kind of block you could add or select your text and then select this code to turn it into code I have embedded an asset so the way that you would do this just so I could show it to you here maybe I can show it to you down here so if you want to embed a NASA you can see there is this embed link or button over here you can have an entry this is other entries that you have created uh inside your uh space this can be other documents there's an inline entry or an asset so this image is an asset so you could say an asset and then it would tell you okay which asset do you want to kind of embed in this I've selected that image or you can have you can select and to embed an entry where you can see here I have a video embed kind of type an entry or a document however you want to call it and I have selected that as my video content over here we're going to go over this part of it in a little while for now what I want to focus is actually rendering this text or Rich text and taking care of this different type of links that we have or this code block and then we're going to talk about you know more advanced stuff which is linking to assets or embedding assets like images and YouTube videos okay so let's go to our next.js app and see how can we fetch these content we just created in our contentful app on the left hand side I just created a simple nexjs app by running npx create next app and all I did is replaced the content of the home page to what you see here it just says home page it's working with Tailwind CSS so if you like it you can just go to tell on CSS it's very easy to set it up you can go to the docs you can go to framework guides and on xjs it tells you how to install the dependencies for Tailwind how to create a config and actually paste in this code and then replace the content of your Global CSS with these directives from Tailwind that kind of resets the Styles in the browser and then you're good to go to start using Telvin so the first step for us is to create a layout a header with some navigation links and a footer and the way you typically do that in next.js or the way that I would like to do it in xjs is that I will create a components folder where I can put in my components and inside of it I'll create a layout folder we're going to have more components for example for posts so for layouts let's just do it do an a simple one index.jsx I have created this before so let me just copy this so it saves us some time so what are we doing here let me just get rid of this react so as you can see here it's a simple layout that shows a header with some links so it's a list and some next.js links going to home going to forward slash posts if everybody would show an index of all the blog posts that we're going to fetch from contentful we are going to have this main tag which renders the children or any page is going to be plugged in here we're going to see this in a second and then a footer so that's a simple layout that we have now how do we apply this to all of our pages so we go to our underscore app.js which is um a component function that represents all the pages and here what we can do is we can wrap this component or all of our pages with this layout that we have created so let me just bring in this layout and then put this component inside of that layout okay so as you can see I have my Global header going to home and going to posts we don't have this route right now so it's 404s and or footer let me just copy over a little base style that I have created before and I'm going to explain what this is so I'm going to go to Styles Global and down here I'm going to paste them it's just resetting some stuff uh you know the full height on body and HTML and I'm creating a section and a container kind of custom Style and if I save this the footage should go down and we should just wrap everything in a container that has a max width and centers everything so it looks a bit nicer so let's just close that off let me just also copy a prettier kind of config file so we can right now it's just putting in semicolons at the end it's the way that I typically do this is I create a file over here it's called Dot prettier RC oops sorry I'm pasting in some kind of settings there to avoid practices for you know Arrow functions single quotes and stuff so nothing crazy but it just formats the code a little nicer so the first step we got the layout done let's uh let's just continue with creating this all posts route so on the pages we're going to create a new folder called pages and inside of it I'm going to have two files I'm sorry this is posts so I'm going to have two files here one is going to be index.jsx which is going to represent our posts page so right now we should see these all posts and then I'm going to have another Dynamic one sorry another file which is a dynamic file that references this log of our um unique post to be shown there so if I go to posts for slash ABC if that's this log it just shows that individual page okay so let's um actually go back to I just close all of these guys and just go back to our all posts page and try to connect to our contentful account and fetch all of our posts and then show an index or a list of all the posts that we have on this page so the user can click on to go to that individual post now to connect the contentful we need to install a package from contentful that's called contentful so it's just to stop the development server and install contentful now once we install this package we can create a client that connects to our contentful account so for this I typically create a lib folder inside of it I can have a content full folder inside of it in this live folder you can have you know different type of functions like maybe we can have utilities here in the contentful I'm going to create a file called client.js and inside of this we're going to get the contentful bear with me for a second so we're going to get this contentful from the package we just downloaded or installed and we're going to create a client and to create a client you need at these two these two variables this space ID and the access token so where would you get these so you can go to your contentful account and sorry go to your contentful account and on the settings tab over here you can come to API keys um I have created this kind of API Keys when you come here for the first time there is nothing here you can just add API key once you hit add API key it will just show you this page where you can put a name for that API key and you can grab your space ID from here that's what you need on your application to connect to this space and you have two API access tokens one is for the content delivery API so where you would just fetch your content and the other one is for Content preview API where which we're going to talk hopefully at the end of this video which allows you to preview once you're editing your content it allows you to preview your content before publishing it to your site you're going to need this later on so you can go ahead and create a DOT and dot local inside of your project and for now we're going to have two variables inside of it this space ID so you're going to copy this from your own account and the other one that we're going to copy is the contentful access token don't worry about the preview right now we're going to set that up later so go ahead and do that I'll do that myself and then I'll come back okay I copied my environment variables let's just uh rerun the development server and go back to our index page we should be able to connect to our contentful account now and fetch all of our blog posts we just quickly go over here so I can copy the code that I've written already so pages okay so let's see what's happening here it's the same function that I had I've added this get static props this is the way that you fetch data in an xjs application on the server side at build time so it's going to be static Pages fetch that build time what we're doing is that we're we're importing this client that we just created in our lib folder and we're calling the get entries function or method on this client that comes from the contentful package and we are specifying some query over here I'm saying the content type that I want you to fetch is all the posts now if you go to your contentful account right here and search for Content you can see here this is the post kind of type we created before um and this type is going to have an ID of post so this idea of post is what you can see over here and that's what I'm passing in to that to only fetch the content or the entries that are off that type post and I'm just sending uh the response.items which is at entries that I get or my posts to the page component where I can map over them and for each one show this postcard so let's just go ahead and create this postcard together so in the components folder we're going to have our post card over here let me just again copy the code so you don't have to watch me do this okay in a postcard we're getting a post we are destructuring the fields that we had from it like the title the slug the excerpt cover image author and date these are the stuff we set up in our contentful that comes with that data on the post on the fields and we're trying to show them over here now for each one of these I have created some components to make it easier to pass data and to show it or to control what we want to show so the first one is contentful image let's just create this together and see what this is going to do inside of our content components maybe I create a UI folder and inside of it I can have a Content full image .jsx let me just copy this over from here okay so I've copied over the code and all we're doing in this contentful image is to render a next image and pass in all the props that we are sending to this contentful image component so if you're passing alt Source width and height it's going to be passed to the underlying image component the only thing is we're using a custom loader that allows us to pass in some parameters that can optimize our images coming from contentful with a quality and width this is something unique to contentful it actually serves up your images or your assets in an optimized way so you can pass in some parameters here and change the quality of the image that you're getting or the width of the image that you're getting on the fly now if you don't know how custom loaders work in xjs I have a video on my channel and a blog post about it that I explain everything that you need to know about next JS different settings the way to style it and custom loaders you could just watch that I will link it somewhere in the cards here um but nevertheless it's as easy as uh this that you can see a custom loader is just a function that returns kind of the path or uh some parameters to access uh your uh external host that's serving up your images the only thing you need to do when you are using a custom loader is to actually update your next config Js so let me just go here if I go to my next config what I can do over here is just pass in this images and loader specify a custom where you specify this it's not going to use the next JS built in loader and instead it's going to use your custom loader that we have just defined together and anytime you are updating your next config you have to restart the dev server okay now the next component that we have here is a date component so let's just work on that let me just copy over again the code that we have over here so components in the UI I'm going to create a date component and all we're doing here is we're getting a date string we are getting some options and any other properties that's sent and we are rendering a time and we're formatting that date with this format date function that I'm going to create inside of our lips so inside of our lib folder or library in the utils I can create a new function let's just put in index.js and let's just have this function format date it takes a date string and options it uses the new Intel date time format which is built in JavaScript and then just forwards the options to that gets this format function and formats the date string that we're passing to it so that our dates are looking nice and standard through our throughout our app now for the Avatar let's just create that together as well so in the UI components I'm going to create an avatar and inside of this again what we're doing is we're showing the name of the author so if you can see here I'm passing in the name which is coming from author this is a field that we have on our post inside of it there is another field kind of uh property and a name and also the picture which holds our asset or the avatar for that specific author so inside of here I'm showing the Avatar using that same contentful image that we created together over here and also the name of the author that's all so with this I think if you go back to our page and to our posts okay so one thing that I forgot to set up is a JS config .json where I can specify this shortcuts to uh the folders uh but I don't have any contents Lit video utilities are inside of our lip Styles yeah sure maybe uh public hooks we don't have it but just let's leave it at the at that so if I go to my posts right now and the reason why I did this before I actually go ahead is that you see how on I mean I wasn't doing it here but on some of the pages you could see I was importing because I copied the code and I was you I was using these aliases to access components instead of like going dot dot dot and then you know if if your project becomes big and you have folders and top folders instead of just having to come back out of these folders to reach where you want to go if you are having this shortcuts set you can just go ahead and include links like that that it's just going to point to the file that you're looking to get okay nevertheless on the all posts page as you can see we are fetching the two uh blog posts that we have the first blog post they're all going to uh correctly showing that slug up there if you can see maybe I can make this a bit bigger actually doesn't change that URL bar but anyways right now both of them are going are not showing anything because we're not dynamically fetching these segments but they do show uh this log correctly so let's just do that next let's implement uh the dynamic page for each post again hold cheat to copy some codes I've written here so you don't have to watch me okay let's see what we're doing over here step by step so on this page the idea is that we want to show the content of each individual blog post so we're going to have to fetch that individual blog post first we're going to do that with get static props on the get static props as you know on the context object that's passed to this function by an xjs you'll get a prams object on which you can get the slug of that page that specific Dynamic route or segment of your url that's representing an individual unique blog post so we're going to get that slug [Music] ignore this line for a second we're going to come back to this this is for when we want to enable previewing our content this preview is also sent to the context object by an xjs we're going to explain this later on in the video but ignore that for a second all we're doing is get this log from the URL and actually try to fetch from our client with that same get entries function uh content type post and then I'm specifying another part to the query to say hey I want the fields.slog to be equal to this slug that the user is currently on if the response doesn't return anything back we're going to redirect the user back to the all posts page this page and if we do find or we do get a response back we're going to send that post which you can find on the response items or number one because because we're using the get entries function it always returns an array even if there is one Post in it so I'm receiving this response items this is the same thing that we were getting response items there there you had all of our posts here we're only interested in the first one or it should only have one because this log as you remember we said it to be unique so if I go back to my content model to my posts if you look at this slog setting we have specified that this guy is unique so there's only one of these entries on my site that has this slug and we're post we're sending that specific blog post uh back to our page okay and this is our page component again um ignore the preview for now so if you're sending this post to our page and what we're doing is we're rendering a post header and a post body so let's create these two to be able to see the content of the post and then I'm going to explain uh they get static paths and then this kind of fallback skeleton that we're going to be showing over here so let's start from the post header so inside of our components posts I'm going to create a new component called post header let me just copy okay so we have Avatar date component content full image that's the same thing we have created Avatar and a date component so everything is what we already have there shouldn't be any problems the other thing that we need is a post body component so let's just go ahead and create this post body component again let me just copy everything over here now that we have these two I'm going to come back to this post body and this Rich text component in a second but we've before we dive into the rich text or the content that's coming from our blog post let's just quickly address this on any Dynamic route in next JS you need to also provide this get static paths function which instructs next JS which paths or which slugs it should build statically at build time without it it doesn't know what pages to build statically but with it we can just specify looping over all of our Pages or contents or entries in contentful and instruct next.js to create these Pages statically at build time so what we're doing is we're calling the get interest function content type post we're going to get all of the items map over them and for each item we're going to return this object that has a prompts property with a slug property on it that just points to that item's slog we're going to return this path and a fallback optional fallback you can pass in actually it's not optional not sure what's the default value but fallback is basically saying if the user tried to access a page that we did not returned in these paths what should we do if you set the fallbacks to true it says hey there might be pages that I did not return here in the path so just go ahead and try to create or generate that page on demand and show a fallback to the user which is this a skeleton we're going to talk about in a second so it's just a loading skeleton so we're going to fall back to a loading skeleton Nexus is going to go ahead and build this page on demand and then once it is ready it's going to swap this loading kind of skeleton with the actual post header and body now that's when you set it to true if you set it to false it means that hey these are the pages that I have and I want you to statically build them if the user tried to access any other page other than this just four or four that doesn't exist so that's fallback false and then there is a third option fallback blocking whereby it's just similar to setting it to True where it would just generate that page on demand but the only difference is that it doesn't show this fallback skeleton it just blocks the browser the user until lab page is generated so that the user will see like a blank page until the content is ready then they would see uh the blog post so true if you wanted to kind of build these pages on demand that true is better because at least you could show the user a loading spinner and loading a skeleton while this is being built but if you want you could also set it to blocking okay so this is just a little housekeeping from next.js that instructs it to build these Pages statically at build time now that we talked about this as skeleton let's just quickly take it uh let's just quickly build this one together so in the UI again we're going to have this skeleton which is just a kind of loading structure so let's go component UI and let's just build this scale at 10.jsx copy the code and all we're doing here is just showing bunch of divs that have an animation on them to kind of show a loading State we're going to see this together so going back to our page um the preview alert let me just comment this out for now we're going to get back to this uh later on when we wanted to enable previewing content um now in the post body the post header we already had all the used components in the post body we were using this Rich text so let me just comment this out and instead of using that rich text show this content so what are we doing here so we showed the post header and all the relevant information such as the title the name the Avatar the image but the content is actually if you remember here if I go to this content model on every blog post we have this content field which if you could see just make this a bit bigger too so this content is a rich text so on our blog post let's say on our first blog post you could see I have headings I have bold text and italics I have block codes and stuff right now all of this is going to be parsed automatically when you're using uh the contentful client this one that we created here this client automatically parses these rich text to the corresponding tags like the heading to show with the corresponding heading the Bold text the italic the block codes and stuff so let's just put it out there so in the body all they're doing is you're getting this content field which is that same field that we defined together on our post this content field and we're getting that from our posts fields and let's just show the contents here so if I go to First blog post this Rich Text let me just comment this out for a second also the preview alert sure we haven't created this okay as you can see this encounters an error and the reason why is this content field that we're trying to show here is an object and objects are not valid react children so let me just comment this one out as well and actually log the contents of this content field okay so as you can see our title image and cover image in Avatar is showing up let's just inspect this guy let me just bring this down make this a bit bigger so as you can see over here this object is this content that we are logging so it's it's an object itself that contains content and data and the content the content inside of it is just an array of everything that we have on our page so if we go back to this content all of these paragraphs and lines and different things are now represented with this array of objects that each one as you can see here the node type is paragraph heading paragraph block code these are kind of the Json representation of our content there now to render this object as a react component as you can see they encountered an error if you just look if you just put it out there directly so we have to use another package from contentful that turns this object into this Json object into react components and that package is called let me just copy the name from here so the package is called contentful reach text react renderer this is from contentful and allows you to turn Rich Text documents or Json objects into react components let me just restart the dev server so what are we going to do we're going to have to Define this Rich Text custom component and I'm going to put this directly in the components folder so I'm going to say reach text Dot jsx okay let's just do this step by step so the first thing that we do is to import this document to react component from the package we just installed and we're defining this Rich text component that takes in a Content that we're passing to it like so and that's the content this same Json object we looked at it together and this function is going to turn that into react components that we can use we can optionally pass it some options so for now I'm going to just say these options is an empty object okay and back here we are having our components back and now if I close this guy you can see my content is showing up here so I have this blog post this is a heading it's not looking like a heading but I at least have my com my content on my page without any errors now to style them let's just inspect the page real quick so as you can see the when this function is actually parsing that Json data it is returning the correct tags or HTML tags for us excuse me so if you had a paragraph versus a heading a block code component or a link so it turns them to corresponding HTML tags we just need to style them now if you can see here I'm wrapping this Rich text component with this div and I'm including this Tailwind Pros class but right now it's not working now if you go to Tailwind this is an easy way for us to style HTML in bulk so there is this Tailwind typography package that we can install which allows us to pass this prose class to markdown files or the content that's coming from like a CMS that we can't control to putting classes on and when we include this prose class as on the wrapper element of anything that's inside of it it just goes ahead and styles those different HTML tags inside of this kind of prose wrapper without us having to specifically set any classes on individual tags that's returned from this document to react component function so let's just go ahead and install this Tailwind typography package let me stop the dev server so npm I Dash D and we need to add it as a plug-in to our config so in the plugin here I can just include this and now if I restart my Dev server when I go to posts and my first post as you can see now everything is styled correctly so this is a heading the italic and bold the block code and if I go back to my post to my second post I can see here that I have my list items and I have my external link working correctly but my internal link so if I show it in the content if we go to the second post over here I have an internal link here that links to the first blog post and right now this is just showing as an object or as an entry type entry hyperlink and ID it's not showing correctly if you're going to fix this together and the code this kind of block is not kind of styled properly the embed video is now showing up the embed asset or the image that we could see over here to this image and this component is not showing up because we're not doing anything about it we're going to fix that in a second but at least we got the basics of are post content fetched from contentful and it's being styled easily with this tail in topography utility package that just Styles this HTML tags that are inside of this Pros class okay now let's go back to this Rich text component and the different options that we can pass in so that we could take care of internal links you know assets and videos that we embed in our file now this document to react component what it does is it it will iterate over the arrays of that content we saw together and for each one decides what to render and we have some control over what we want to Output in different cases so let me just bring in the complete file here I'm going to explain what each of these methods are doing over here but basically to begin this is just the same thing we had before document to react component we are just editing over our content and trying to kind of parse them into react components now if you're populating some options here that gives us more control in the output of this function now before I explain that I want to point out to this document on contentful docs that talks about this customizing rendering in react which is basically using this same function and this extra package we're going to install together that allows us to Define some types so for example if we are dealing with a bold type of marks or a paragraph from the blocks type we get to decide what the output of this parser or this function is going to be for example here it has defined a text component that takes in the children and returns a paragraph with a specific class and we are saying hey inside of our options in the render node anytime that you're encountering a node of type paragraph Just render that text anytime you're encountering a bold element just render this bold custom component that's just they span with a class name of bold and then we are calling this document to react component we're passing in the document or our content together with these options basically if you're doing the same thing over here we have to install this package so let me just stop to the server first of all and install that package so we can use different types that comes in when we're parsing our content let me just run the dev server again and let's see what we're doing here so I have two outermost methods the render Mark and render node each one of them take in different properties that are again methods so in the code I'm saying hey if you got a code which is the code blocks that we had on our post over here uh where was it yeah here so I'm saying just wrap them in a pre-tag and a code so that's the code I could have just added um Maybe marks Dot bold as we just saw together get the text and maybe just return a span with that text and let's just put a class name of font bold from tell it right so that's how easy if I can type correctly that's how easy you can customize the return value of each node and each kind of segment or element inside of this content object okay I'm just going to remove this now that was the marks the second part is the render node here for the paragraphs all I'm doing is that I'm saying if there was a code inside of a paragraph Just show a div inside of a P tag because the browser is going to scream at you if you put a pre-tag inside of a P tag so it I'm just changing it to div tag so that it doesn't scream at me for every other cases I'm just returning a regular pair of tags so that's the first thing that I'm doing the second thing is taking care of hyperlinks so if I'm having an inline link to another entry of my own content which is this first blog post that we saw together wasn't working before it's not it's working now because of this so all I'm saying is that hey this link to an entry is called entry hyperlink so if you encountered that uh look to see if the content type is of post so if the link is actually to another post because it can be to another author it can be to another Maybe video if it is a post just render a link with this posts uh kind of href so therefore this just takes us to the first post correctly because I have defined the path or the structure here in this in line kind of option that I have over here now the inline is hyperlink this is where we would have just an external link so if we go back over here this Google one is just an external link it's called hyperlink it's not entry hyperlink and in that case I'm just rendering an a tag with a Target blank so if I click on it it should open on a new page okay easy as that now these last two are when we are embedding entries or assets on our site so remember if I go back to our content um if you remember here I had an embedded asset so this is an asset we created together now I'm just including it here so how do we go about showing this asset so this is the last option here so I'm going to start with this I'm saying hey if you have an embedded asset right and my embedded asset is an image so go ahead and create a contentful image component and pass in those components so now you might ask an embedded asset maybe a video well in this case I don't have it but if you do you'd have to just check in to see if the type is image or if it's a video and then render the correct component for me the only assets that I have created are images so I'm saying hey just render that same contentful image component that we created before and pass in this necessary props to it so that's easy now the next one is this embedded video that you could see over here how do we go about doing that and that's the block embed entry over here that I'm going to come back to this part in a second but the way that I am doing it is if you come to this Rich Text Editor when you are kind of editing your blog post there is no way in this content kind of section for me to embed a video there are links and text options list options but nothing for me to embed a video so the way that I'm doing it is I'm creating a different type called embed video and then I'm using this embed functionality to embed an entry so let's just go one level back in the content model I've created this video embed type that has a title and a short text field where you can paste in and embed URL so from this content model we can create now some contents and I went ahead and created this content so if you could see this from our content type video embed if you click on it it's I've created just one entry I've gave you the title which is one of my videos on the channel the next.js 13 introduction and then I've pasted in the embed URL now one quick note over here if you want to get uh the link for the embed don't just copy the link that you see let's say here but if you go on any of these long to see our first you shouldn't copy this link because this just errors out if your link copying this inside of an iframe in your site instead you could just go here and get the share or here get the embed and get this link which is the embed link for that and I guess this is just a like you could just update that yourself too change the watch and then remove these two characters but you can just copy it from here so that it works properly when you're pasting this inside of an iframe because that's how we're going to be showing it later inside of an iframe that's how we embed videos on our site but nevertheless I have created an entry for this video embed type of this type so I can go back to my content on the second blog post and I can say hey if I come in here and say embed entry it allows me to embed any of my entries and I can select that single entry that I created for my next video on the channel so that that's what we've done here right now in the back end here when we're parsing this content these are called embed entry okay so it's an embedded entry I'm saying hey if you encounter one of these guys check to see if the content type is video embed and this is what I have defined over here this video embed if you look at the ID is just video embed so I'm saying if it is video I'm bad show this iframe drill down into the fields get the embed URL and the title and just show it on the page that's why it's showing up the way that it's supposed to be now you may create more entries or more embed entries that you would put on your page all you need to do is to check the type let's say maybe I want to have my own code blocks I don't want to use these code blocks like this I want to have a specific kind of type for code blocks and inside of them I want to maybe style them differently or put in different fields maybe I want to put in what type of language this is or what's the file name so forth and so on and then I want to create entries for that code block and then embed those entries inside of my blog post so therefore here in this if check for the content type I'll check to see if this is a code Block versus a video embed so the sky is the limit you can have so many different content types that you can put in here it's just that for this tutorial I just had one and that's the only one that I'm checking which allows me to show the content of my page let's now talk about the preview functionality in contentful so right now anytime that we are changing and updating a Content via publishing it before we are able to see it on our site what if you just want to preview the changes we have with this open preview functionality before actually publishing it and I guess this will be more useful when you're deploying your app and your content editors and you know marketing team is trying to kind of update or create a new entry and then they want to preview it before publishing it on uh the actual site so let's see how we can set this up so if you go to your settings there is a Content preview tab over here when you come here for the first time there is nothing I've already created one but you could go just go ahead and create a Content preview and here you will give you the name and then you would specify a preview URL so here I'm specifying The Local Host because this is where I'm running right now and this is how I want to re enable or where I want to preview my content I'm hearing the API preview this is an endpoint we have to create together and then I'm passing in a secret to be sure that this request is coming in actually from contentful by hitting that open preview and not somebody else hitting this endpoint and I'm passing in a slug as you can see on the right hand side it shows you what dynamically contentful would insert here for you so I'm saying Hey I want to get this log so I want to be able to preview posts this is the type of Entry if I had more entries or more types over here it would allow me to choose them right now I have author or post or video embed these are the only three types that I have and I've only enabled to preview my posts and I'm saying past the slug of that post here to this API endpoint so I know what content to fetch and what content to show so the first step is to specify this and if you wanted to specify one for not the development actually for your live site instead of specifying localhost here you would just plug in the endpoint the domain of your live application so on here on our application we have to create these API endpoints so I'm going to rename this to preview and I'm going to paste in the code and I'm going to explain what exactly is happening now the first thing that we are doing here is destructuring the secret and the slug out of the request and these are the stuff that we sent over here so the slug is provided for us by contentful and the secret is whatever we chosen here this is a way to just check to see that this request again is coming from condel so the first step we are saying if there is no slog or the secret is not the secret that we are setting in our environment variable just return a 401 bad request and say invalid token so we need to pass in two more environment variables now we had the space ID and the regular access token set before I just deleted them here to be able to show you these two so for the preview functionality we need the preview secret and the preview access token so for the preview access token you could just go ahead to your API keys I have shown this in the beginning you might remember so we had two API Keys one was for Content delivery API and the second was one was for Content preview API access token so all you need to do is to copy this access token so you can use to create a client a preview client from contentful that allows us to fetch unpublished or draft content so the preview access token is the guy from your dashboard and this preview secret is whatever you just passed in this secret over here I said preview you could say whatever secret you want it's the same thing you would just set over here sorry like so okay once you've done that uh let me just copy mine too and then we'll continue okay I've copied my environment variables and now we can create this preview client now all we need to do to create this preview client is go to library where we are requiring that contentful package and creating a client and actually create a second client that's very similar to the way that we're doing it there it's just a preview client and the difference is the host is preview.contentful.com here the host just defaults to [Music] um I think cdn.contentful contentful.com you don't need to pass it it defaults to that but for the preview we have to set it to the preview uh kind of sub domain of contentful their space ID is the same but the access token this time is this contentful preview access token we just set together now with this if you're having two clients for content for one it's just a regular client that fetches uh the published content the other one the preview client fetches unpublished or draft content okay so let's save this go back to our preview so all they're really doing here is to check the secret and slug to see actually if they've passed in the secret and if it matches the environment variable secret that we just set together if not we're going to say invalid token and then we're going to check to see if actually there is a post on our contentful with this slug if that post doesn't even exist we're going to say this is an invalid slog you're trying to preview and if everything goes well all we're doing is we're setting this preview data cookie and then we are redirecting the user back to the posts for that slot which just brings them back to this Dynamic path that we've defined before but this time with a difference with this cookie that sets the preview data now this all it's going to do is going to set this preview data in next.js so with that cookie of your setting on the API route this preview is going to be true on the context object that's passed to this get static props and if you remember in the beginning I said just ignore this preview for now but all we're using this for is to say hey if this preview is true use the preview client if it's false which defaults to false if we never passed or set that cookie it's just going to use the regular client which fetches the published content so again in this preview endpoint we are still using that same get static props on same pages to previewer content it's just that we're using a different client to now this time Fetch and a draft or unpublished version of this specific post for that slog and then on the page component itself too of your receiving this preview and then we are showing this preview alert and the reason why we do that is uh we're going to see in a second when you actually go to the preview page you want to have a way for the user to exit the preview because they're going to be on that same endpoint anyways so let's actually try that so let's just go to our contents in contentful so let's go to this second post block and let's say I want to put in some exclamation uh marks at the end of the title I'm not going to publish it I'm just going to wait for this to save and then I'm going to just hit open preview and all this does is again hits that end point checks to see if this is logs uh actually exist or not and then redirects us back to this post second post with this log which is just this function we've been working on before but this time because we're using the preview client we are just getting this draft version which has this exclamation points now again because we are on that same endpoint we want to give the user a way to exit the preview so that they could see actually the published content and to do that we we have to define a new endpoint called exit Dash preview .js let me just copy the code here okay so all this endpoint is doing is it's clearing the preview data that we set over here and all that does it just turns this preview back to false so therefore we are going to use the regular client which fetches the already published content and not the draft okay so that's all this endpoint is doing and then after clearing the data the preview data it just redirects the user back to the home page now we have to give the user a way to hit this endpoint and this is where this uh preview alert component comes in so let me just uncomment this here so in the components UI I have passed in or copied this preview alert and all this is doing is actually showing a little toast notification on top of the page that tells the user this is a preview and gives them a link and that link hits that endpoint we just created API exit preview so once they hit there the preview data will be cleared and they will be redirected back to the home page where they can just use the regular client to fetch published content now this uh component I just copied is using uh headless UI so let me just go ahead and install these packages and it's actually using let me see this icons too so let me go to components to documentation I think we are actually using hero icons too so let's just copy that one as well if you don't know what headless UI is a library from the Tailwind team that gives you um UI components so headless UI it's you know different UI components and they're undesigned um so you can just use them it's it's great so let me just rerun the dev server over here close that and here on the blog post okay so right now we are seeing the publish content we don't see the exclamation point if I go over here and say open preview we're going to see the open preview the preview with this exclamations and that's the pop-up toast notification that I just set with this alert preview and again if you're just conditionally showing this if this preview that's returned back from get static props is true we're just showing that preview alert it just says hey this page is preview uh click here to exit the preview mode once we click here it just goes back to the home page and again this exit preview all it does is just clears that preview data and redirects the user back to the home page so this time if I just go to the second blog post now I'm using the regular client from contentful I'm just getting the regular posts and not the drafts that's a wrap for this video folks I know we covered a lot of grounds with contentful and xjs in this video if you have any questions leave them in the comments I try to be as responsive as I can there and if this is type of content that you like and if you're interested into learning how to build full stack apps with react and xjs you might be interested in checking out my course the full next.js course that we have I'm going to include the link in the description below and I'll see you in the next one bye
Info
Channel: Hamed Bahram
Views: 24,754
Rating: undefined out of 5
Keywords:
Id: ApztAQuXisU
Channel Id: undefined
Length: 83min 42sec (5022 seconds)
Published: Sun Jan 22 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.