Im currently trying to implement SEO for a next.js and react webside, im using next-seo library for this. But i have the problem that when i share the link of the different sections i alway get the default title and description.
if i inspect the page, the title, description and openGraph options are been change, but at the moment of sharing the link of the page / pages or sharing on social media using the library next-share the default config is always taken. Im using getStaticProps() for most of the pages and getServerSideProps() for the my post section.
_app.tsx
const clientSideEmotionCache = createEmotionCache();
interface CustomAppProps extends AppProps {
emotionCache?: EmotionCache;
}
function ApinityApp({ Component, emotionCache = clientSideEmotionCache, pageProps }: CustomAppProps) {
return (
<>
<DefaultSeo {...SEO} />
<ApinityHomeUtilTracking containerId={process.env.NEXT_PUBLIC_PIWIK_ID}>
<HideAndSeek>
<MainMenuProvider>
<CacheProvider value={emotionCache}>
<Head>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
<ThemeProvider theme={theme}>
<SnackbarProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</SnackbarProvider>
</ThemeProvider>
</CacheProvider>
</MainMenuProvider>
</HideAndSeek>
</ApinityHomeUtilTracking>
</>
);
}
export default ApinityApp;
Default config
const SEO = {
title: 'API Business Operations SaaS platform | apinity.io',
description:
'Our SaaS platform for API Business Operations enables you to get the most business value from your APIs and make them part of your future API strategy.',
noindex: false,
openGraph: {
type: 'website',
locale: 'en_DE',
url: 'https://apinity.io/',
title: 'API Business Operations SaaS platform | apinity.io',
description:
'Our SaaS platform for API Business Operations enables you to get the most business value from your APIs and make them part of your future API strategy.',
images: [
{
url: 'https://apinity.io/images/logos/Apinity-logo-white-text.svg',
width: 139,
height: 35,
alt: 'apinity GmbH logo',
},
],
site_name: 'apinity GmbH',
},
twitter: {
handle: '#handle',
site: '#site',
cardType: 'summary_large_image',
},
};
export default SEO;
About page
export function AboutUs({ cmsData, menu }: { cmsData: StrapiMarketingAboutUs; menu: MainMenuItem[] }) {
const { aboutUsHome, ourTeamDetail, apinityLeaders, ourApinityStory, apinityOurAwards, apinityInvestor, apinityPartners, apinityScaleUp, getInTouch, seo } =
cmsData.marketingAboutUs.data.attributes;
const { setMenuItems } = useMainMenu();
setMenuItems(menu);
return (
<>
<NextSeo {...seoConfigAdapter(seo)} />
seoConfigAdapter
export const seoConfigAdapter = (seo) => {
if (!seo) {
return {};
}
const { metaTitle, metaDescription, metaRobots, canonicalURL, keywords, metaImage } = seo;
return {
title: metaTitle,
description: metaDescription,
canonical: canonicalURL,
noindex: false,
openGraph: {
type: 'website',
locale: 'en_IE',
url: window.location.href,
title: metaTitle,
description: metaDescription,
images: metaImage
? [
{
url: metaImage.data.attributes.url,
width: metaImage.data.attributes.width,
height: metaImage.data.attributes.height,
alt: metaImage.data.attributes.name,
},
]
: [],
},
additionalMetaTags: [
{
name: 'keywords',
content: keywords,
},
{
name: 'googlebot',
content: metaRobots,
},
],
};
};
Related
I'm trying to create a Figure component in which I pass the img src along with other data.
I realize it's not straightforward—e.g., this thread—but I thought it would work fine with normal HTML img tags.
The image is not displaying. Does that mean that this limitation also applies to HTML img tags within components?
If this is the case, I guess I indeed ought to use Gatsby's dynamic images. How would I do this in a static query (nonpage component)? This thread had me believing it isn't possible—or at least a hack?
The component inside MDX documents:
<Figure
image=""
size=""
caption=""
credits=""
/>
Figure.js:
import * as React from "react"
const Figure = ({ image, size, caption, credits }) => {
return (
<figure className={size}>
<img src={image} alt={caption} />
<figcaption>
<span>{caption}</span>
<span>{credits}</span>
</figcaption>
</figure>
)
}
export default Figure
articlePostTemplate.js
import * as React from "react"
import { graphql } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import Layout from "../components/layout.js"
import Seo from "../components/seo.js"
const PostTemplate = ({ data, location }) => {
let post = data.mdx
return (
<Layout location={location}>
<Seo
title={post.frontmatter.title}
description={post.frontmatter.lead}
date={post.frontmatter.computerDate}
/>
<article className="post">
<header className="post" id="intro">
<p className="date">
<time dateTime={post.frontmatter.computerDate}>{post.frontmatter.humanDate}</time>
</p>
<h1 itemprop="headline">{post.frontmatter.title}</h1>
<p className="lead">{post.frontmatter.lead}</p>
</header>
<section className="post" id="body-text">
<MDXRenderer data={data}>{post.body}</MDXRenderer>
</section>
</article>
</Layout>
)
}
export default PostTemplate
export const pageQuery = graphql`
query PostBySlug(
$id: String!
) {
site {
siteMetadata {
title
}
}
mdx(id: { eq: $id }) {
id
excerpt(pruneLength: 160)
body
frontmatter {
title
computerDate: date(formatString: "YYYY-MM-DD")
humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
hook
type
lead
featuredImage {
childImageSharp {
fluid(maxWidth: 800) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
gatsby-config.js
module.exports = {
…
},
plugins: [
`gatsby-plugin-image`,
`gatsby-plugin-sitemap`,
{
resolve: `gatsby-plugin-mdx`,
options: {
extensions: [`.md`, `.mdx`],
gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: `900000000000`,
linkImagesToOriginal: false,
backgroundColor: `none`,
},
},
{
resolve: `gatsby-remark-responsive-iframe`,
options: {
wrapperStyle: `margin-bottom: 1.07var(--line-length)`,
},
},
`gatsby-remark-prismjs`,
`gatsby-remark-copy-linked-files`,
`gatsby-remark-smartypants`,
{
resolve: `gatsby-remark-autolink-headers`,
options: {
icon: false,
itemprop: `heading`,
maintainCase: false,
removeAccents: true,
elements: [`h2`, `h3`, `h4`],
},
}
],
},
},
…
{
resolve: `gatsby-source-filesystem`,
options: {
name: `content`,
path: `${__dirname}/content/`,
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/data`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/images`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/pages/`,
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `journalistikk`,
path: `${__dirname}/content/journalism/`,
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `discussion`,
path: `${__dirname}/content/discussion/`,
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `photography`,
path: `${__dirname}/content/photography/`,
}
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `Gatsby Starter Blog`,
short_name: `GatsbyJS`,
start_url: `/`,
background_color: `#ffffff`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`,
},
},
`gatsby-plugin-react-helmet`,
],
}
gatsby-node.js
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const articlePostTemplate = path.resolve(`./src/templates/articlePostTemplate.js`)
const result = await graphql(
`
{
allMdx(
sort: { fields: [frontmatter___date], order: ASC }
limit: 1000
) {
nodes {
id
frontmatter {
title
computerDate: date(formatString: "YYYY-MM-DD")
humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
}
fields {
slug
}
}
}
}
`
)
if (result.errors) {
reporter.panicOnBuild(
`There was an error loading your blog posts`,
result.errors
)
return
}
const posts = result.data.allMdx.nodes
if (posts.length > 0) {
posts.forEach((post, index) => {
[index + 1].id
createPage({
path: post.fields.slug,
component: articlePostTemplate,
context: {
id: post.id
},
})
})
}
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `Mdx`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
createTypes(`
type SiteSiteMetadata {
author: Author
siteUrl: String
social: Social
}
type Author {
name: String
summary: String
}
type Social {
twitter: String
instagram: String
mail: String
}
type MarkdownRemark implements Node {
frontmatter: Frontmatter
fields: Fields
}
type Frontmatter {
title: String
description: String
date: Date #dateformat
}
type Fields {
slug: String
}
`)
}
layout.js
import * as React from "react"
import { MDXProvider } from "#mdx-js/react"
import { Link } from "gatsby"
import DWChart from "react-datawrapper-chart"
import Header from "./Header"
import Footer from "./Footer"
import Figure from "./Figure"
const shortcodes = { Link, DWChart, Figure }
export default function Layout({ children }) {
return (
<div className="layout-wrapper">
<Header />
<main>
<MDXProvider components={shortcodes}>{children}</MDXProvider>
</main>
<Footer />
</div>
)
}
The limitation you mention in How to pass a path of image as a prop in Gatsby in Gatsby-plugin-image only applies to StaticImage + dynamic props data (with a dynamic source), meaning that the component that returns a StaticImage cannot receive the src as a props, because all the props of StaticImage needs to be statically analyzed.
In other words, your MDX can receive a src to be used in a <img> tag or you can use GatsbyImage component if properly configured.
Keep in mind that the query that will fetch GatsbyImage data (childImageSharp, gatsbyImageData, etc) must be placed in a top-level component (pages) if using a page query or in a useStaticQuery hook if used elsewhere.
The approach in both scenarios (using <img> or GatsbyImage) is similar. You need to:
Provide your image sources in your markdown file
Query those images using a page query or useStaticQuery to provide to your MDXProvider the queried image props. Using the blog example:
<MDXProvider>
<MDXRenderer data={data}/>
</MDXProvider>
data stands for your queried data in a GraphQL page query or useStaticQuery. Without knowing your data structure I haven't add the GraphQL part because I do not know the nodes available.
At this point, your MDXProvider holds the images data (all from your markdown files), you just need to provide it to your GatsbyImage or Figure component:
// some.mdx
import Figure from 'path/to/figure/component';
## Post Body
Lorem ipsum dolor...
<Figure img={props.data} />
As you can see, I lift all props to Figure just to allow to debug (using console.logs() for example) to see the available props there like:
const Figure = (props) => {
console.log(props);
return (
<div>I will be a figure in a future</div>
)
}
export default Figure
In that way, you will be able to pass to Figure something like img={props.someNode.frontmatter.imageNodeSource}.
Again, without knowing your data structure is like a pie in the sky but get the idea.
Hat tip to Ferran for helpful guidance.
After more research, I revised my solution—
articleTemplate.js
/* shortcodes */
const ArticleTemplate = ({ data, location }) => {
let post = data.mdx
return (
<Layout location={location}>
<Seo
title={post.frontmatter.title}
description={post.frontmatter.lead}
date={post.frontmatter.computerDate}
/>
<article className="article">
<p className="date">
<time dateTime={post.frontmatter.computerDate}>{post.frontmatter.humanDate}</time>
</p>
<h1 itemprop="headline">{post.frontmatter.title}</h1>
<p className="lead" itemprop="introduction">{post.frontmatter.lead}</p>
<MDXProvider components={shortcodes}>
<MDXRenderer
data={post.frontmatter.thumbnail}
localImages={post.frontmatter.embeddedImagesLocal}
>
{post.body}
</MDXRenderer>
</MDXProvider>
</article>
</Layout>
)
}
export default ArticleTemplate
export const pageQuery = graphql`
query ArticleBySlug($id: String!) {
site {
siteMetadata {
title
}
}
mdx(id: {eq: $id}) {
id
excerpt(pruneLength: 160)
body
frontmatter {
title
computerDate: date(formatString: "YYYY-MM-DD")
humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
hook
type
lead
thumbnail {
childImageSharp {
gatsbyImageData(
layout: FULL_WIDTH
)
}
}
embeddedImagesLocal {
childImageSharp {
gatsbyImageData
}
}
}
}
}
`
figure.js
import * as React from "react"
import { GatsbyImage, getImage } from 'gatsby-plugin-image'
const Figure = ({ source, size, caption, credit }) => {
return (
<figure className={size}>
<GatsbyImage image={getImage(source)} alt={caption} />
<figcaption>
<span>{caption}</span>
<span>{credit}</span>
</figcaption>
</figure>
);
}
export default Figure
index.mdx
---
…
thumbnail: "thumb.jpeg"
embeddedImagesLocal:
- "first.jpeg"
- "second.jpeg"
---
<Figure
source={(props.localImages [0])} <!-- first image; second image would be `[1]` -->
size="I'm a `className`"
caption="I'm a caption"
photographer="I'm a name."
/>
(Marking this as the solution as it's the most helpful for anyone looking to do this in the future. It also shows how to query for embedded images and featured images—at the same time.)
Can someone please advise how can i hide a tab from display in Bottom Navigation, i want to jumpTo the tab from code but i don't want it show in the Bottom Navigation. Below is some code i am using, i just want to hide the vehicle_edit tab from bottom but i want to keep using it in my code via jumpTo,
please if someone can advise.
//routes
const [routes] = React.useState([
{ key: "dashboard", title: "Dashboard", icon: "home" },
{ key: "notifications", title: "Notifications", icon: "bell" },
{ key: "account", title: "My Account", icon: "account" },
{ key: "vehicle_edit", title: "Vehicles", icon: "car" },
{ key: "appointments", title: "Appointments", icon: "calendar" },
]);
//set bottom tab to first always
useEffect(() => {
setIndex(0);
}, []);
//screens
const renderScene = BottomNavigation.SceneMap({
dashboard: DashboardScreen,
notifications: NotificationsScreen,
account: AccountScreen,
vehicle_edit: VehicleEditScreen,
appointments: AppointmentsScreen,
});
//render
return <BottomNavigation navigationState={{ index, routes }} onIndexChange={setIndex} renderScene={renderScene} />;
react-native-paper Bottom Navigation component design for only for Bottom navigation screen.
You need stack navigation for vehicle_edit. You can simply achieve this by using React navigation stack navigator
Brilliant thanks that solved it..
const Stack = createStackNavigator();
const Account = () => {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Account" component={AccountScreen} />
<Stack.Screen name="VehicleEdit" component={VehicleEditScreen} />
</Stack.Navigator>
);
};
//screens
const renderScene = BottomNavigation.SceneMap({
dashboard: DashboardScreen,
notifications: NotificationsScreen,
account: Account,
appointments: AppointmentsScreen,
});
I am trying to build a HULU Clone
I have build header successfully and
I am Building a results section where user can see images of movie but when I load images it just does not load Images
Technology I am Using
React.Js
Next.js
Tailwind css
TMDB Api
The Error Says - Failed to load resource: the server responded with a status of 404 ()
I assume its an error due to poor request to the TMDB Api
Here is My request.js
const API_KEY = process.env.API_KEY;
export default {
fetchTrending: {
title: "Trending",
url: `/trending/all/week?api_key=${API_KEY}&language=en-US`,
},
fetchTopRated: {
title: "Top Rated",
url: `/movie/top_rated?api_key=${API_KEY}&language=en-US`,
},
fetchActionMovies: {
title: "Action",
url: `/discover/movie?api_key=${API_KEY}&with_genres=28`,
},
fetchComedyMovies: {
title: "Comedy",
url: `/discover/movie?api_key=${API_KEY}&with_genres=35`,
},
fetchHorrorMovies: {
title: "Horror",
url: `/discover/movie?api_key=${API_KEY}&with_genres=27`,
},
fetchRomanceMovies: {
title: "Romance",
url: `/discover/movie?api_key=${API_KEY}&with_genres=10749`,
},
fetchMystery: {
title: "Mystery",
url: `/discover/movie?api_key=${API_KEY}&with_genres=9648`,
},
fetchSciFi: {
title: "Sci Fi",
url: `/discover/movie?api_key=${API_KEY}&with_genres=878`,
},
fetchWestern: {
title: "Western",
url: `/discover/movie?api_key=${API_KEY}&with_genres=37`,
},
fetchAnimation: {
title: "Animation",
url: `/discover/movie?api_key=${API_KEY}&with_genres=16`,
},
fetchTV: {
title: "TV Movie",
url: `/discover/movie?api_key=${API_KEY}&with_genres=10770`,
},
};
And Here is My index.js
import Head from "next/head";
import Header from "../components/Header";
import Nav from "../components/Nav";
import Results from "../components/Results";
import request from "../utils/request";
export default function Home({ results }) {
return (
<div>
<Head>
<title>HULU</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Header />
<Nav />
<Results results={results} />
</div>
);
}
export async function getServerSideProps(context) {
const genre = context.query.genre;
const requests = await fetch(
`https://api.themoviedb.org/3${
request[genre]?.url || request.fetchTrending.url
}`
).then((res) => res.json());
return {
props: {
results: requests.results,
},
};
}
and This is where I Load Images in Thumbnail.js
import React from "react";
import Image from "next/image";
function Thumbnail({ result }) {
const BASE_URL = "https://image.tmdb.org/t/p/orignal";
console.log(result);
return (
<div>
<Image
layout="responsive"
src={
`${BASE_URL}${result.backdrop_path || result.poster_path}` ||
` ${BASE_URL}${result.poster_path}`
}
height={1080}
width={1920}
/>
</div>
);
}
export default Thumbnail;
this is what results console logs in Thumbnail.js
Result Console Log
Error Shown in Console
Please Tell Me If You Need Any Further Information
Thank You in Advance
The URL that is throwing the error points to http://localhost:3000 instead of the IMBD URL that you have.
Ensure that your proxy is not prepending http://localhost:3000 to all HTTP requests
Also ensure that you are not using relative URLS as that will cause http://localhost:3000 to be prepended to the HTTP request.
I have faced same issue. Then solve by changing few code in next.config.js
file like below
module.exports = {
images: {
domains:['image.tmdb.org'],
},
}
instead of module.exports =nextConfig
I am trying to fetch data from Storyblok API, but in getStaticProps I get the data from the storybook but it can't return data to the page.
pages/docs/[slug].js
import React from 'react'
import Storyblok from "../../lib/storyblok"
export default function DocsArticle( props ) {
console.log("PROPS: ", props)
return (
<>
<div className="page">
{props.story.name}
</div>
</>
);
}
export async function getStaticProps({ params, preview = false }) {
let slug = params.slug ? params.slug : "home";
let sbParams = {
version: "draft", // or 'published' / ' draft
};
if (preview) {
sbParams.version = "draft";
sbParams.cv = Date.now();
}
// load the stories insides the pages folder
let { data } = await Storyblok.get(`cdn/stories/${slug}`, sbParams);
console.log("STORY DATA:", data);
return {
props: {
story: data ? data.story : null,
preview,
},
revalidate: 10, // revalidate every hour
};
}
export async function getStaticPaths() {
let { data } = await Storyblok.get('cdn/links/', {
starts_with: 'article'
})
let paths = [];
Object.keys(data.links).forEach((linkKey) => {
// don't create routes for folders and the index page
if (data.links[linkKey].is_folder || data.links[linkKey].slug === "home") {
return;
}
// get array for slug because of catch all
const slug = data.links[linkKey].slug;
// remove the pages part from the slug
let newSlug = slug.replace('docs', '')
let splittedSlug = newSlug.split("/");
paths.push({ params: { slug: splittedSlug.toString() } });
});
return {
paths: paths,
fallback: false,
};
}
pages/_app.js
...
export default withRedux(initStore)(
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
return {
pageProps: Component.getInitialProps
? await Component.getInitialProps(ctx)
: {},
}
}
render() {
const { Component, pageProps, store } = this.props
return (
<>
<DefaultSeo
title="My page"
description="My test page"
openGraph={{
type: 'website',
locale: 'en_IE',
}}
/>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
</Head>
<Provider store={store}>
<ThemeProvider theme={theme}>
<GetCurrentUser />
<Component {...pageProps} />
</ThemeProvider>
</Provider>
</>
);
}
}
)
If I display the data using console.log(), I get the data, but it doesn't return it.
STORY DATA: {
story: {
name: 'article1',
created_at: '2021-08-13T00:36:04.648Z',
published_at: '2021-08-15T16:24:54.810Z',
id: 66059334,
uuid: '900a311a-2ad4-461c-9304-e2f36fd25b07',
content: {
_uid: 'd21214b5-1e80-4c6a-aa74-259f082a8242',
content: [Array],
component: 'page',
_editable: '<!--#storyblok#{"name": "page", "space": "122749", "uid": "d21214b5-1e80-4c6a-aa74-259f082a8242", "id": "66059334"}-->'
},
slug: 'article1',
full_slug: 'article1',
sort_by_date: null,
position: 10,
tag_list: [],
is_startpage: false,
parent_id: 0,
meta_data: null,
group_id: 'bdf123cc-0044-4d02-b4b3-28034ee457d0',
first_published_at: '2021-08-14T00:02:05.000Z',
release_id: null,
lang: 'default',
path: 'docs',
alternates: [],
default_full_slug: null,
translated_slugs: null
},
cv: 1629044699,
rels: [],
links: []
}
PROPS: {}
TypeError: Cannot read property 'title' of undefined
I'd appreciate it if you could let me know what I did wrong.
I created an SEO component, but for some reason when I run my site through lighthouse or an SEO checker it says I'm missing a meta description.
Here is my SEO component
import React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"
function SEO({ description, title, keywords, siteUrl, lang, meta }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
description
keywords
title
siteUrl
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
const defaultTitle = site.siteMetadata.title
const metaUrl = siteUrl || site.siteMetadata.siteUrl
const metaKeywords = keywords || site.siteMetadata.keywords
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
meta={[
{
property: `og:title`,
content: title,
},
{
property: `og:siteurl`,
content: metaUrl,
},
{
name: `keywords`,
content: metaKeywords,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
].concat(meta)}
/>
)
}
SEO.defaultProps = {
lang: `en`,
meta: [],
description: ``,
}
SEO.propTypes = {
description: PropTypes.string,
lang: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
}
export default SEO
When I inspect my site, it shows
<meta data-react-helmet="true" property="og:description" content="My coding blog about tech
and design.">
So I'm not sure what I need to add or change for my SEO component because my current method of showing the description isn't working apparently based off lighthouse or the other SEO website checkers.
Just change the og:description to description (standalone):
{
property: `description`,
content: metaDescription,
},
og attributes stands for Open Graph. They are mostly used for social networks to get information when a web is shared, you can customize the description for those social networks instead of taking the description of the page itself. If you don't care about that, change it to description, if you do, keep both meta tags:
{
property: `og:description`,
content: anoterOgMetaDescription,
},
{
property: `description`,
content: metaDescription,
},