Stackbit is a website builder that gives both technical and non-technical people a lot of power when creating their websites. It can be used to create portfolio websites, blogs, or any type of website if you wish to extend it to your use case.
In this tutorial, you'll learn how to create a blog with Stackbit using its Next.js starter theme. You'll also learn how to add custom pages for Content Models by creating an Authors page.
Project Setup
Start by choosing one of the Starter theme. This tutorial will be focused on the Starter theme.
Then, choose a name for your new project.
If you're not signed in you'll then be asked to either create an account or sign in. I recommend creating an account with GitHub as it will be easier to connect your repository to it then.
You'll then have your website ready for customization.
Notice that your website will be deployed on a free Stackbit subdomain. So, you'll be able to view it online right away.
Transfer Repository to Your Account
The next step is to transfer the website codebase to your GitHub account. This makes it possible for you to make changes to the website's codebase and add new content models.
Click on the gear icon at the top left. Then, under "Connected Services" you'll see GitHub and you'll be able to Request Repo Transfer.
When you click on that you'll receive an email to accept the transfer. Once you click on the link in the email, the transfer will begin and might take a couple of minutes.
Once the transfer is done, you'll have your website's codebase in you GitHub account.
Understanding the Branches
In your GitHub repository, you'll have 2 branches: the master
branch and the preview
branch.
The master
branch is the deployed version that everyone can see when they go on your website.
The preview
branch is what you can see when you log in on Stackbit. Think of it as a draft version. Once you think the changes are ready to be deployed on the main website, you can either push the changes to the master branch manually or just click the "Publish" button at the top right in your Stackbit app.
Set Up Local Development
Stackbit has a code editor that you can use right in your Stackbit app by clicking on the code icon in the sidebar.
Once you make a change in the code, it will be automatically committed to the preview
branch which is what you see in your Stackbit app.
Alternatively, you can work on your website's development locally. To do that, click on the gear icon at the top left again. Under "Envoironment" you'll see "Local Development" with steps you can copy and paste into your terminal directly.
Please note that if you haven't transferred the codebase into your GitHub account you won't be able to see these tips.
As mentioned under "Local Development", once you push commits to the preview
branch, the visual editor in your Stackbit app will update automatically.
Creating Posts
There are 2 ways to create posts: through the visual editor or through the code editor.
Visual Editor
On your Stackbit app, if you press the second icon "CMS" you'll be able to edit and add pages and blog posts on your website.
Try clicking on "Post" then "Add new Post". You'll be able to enter information like slug and title. Then, you can select a feature image and the author.
You can then use the content editor, which has text formatting you can use but also supports raw markdown editing by pressing the Raw MD button.
All changes you make to posts are automatically committed to the preview
branch. Once you publish them they'll be live on your deployed website.
Code Editor
To add posts in the code editor, go to content
then pages
. You'll see all pages there in markdown files, where the names of the files are the slugs of the pages.
You'll also find a blog
directory which holds all posts inside it. To add a blog post create a new file with its name the slug you want for the post. Then, add in it the following information:
---
title: Test Post
layout: PostLayout
date: '2021-07-01'
author: content/data/team/hugh-saturation.json
excerpt: >-
Sed in facilisis dui. Nulla molestie risus in mi dapibus, eget porta lorem
semper. Donec sed facilisis nibh.
featuredImage:
type: ImageBlock
url: /images/post-2.jpg
altText: Post Image
bottomSections:
- elementId: ''
variant: variant-c
colors: colors-a
title: Read next
recentCount: 3
styles:
self:
height: auto
width: wide
margin: ['mt-0', 'mb-0', 'ml-0', 'mr-0']
padding: ['pt-12', 'pb-56', 'pr-4', 'pl-4']
justifyContent: center
title:
textAlign: center
subtitle:
textAlign: center
actions:
justifyContent: center
type: RecentPostsSection
---
This is test post
Everything between the opening and closing 3 dashes are the values of the fields you enter in your visual editor. That includes the title, author, feature image, and more.
Then, after the three dashes is the markdown content of the post. This is the content you'd enter in the text editor in the visual Stackbit app, but it should be in markdown format.
Once you're done, save the new file and commit it to the preview
branch. You'll be able to see it in the visual editor among the CMS.
If you also open the Blog page in your Stackbit app or open the website locally, you should see the post you added among other existing posts.
Add Pages for Authors
In this section, you'll start to customize your Stackbit starter. You'll be adding a new predefined type of page to display authors. You'll need to create a layout specific for that page before creating that page.
Add Page to Content Models
Open stackbit.yaml
in the root of your website's code and add the following under contentModels
:
contentModels:
...
PersonFeedLayout:
isPage: true
singleInstance: true
urlPath: '/authors'
file: 'authors.md'
newFilePath: 'authors.md'
You're adding a new layout PersonFeedLayout
. You can read more about content model fields in Stackbit's documentation, but briefly:
- If
isPage
is set totrue
the UI will allow you to create pages using this model. singleInstance
means that this page can only be created once.urlPath
is the path that this page will be found on.file
is the markdown file that holds the data and content for this page. Since this is a page, its path is relative tocontent/pages
newFilePath
is the file that should be created when this page is created through the UI. Similarly, since this content model is a page the path is relative tocontent/pages
.
Define the Content Model Fields
In this section, you'll define the fields of the new content model PersonFeedLayout
. This means that when you try to create the page through the UI, these fields is what you will see.
To do that, create the file .stackbit/models/PersonFeedLayout.yaml
with the following content:
name: PersonFeedLayout
label: Authors
labelField: title
layout: PersonFeedLayout
hideContent: true
extends:
- Seo
fields:
- type: string
name: title
label: Title
default: This is a page title
- type: list
name: topSections
label: Top Sections
items:
type: model
groups:
- sectionComponent
- type: list
name: bottomSections
label: Bottom Sections
items:
type: model
groups:
- sectionComponent
- type: style
name: styles
styles:
title:
fontWeight: ['400', '700']
fontStyle: ['normal', 'italic']
textAlign: ['left', 'center', 'right']
default:
title:
textAlign: center
You can learn more about Models in Stackbit through their documentation, but briefly the items under fields
are what you'll see in the UI and the fields you can enter for this content model. This content model has 4 fields:
title
: the title of the pagetopSections
: Sections you want to add to the top of the page. This is useful if you want to allow users using the visual editor to add custom sections before your defined layout.bottomSections
: Similarly totopSections
, you'll allow users using the visual editor to add custom sections after the defined layout.styles
: Allow the users using the visual editor to customize some of the style of the layout.
Create New Layout
Next, you'll be creating the PersonFeedLayout
which will hold the implementation of the Authors page.
Create a new file src/components/layouts/PersonFeedLayout/index.tsx
with the following content:
import * as React from 'react';
import ImageBlock from '../../molecules/ImageBlock';
import { getBaseLayoutComponent } from '../../../utils/base-layout';
import { getComponent } from '../../components-registry';
export default function PageLayout(props) {
const { page, site } = props;
const BaseLayout = getBaseLayoutComponent(page.baseLayout, site.baseLayout);
const topSections = page.topSections || [];
const authors = page.authors || [];
const bottomSections = page.bottomSections || [];
return (
<BaseLayout page={page} site={site}>
<main id="main" className="sb-layout sb-page-layout">
{page.title && (
<h1 className="text-center my-5" data-sb-field-path="title">
{page.title}
</h1>
)}
{topSections.length > 0 && (
<div data-sb-field-path="sections">
{topSections.map((section, index) => {
const Component = getComponent(section.type);
if (!Component) {
throw new Error(`no component matching the page section's type: ${section.type}`);
}
return <Component key={index} {...section} data-sb-field-path={`sections.${index}`} />;
})}
</div>
)}
<div className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-10 my-16 max-w-screen-md mx-auto'>
{authors.map((author, index) => (
<div className='group text-center' key={index}>
{author.image && <ImageBlock {...author.image}
className="group-hover:shadow-md transition-shadow rounded-full w-40 h-40 mx-auto" />}
<h3>{author.firstName} {author.lastName}</h3>
<span className="text-gray-500">{author.role}</span>
</div>
))}
</div>
{bottomSections.length > 0 && (
<div data-sb-field-path="sections">
{bottomSections.map((section, index) => {
const Component = getComponent(section.type);
if (!Component) {
throw new Error(`no component matching the page section's type: ${section.type}`);
}
return <Component key={index} {...section} data-sb-field-path={`sections.${index}`} />;
})}
</div>
)}
</main>
</BaseLayout>
);
}
First, notice that you display the topSections
first and the bottomSections
last in your layout.
In the middle, you display the authors in a grid. The authors are received in the props of the layout. You'll be defining this in the next section.
After creating this layout, add it in src/components/layouts/index.tsx
:
import PostFeedLayout from './PostFeedLayout';
//...
export {
...,
PersonFeedLayout
}
Finally, you need to add it to src/components/components-registry.ts
:
const components = {
//...,
'PersonFeedLayout': dynamic(() => import('./layouts/PersonFeedLayout'))
};
Add Props
To define the props passed to this layout, first, go to src/utils/data-utils.js
and add a new function:
export function getAuthors(objects) {
return objects.filter((object) => object.type === 'Person');
}
The sourcebit-target-next
plugin will use the sourcebit-source-filesystem
to read files under content
and import them into your Stackbit website.
There are two types of content: pages under the content/pages
directory and data under content/data
directory. You'll be able to filter out content based on the type
field for data content, or the layout
field for pages content.
In this case, you're retrieving all authors, which are data content. So, you check if the type
field is Person
. Please note that, by default, all authors are under content/data/team
in JSON files.
Next, you'll use this function to pass the authors as a prop to the layout you created in the previous section. Go to src/utils/static-props-resolvers.js
and add the following:
import {
//...,
getAuthors
} from './data-utils';
//...
const StaticPropsResolvers = {
//..,
PersonFeedLayout: (props, data) => {
return {
...props,
authors: getAuthors(data.objects)
};
}
};
Your Next.js website will resolve the props of the layouts by checking through the StaticPropsResolvers
object. The key is the name of the layout and the value is a function that returns an object which will be the props of the layout.
You add a new key for PersonFeedLayout
which accepts props
and data
as parameters. props
is the data entered by the user in the UI for the fields you created for the content model earlier. For example, the bottomSections
field.
The data
is all the data on your website made available by sourcebit-target-next
as explained earlier. It is an object that has 3 properties:
-
objects
which is an array of all content files loaded by thesourcebit-source-filesystem
plugin. pages
which is an array holding all static page props.props
which is an object with common props for all pages.
In this function, you return all the props as-is and you add the authors
prop which will call the getAuthors
function you created earlier passing it data.objects
.
Add the Authors Page
Finally, you just need to add the Authors page. Create the file content/pages/authors.md
with the following content:
---
title: Authors
layout: PersonFeedLayout
topSections:
- type: CtaSection
elementId: ''
colors: colors-a
backgroundSize: full
title: Let's do this
text: >-
The Stackbit theme is flexible and scalable to every need. It can manage
any layout and any screen.
actions:
- type: Button
label: Try it now
url: /
style: primary
backgroundImage: null
styles:
self:
height: auto
width: narrow
margin:
- mt-0
- mb-0
- ml-0
- mr-0
padding:
- pt-24
- pb-24
- pl-4
- pr-4
alignItems: center
justifyContent: center
flexDirection: col
title:
textAlign: left
text:
textAlign: left
actions:
justifyContent: flex-start
---
This defines the page to use the PersonFeedLayout
and adds among its top sections a Call to Action (CTA) section.
If you run your server now:
npm run dev
and go to /authors
, you'll be able to see all the authors in your blog.
If you push the changes to the preview
branch you'll be able to see your new page in the Stackbit app as well as edit the page fields.
Add Link to Page in the Header
Optionally, you can add a link to the page in the header. To do that, open content/data/config.json
and add the new link under primaryLinks
in header
:
{
...,
"header": {
...,
"primaryLinks": [
...,
{
"type": "Link",
"label": "Authors",
"altText": "Authors",
"url": "/authors"
}
]
}
}
If you save the changes and view the website in local development, or push the changes to the preview
branch to view it on the Stackbit app, you'll see a new link the navigation bar for "Authors".
Conclusion
In this tutorial, you learned how you can set up Stackbit and do some development and customization on it. For more features, be sure to check out Stackbit's documentation for more details.