Build a static blog using Gatsby and Strapi
Strapi
Posted on February 15, 2021
Introduction
If you are familiar with our blog you must have seen that we've released a series of tutorials on how to make blogs using Strapi with a lot of frontend frameworks: React, Next.js, Vue, Nuxt.js or Angular.
This one if for the people who wants to build a simple static blog with Gatsby!
Why gatsby?
Gatsby is a blazing-fast **website framework* for React*. It allows developers to build React based websites within minutes. Whether you want to develop a blog or a corporate website, Gatsby will fill your needs.
Because it is based on React, the website pages are never reloaded which makes the generated website super fast. A large set of plugins is available to allowing developers to save time coding. For example, plugins exist to get data from any source (Markdown files, CMS, etc.). Gatsby is strongly based on the "node" interface, which is the center of Gatsby's data system.
Created by Kyle Mathews, the project was officially released in July 2017. (As of February 2109,Gatsby is in Gatsby v2 and is now used by many companies and for hundreds of websites.
What is Strapi?
Strapi is the open source **Headless CMS **. It saves weeks of API development time, and allows easy long-term content management through a beautiful administration panel anyone can use.
Unlike other CMSs, Strapi is 100% open-source, which means:
- Strapi is completely free.
- You can host it on your own servers, so you own the data.
- It is entirely customisable and extensible, thanks to the plugin system.
Starters
You may want to directly try the result of this tutorial. Well, we made a starter out of it so give it a try!
Goal
The goal here is to be able to create a simple static blog website using Strapi as the backend and Gatsby for the frontend
The source code is available on GitHub.
This tutorial is an update of the old version. We will make this tutorial shorter and more efficient by using our new templates.
Prerequisites
This tutorial will always use the latest version of Strapi. That is awesome right!? You'll understand why below.
You need to have node v.12 installed and that's all.
Setup
- Create a blog-strapi folder and get inside!
take blog-strapi
Back-end setup
That's the easiest part of this tutorial thanks to Rémi who developed a series of Strapi templates that you can use for your Blog, E-commerce, Portfolio or Corporate website project.
These templates are Strapi applications containing existing collection-types and single-types suited for the appropriate use case, and data.
In this tutorial we'll use the Blog template and connect a Gatsby application to it.
Note: for this tutorial, we will use yarn
as your package manager.
- Create your Strapi backend folder using the Blog template.
yarn create strapi-app backend --quickstart --template https://github.com/strapi/strapi-template-blog
Don't forget that Strapi is running on http://localhost:1337. Create your admin user by signing up!
That's it! You're done with Strapi! I'm not kidding, we can start to create our Gatsby application now in order to fetch our content from Strapi.
Ok ok wait, let's talk about this amazing template you just created.
You should know that before the starters and before the templates we only had tutorials. The idea of creating starters came to us when we realized that we could do something with the end result of our tutorials. Thus were born our starters.
However Strapi evolves quickly, very quickly and at the time the starters constituted a repository including the backend as well as the frontend. This means that updating the Strapi version on all our starters took time, too much time. We then decided to develop templates that are always created with the latest versions of Strapi. Quite simply by passing in parameter the repository of the desired template like you just did. Also, it gives you a good architecture for your Strapi project.
These templates provide a solid basis for your Strapi application.
- 3 Collection types are already created. Article, Category, Writer.
- 2 Single types are already created. Global, Homepage.
- Find and FindOne permissions are publicly open for all of you content-types types and single types.
- Existing data.
Feel free to modify all this, however, we will be satisfied with that for the tutorial.
Nice! Now that Strapi is ready, you are going to create your Gatsby application.
Front-end setup
The easiest part has been completed, let's get our hands dirty developing our blog with Gatsby!
Gatsby setup
First of all, you'll need to install the Gatsby CLI
- Install the Gatsby CLI by running the following command:
yarn global add gatsby-cli
- Create a Gatsby
frontend
project by running the following command:
gatsby new frontend
Once the installation is completed, you can start your front-end app to make sure everything went ok.
cd frontend
gatsby develop
We are not keeping the default Gatsby starter style but the one we used for every other tutorials of this series. You'll see that after! First let's create an .env
file containing some environment variables for our Gatsby application.
- Create ann
.env
file at the root of your Gatsby application containing the following:
GATSBY_ROOT_URL=http://localhost:8000
API_URL=http://localhost:1337
Strapi Setup
To connect Gatsby to a new source of data, you have to develop a new source plugin. Fortunately, several source plugins already exist, so one of them should fill your needs.
In this example, we are using Strapi. Obviously, we are going to need a source plugin for Strapi APIs. Good news: we built it for you!
- Install
gatsby-source-strapi
by running the following command:
yarn add gatsby-source-strapi
This plugin needs to be configured.
- Replace the content of
gatsby-config.js
with the following code:
require("dotenv").config({
path: `.env`,
});
module.exports = {
plugins: [
"gatsby-plugin-react-helmet",
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
{
resolve: "gatsby-source-strapi",
options: {
apiURL: process.env.API_URL || "http://localhost:1337",
contentTypes: ["article", "category", "writer"],
singleTypes: [`homepage`, `global`],
queryLimit: 1000,
},
},
"gatsby-transformer-sharp",
"gatsby-plugin-sharp",
{
resolve: `gatsby-plugin-manifest`,
options: {
name: "gatsby-starter-default",
short_name: "starter",
start_url: "/",
background_color: "#663399",
theme_color: "#663399",
display: "minimal-ui",
icon: `src/images/gatsby-icon.png`
},
},
"gatsby-plugin-offline",
],
};
What's important here is that we define our API_URL
for the Strapi API: http://localhost:1337
without a trailling slash and the collection types and single types you want to be able to query from Strapi, here for this tutorial: article, category, writer, global and homepage
Alright! Gatsby is now ready to fetch data from Strapi! Let's add our custom css now!
UIkit setup
Gatsby generate by default a Seo
component. We will update it in order to configure our Seo, add UIkit cdn and Staatliches font.
- Replace the content of
src/components/seo.js
with the following:
import React from "react";
import PropTypes from "prop-types";
import { Helmet } from "react-helmet";
import { useStaticQuery, graphql } from "gatsby";
const SEO = ({ seo = {} }) => {
const { strapiGlobal } = useStaticQuery(query);
const { defaultSeo, siteName, favicon } = strapiGlobal;
// Merge default and page-specific SEO values
const fullSeo = { ...defaultSeo, ...seo };
const getMetaTags = () => {
const tags = [];
if (fullSeo.metaTitle) {
tags.push(
{
property: "og:title",
content: fullSeo.metaTitle,
},
{
name: "twitter:title",
content: fullSeo.metaTitle,
}
);
}
if (fullSeo.metaDescription) {
tags.push(
{
name: "description",
content: fullSeo.metaDescription,
},
{
property: "og:description",
content: fullSeo.metaDescription,
},
{
name: "twitter:description",
content: fullSeo.metaDescription,
}
);
}
if (fullSeo.shareImage) {
const imageUrl =
(process.env.GATSBY_ROOT_URL || "http://localhost:8000") +
fullSeo.shareImage.publicURL;
tags.push(
{
name: "image",
content: imageUrl,
},
{
property: "og:image",
content: imageUrl,
},
{
name: "twitter:image",
content: imageUrl,
}
);
}
if (fullSeo.article) {
tags.push({
property: "og:type",
content: "article",
});
}
tags.push({ name: "twitter:card", content: "summary_large_image" });
return tags;
};
const metaTags = getMetaTags();
return (
<Helmet
title={fullSeo.metaTitle}
titleTemplate={`%s | ${siteName}`}
link={[
{
rel: "icon",
href: favicon.publicURL,
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css?family=Staatliches",
},
{
rel: "stylesheet",
href:
"https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/css/uikit.min.css",
},
]}
script={[
{
src:
"https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.min.js",
},
{
src:
"https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/js/uikit-icons.min.js",
},
{
src: "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.js",
},
]}
meta={metaTags}
/>
);
};
export default SEO;
SEO.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
image: PropTypes.string,
article: PropTypes.bool,
};
SEO.defaultProps = {
title: null,
description: null,
image: null,
article: false,
};
const query = graphql`
query {
strapiGlobal {
siteName
favicon {
publicURL
}
defaultSeo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`;
Wow! That's a lot of code! Here we are simply fetching the content of the Global collection type.
const query = graphql`
query {
strapiGlobal {
siteName
favicon {
publicURL
}
defaultSeo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`;
This way, we can use this data in our SEO component.
const SEO = ({ seo = {} }) => {
const { strapiGlobal } = useStaticQuery(query);
const { defaultSeo, siteName, favicon } = strapiGlobal;
...
In order to have a simple but beautiful blog we're going to add some style:
- Create a
src/assets/css/main.css
file containing the following:
a {
text-decoration: none !important;
}
h1 {
font-family: Staatliches !important;
font-size: 120px !important;
}
#category {
font-family: Staatliches !important;
font-weight: 500 !important;
}
#title {
letter-spacing: 0.4px !important;
font-size: 22px !important;
font-size: 1.375rem !important;
line-height: 1.13636 !important;
}
#banner {
margin: 20px !important;
height: 800px !important;
}
#editor {
font-size: 16px !important;
font-size: 1rem !important;
line-height: 1.75 !important;
}
.uk-navbar-container {
background: #fff !important;
font-family: Staatliches !important;
}
img:hover {
opacity: 1 !important;
transition: opacity 0.25s cubic-bezier(0.39, 0.575, 0.565, 1) !important;
}
Please don't force me to explain you some css!
Architecture
Before we can dive in, we have to clean the default Gatsby architecture by removing useless components/pages
- Remove useless components/pages by running the following command:
rm src/components/header.js src/components/layout.css src/components/image.js src/pages/page-2.js src/pages/using-typescript.tsx
We are also going to update the pages/index.js
and components/layout.js
files
- Replace the content of
pages/index.js
by the following code:
import React from "react";
import { graphql, useStaticQuery } from "gatsby";
import Layout from "../components/layout";
import "../assets/css/main.css";
const IndexPage = () => {
const data = useStaticQuery(query);
return (
<Layout seo={data.strapiHomepage.seo}>
<div className="uk-section">
<div className="uk-container uk-container-large">
<h1>{data.strapiHomepage.hero.title}</h1>
</div>
</div>
</Layout>
);
};
const query = graphql`
query {
strapiHomepage {
hero {
title
}
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`;
export default IndexPage;
Here, we are just importing the Layout
component and the css file, this is the main page of your app.
- Replace the content of
components/layout.js
by the following code:
import React from "react";
import PropTypes from "prop-types";
import { StaticQuery, graphql } from "gatsby";
import Seo from "./seo";
const Layout = ({ children, seo }) => (
<StaticQuery
query={graphql`
query {
strapiHomepage {
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`}
render={(data) => (
<>
<Seo seo={seo} />
<main>{children}</main>
</>
)}
/>
);
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;
What is the Layouts component in Gatsby ? These components are for sections of your site that you want to share across multiple pages. For example, Gatsby sites will commonly have a layout component with a shared header and footer. Other common things to add to layouts are a sidebar and/or navigation menu.
We'll use this layout in order to put our Nav component inside.
You can already check out the result! You must simply have a blank page containing a h1 'My Blog'!
Nav component
Let's create our Nav that will display all your categories on top of every pages of your blog
- Create a
./src/components/nav.js
file containing the following code:
import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";
const Nav = () => (
<StaticQuery
query={graphql`
query {
strapiGlobal {
siteName
}
allStrapiCategory {
edges {
node {
slug
name
}
}
}
}
`}
render={(data) => (
<div>
<div>
<nav className="uk-navbar-container" data-uk-navbar>
<div className="uk-navbar-left">
<ul className="uk-navbar-nav">
<li>
<Link to="/">{data.strapiGlobal.siteName}</Link>
</li>
</ul>
</div>
<div className="uk-navbar-right">
<button
className="uk-button uk-button-default uk-margin-right"
type="button"
>
Categories
</button>
<div uk-dropdown="animation: uk-animation-slide-top-small; duration: 1000">
<ul className="uk-nav uk-dropdown-nav">
{data.allStrapiCategory.edges.map((category, i) => (
<li key={`category__${category.node.slug}`}>
<Link to={`/category/${category.node.slug}`}>
{category.node.name}
</Link>
</li>
))}
</ul>
</div>
</div>
</nav>
</div>
</div>
)}
/>
);
export default Nav;
What is going on here ? Let me explain
Gatsby v2 introduces StaticQuery
, a new API that allows components to retrieve data via a GraphQL query
query {
allStrapiCategory {
edges {
node {
slug
name
}
}
}
}
This one fetch all your categories from Strapi.
Then StaticQuery
render your html with the fetched data.
...
render={(data) => (
...
Now we need to use this component in your Layout
component.
- Import and use your new
Nav
component by pasting the following code inside yourcomponents/layout.js
file:
import React from "react";
import PropTypes from "prop-types";
import { StaticQuery, graphql } from "gatsby";
import Nav from "./nav";
import Seo from "./seo";
const Layout = ({ children, seo }) => (
<StaticQuery
query={graphql`
query {
strapiHomepage {
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`}
render={(data) => (
<>
<Seo seo={seo} />
<Nav />
<main>{children}</main>
</>
)}
/>
);
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;
Great! You should now be able to see your brand new nav containing your categories. But the links are not working right now. We'll fix this later on the tutorial, don't worry.
Note: The current code is not suited to display a lot of categories as you may encounter a UI issue. Since this blog post is supposed to be short, you could improve the code by adding a lazy load or something like that.
Articles component
We are going to display every articles on your main pages/index.js
page now:
- Replace the code of the
pages/index.js
file with the following code:
import React from "react";
import { graphql, useStaticQuery } from "gatsby";
import Layout from "../components/layout";
import ArticlesComponent from "../components/articles";
import "../assets/css/main.css";
const IndexPage = () => {
const data = useStaticQuery(query);
return (
<Layout seo={data.strapiHomepage.seo}>
<div className="uk-section">
<div className="uk-container uk-container-large">
<h1>{data.strapiHomepage.hero.title}</h1>
<ArticlesComponent articles={data.allStrapiArticle.edges} />
</div>
</div>
</Layout>
);
};
const query = graphql`
query {
strapiHomepage {
hero {
title
}
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
allStrapiArticle(filter: { status: { eq: "published" } }) {
edges {
node {
strapiId
slug
title
category {
name
}
image {
childImageSharp {
fixed(width: 800, height: 500) {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
src
}
}
}
}
}
}
}
}
`;
export default IndexPage;
As you can see, we are fetching the articles with useStaticQuery
that render them using this ArticlesComponent
.
Fetching articles:
allStrapiArticle(filter: { status: { eq: "published" } }) {
edges {
node {
strapiId
slug
title
category {
name
}
image {
childImageSharp {
fixed(width: 800, height: 500) {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
src
}
}
}
}
}
}
}
Render them using a component that we are going to create:
<ArticlesComponent articles={data.allStrapiArticle.edges} />
In fact we are going to separate our articles from left to right and we don't want this code to be inside the index.js
but in a component that we'll be able to reuse after that.
- Create a
components/articles.js
containing the following code:
import React from "react";
import Card from "./card";
const Articles = ({ articles }) => {
const leftArticlesCount = Math.ceil(articles.length / 5);
const leftArticles = articles.slice(0, leftArticlesCount);
const rightArticles = articles.slice(leftArticlesCount, articles.length);
return (
<div>
<div className="uk-child-width-1-2@s" data-uk-grid="true">
<div>
{leftArticles.map((article, i) => {
return (
<Card
article={article}
key={`article__left__${article.node.slug}`}
/>
);
})}
</div>
<div>
<div className="uk-child-width-1-2@m uk-grid-match" data-uk-grid>
{rightArticles.map((article, i) => {
return (
<Card
article={article}
key={`article__right__${article.node.slug}`}
/>
);
})}
</div>
</div>
</div>
</div>
);
};
export default Articles;
Here we are splitting our articles because we want to display some of them on the left side of the blog making them bigger and some on the right making them smaller. It's just a design thing, nothing really important
Again, we're using another Card
component. Components are the building blocks of any React application, this is why you'll find many of these in them.
The benefit to this approach is that you end up doing less duplicate work by managing the components rather than managing duplicate content across different pages. This concept has become a real success and you are going to use it too!
- Create a
components/card.js
file containing the following code:
import React from "react";
import { Link } from "gatsby";
import Img from "gatsby-image";
const Card = ({ article }) => {
return (
<Link to={`/article/${article.node.slug}`} className="uk-link-reset">
<div className="uk-card uk-card-muted">
<div className="uk-card-media-top">
<Img
fixed={article.node.image.childImageSharp.fixed}
imgStyle={{ position: "static" }}
/>
</div>
<div className="uk-card-body">
<p id="category" className="uk-text-uppercase">
{article.node.category.name}
</p>
<p id="title" className="uk-text-large">
{article.node.title}
</p>
<div>
<hr className="uk-divider-small" />
<div className="uk-grid-small uk-flex-left" data-uk-grid="true">
<div>
{article.node.author.picture && (
<Img
fixed={article.node.author.picture.childImageSharp.fixed}
imgStyle={{ position: "static", borderRadius: "50%" }}
/>
)}
</div>
<div className="uk-width-expand">
<p className="uk-margin-remove-bottom">
{article.node.author.name}
</p>
</div>
</div>
</div>
</div>
</div>
</Link>
);
};
export default Card;
- Refresh your app
Awesome! You can now display all your articles on the main page!
Article page
How can we create a page for each one of your article now? We'll need to use the createPages
API. It will be called once the data layer is bootstrapped to let plugins create pages from data.
- Add the following code to your
gatsby.node.js
file:
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(
`
{
articles: allStrapiArticle {
edges {
node {
strapiId
slug
}
}
}
}
`
);
if (result.errors) {
throw result.errors;
}
// Create blog articles pages.
const articles = result.data.articles.edges;
const ArticleTemplate = require.resolve("./src/templates/article.js");
articles.forEach((article, index) => {
createPage({
path: `/article/${article.node.slug}`,
component: ArticleTemplate,
context: {
slug: article.node.slug,
},
});
});
};
module.exports.onCreateNode = async ({ node, actions, createNodeId }) => {
const crypto = require(`crypto`);
if (node.internal.type === "StrapiArticle") {
const newNode = {
id: createNodeId(`StrapiArticleContent-${node.id}`),
parent: node.id,
children: [],
internal: {
content: node.content || " ",
type: "StrapiArticleContent",
mediaType: "text/markdown",
contentDigest: crypto
.createHash("md5")
.update(node.content || " ")
.digest("hex"),
},
};
actions.createNode(newNode);
actions.createParentChildLink({
parent: node,
child: newNode,
});
}
};
We are fetching all article and category slugs in order to generate pages for each one of them
It means that if you have 4 articles it will create 4 pages depending on the path you give, here it's path: /article/${article.node.slug}
:
/article/my-article
/article/another-article
/article/hey-strapi
/article/love-gatsby
Before going further you'll need to install two packages: one to display your content as Markdown and Moment
- Install
react-markdown
andreact-moment
by running the following command:
yarn add react-markdown react-moment moment
Now we need to create the page that will display each one of your article, you can see inside gatsby.node.js
that here it's const ArticleTemplate = require.resolve("./src/templates/article.js");
- Create a
src/templates/article.js
file containing the following:
import React from "react";
import { graphql } from "gatsby";
import Img from "gatsby-image";
import Moment from "react-moment";
import Layout from "../components/layout";
import Markdown from "react-markdown";
export const query = graphql`
query ArticleQuery($slug: String!) {
strapiArticle(slug: { eq: $slug }, status: { eq: "published" }) {
strapiId
title
description
content
publishedAt
image {
publicURL
childImageSharp {
fixed {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
src
}
}
}
}
}
}
`;
const Article = ({ data }) => {
const article = data.strapiArticle;
const seo = {
metaTitle: article.title,
metaDescription: article.description,
shareImage: article.image,
article: true,
};
return (
<Layout seo={seo}>
<div>
<div
id="banner"
className="uk-height-medium uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light uk-padding uk-margin"
data-src={article.image.publicURL}
data-srcset={article.image.publicURL}
data-uk-img
>
<h1>{article.title}</h1>
</div>
<div className="uk-section">
<div className="uk-container uk-container-small">
<Markdown source={article.content} escapeHtml={false} />
<hr className="uk-divider-small" />
<div className="uk-grid-small uk-flex-left" data-uk-grid="true">
<div>
{article.author.picture && (
<Img
fixed={article.author.picture.childImageSharp.fixed}
imgStyle={{ position: "static", borderRadius: "50%" }}
/>
)}
</div>
<div className="uk-width-expand">
<p className="uk-margin-remove-bottom">
By {article.author.name}
</p>
<p className="uk-text-meta uk-margin-remove-top">
<Moment format="MMM Do YYYY">{article.published_at}</Moment>
</p>
</div>
</div>
</div>
</div>
</div>
</Layout>
);
};
export default Article;
-
Restart your Gatsby server (you modified your
gatsby.node.js
file)
You should now be able to visit each one of your article now!
Category page
We need to do the exact same process as for the article page.
First of all, we need to generate all the necessary pages. We fetch all your category ids and then we create the pages
- Replace the content of your
gatsby.node.js
file with the following code:
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(
`
{
articles: allStrapiArticle {
edges {
node {
strapiId
slug
}
}
}
categories: allStrapiCategory {
edges {
node {
strapiId
slug
}
}
}
}
`
);
if (result.errors) {
throw result.errors;
}
// Create blog articles pages.
const articles = result.data.articles.edges;
const categories = result.data.categories.edges;
const ArticleTemplate = require.resolve("./src/templates/article.js");
articles.forEach((article, index) => {
createPage({
path: `/article/${article.node.slug}`,
component: ArticleTemplate,
context: {
slug: article.node.slug,
},
});
});
const CategoryTemplate = require.resolve("./src/templates/category.js");
categories.forEach((category, index) => {
createPage({
path: `/category/${category.node.slug}`,
component: CategoryTemplate,
context: {
slug: category.node.slug,
},
});
});
};
module.exports.onCreateNode = async ({ node, actions, createNodeId }) => {
const crypto = require(`crypto`);
if (node.internal.type === "StrapiArticle") {
const newNode = {
id: createNodeId(`StrapiArticleContent-${node.id}`),
parent: node.id,
children: [],
internal: {
content: node.content || " ",
type: "StrapiArticleContent",
mediaType: "text/markdown",
contentDigest: crypto
.createHash("md5")
.update(node.content || " ")
.digest("hex"),
},
};
actions.createNode(newNode);
actions.createParentChildLink({
parent: node,
child: newNode,
});
}
};
As you can see, we are doing the exact same thing as for articles.
- Create a
src/templates/category.js
file containing the following code:
import React from "react";
import { graphql } from "gatsby";
import ArticlesComponent from "../components/articles";
import Layout from "../components/layout";
export const query = graphql`
query Category($slug: String!) {
articles: allStrapiArticle(
filter: { status: { eq: "published" }, category: { slug: { eq: $slug } } }
) {
edges {
node {
slug
title
category {
name
}
image {
childImageSharp {
fixed(width: 660) {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
...GatsbyImageSharpFixed
}
}
}
}
}
}
}
category: strapiCategory(slug: { eq: $slug }) {
name
}
}
`;
const Category = ({ data }) => {
const articles = data.articles.edges;
const category = data.category.name;
const seo = {
metaTitle: category,
metaDescription: `All ${category} articles`,
};
return (
<Layout seo={seo}>
<div className="uk-section">
<div className="uk-container uk-container-large">
<h1>{category}</h1>
<ArticlesComponent articles={articles} />
</div>
</div>
</Layout>
);
};
export default Category;
You can see that we are using the ArticlesComponent
again! In fact we are displaying articles the same we as in the index.js
main file, this is why we created a component, in order to not duplicate code ;)
-
Restart your Gatsby server (you modified your
gatsby.node.js
file)
Awesome! You can list articles depending on the selected category now.
Conclusion
Huge congrats, you successfully achieved this tutorial. I hope you enjoyed it!
Still hungry?
Feel free to add additional features, adapt this project to your own needs, and give your feedback in the comment section below.
If you want to deploy your application, check our documentation.
Write for the community
Contribute and collaborate on educational content for the Strapi Community https://strapi.io/write-for-the-community
Can't wait to see your contribution!
One last thing, we are trying to make the best possible tutorials for you, help us in this mission by answering this short survey https://strapisolutions.typeform.com/to/bwXvhA?channel=xxxxx
Please note: Since we initially published this blog, we released new versions of Strapi and tutorials may be outdated. Sorry for the inconvenience if it's the case, and please help us by reporting it here.
Posted on February 15, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024