I'm developing my website with Next.js To upgrade my website's SEO performance, I'm trying to avoid duplicated meta tags.
My Question
In Next official docs, they say that I can avoid overlapped meta tag by insert key property in meta tag. But this does not work.
<meta name="description" content="~~" key="titleDescription"/>
<meta name="keywords" content="~~" key="titleKeywords"/>
These are default rootDocument meta tags and,
<meta name="description" content={item.product_description} key="titleDescription"></meta>
<meta name="keywords" content={item.brand_name} key="titleKeywords"></meta>
These are dynamically generated meta tags in item pages.
In deployed browser, there are still two description and keywords meta tags in website. I want to avoid duplicated meta tag. Thank you for your help!
There are a few things to watch for when using Next.js Head components.
The _document Head component is next/document
Tags in _document will not be replaced (can be duplicated) even with a key identifier
The _app Head component is next/head
Tags in _app can be in child components
Tags in _app can be overridden with the key identifier
Tags in pages cannot be in child components
Tags in pages can override tags with the same key identifier.
Examples
_document.{js|jsx|ts|tsx}
Scripts, styles, and other tags you need access to immediately - Next will likely not be fully mounted at this point. You cannot replace tags in the document/head component with the key attribute.
import Document, {Head, Html, Main, NextScript } from 'next/document';
class MyDocument extends Document {
render = () => (
<Html lang="en-US" dir="ltr">
<Head>
<script src="/some-script.js" defer={false} />
<style>.inline-styles{}</style>
{/* META & TITLE TAGS PLACED HERE CANNOT BE OVERRODE */}
</Head>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
OR self-closing Head tag
class MyDocument extends Document {
render = () => (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
Note: import is from next/document
_app.{js|jsx|ts|tsx}
import Head from 'next/head';
const App = ({ Component, pageProps }) => (
<>
<Head>
<title key="title">App Tittle</title>
</Head>
<Component {...pageProps} />
</>
);
OR load from a custom component
import Head from 'next/head';
const MyHeadTags = () => (
<Head>
<title key="title">App Tittle</title>
<meta key="description" name="description">Description</meta>
</Head>
);
const App = ({ Component, pageProps }) => (
<>
<MyHeadTags />
<Component {...pageProps} />
</>
);
Note: import is from next/head
some_page.{js|jsx|ts|tsx}
const SomePage = () => (
<>
<Head>
<title key="title">Some Page Tittle</title>
<meta key="description" name="description">Some Page Description</meta>
</Head>
<div>My Page</div>
</>
);
NOT ALLOWED
The head component must be on the page and cannot be a child component. If it's a child component, it sometimes will not override other tags with the same key property.
some_page.{js|jsx|ts|tsx}
const MyHeadTags = () => (
<Head>
<title key="title">Some Page</title>
<meta key="description" name="description">Some Page Description</meta>
</Head>
);
const ChildComponent = () => (
<>
<MyHeadTags />
Info.
</>
);
const SomePage= () => (
<>
<ChildComponent />
<div>Will not work</div>
</>
);
Update: The last example seems to work in some cases with Next 11+, but I have run into a few instances where it duplicates tags. I avoid the last method.
UPDATE
Here's what Next.js docs say regarding the <Head /> element within the _document.js file:
The component used here is not the same one from next/head.
The component used here should only be used for any
code that is common for all pages. For all other cases, such as
<title> tags, we recommend using next/head in your pages or
components.
Source: https://nextjs.org/docs/advanced-features/custom-document
Therefore, Next.js recommends that all the dynamic <meta /> tags should only be defined on an individual page level.
ORIGINAL ANSWEAR (it seemed to work at first, but as it turns out, only at random).
This issue seems to appear when you mix up two ways of closing empty HTML tags in JSX. Notice that your meta tags in the _document.js file are self-closing: <meta /> and the dynamic ones are not: <meta></meta>.
Ensure you are consistent with it (i.e. according to best practices you should convert all empty tags to the self-closing variant) and you should be fine.
I believe you can take a look at this package that helps managing meta tags https://github.com/garmeeh/next-seo in Next.js project. It helped me :D
For your question, yea try putting the Head in the _app instead of _document. _document is like non mutated one.. it will be always in the website. Cheers 🥂
I use Next 12.
Thanks to Sean's comment here, I was able to progress.
I personally update the tags for SEO purpose according to the consulted page with a component Seo that I crafted.
But to prevent importing it in every pages, I wanted to import it once. It happened that importing this Seo component in pages/_app.js was eventually just duplicating the tags and especially breaking my social media links.
So here is my code.
First the Seo component:
import Head from 'next/head'
import {SEO} from '#/Constants/seo'
const titlePrepend = 'WeekandGO | '
const Seo = ({ seo }) => {
const currentUrl = typeof window !== 'undefined' && window.location.href
const defaultSeo = {...SEO['index']}
let seoWithDefaults = {...defaultSeo}
if (seo) {
seoWithDefaults = {
...seoWithDefaults,
...seo,
}
}
const fullSeo = {
...seoWithDefaults,
metaTitle: seoWithDefaults?.metaTitle ? `${titlePrepend}${seoWithDefaults.metaTitle}` : `${titlePrepend}${defaultSeo.metaTitle}`,
shareImage: seoWithDefaults?.shareImage || defaultSeo.shareImage,
metaDescription: seoWithDefaults?.metaDescription || defaultSeo.metaDescription,
}
return <Head>
<title>{fullSeo.metaTitle}</title>
<meta name="Author" lang="fr" content="Leb Communication"/>
<meta name="Identifier-URL" content="www.weekandgo.com"/>
<meta name="Reply-to" content=""/>
<meta name="revisit-after" content="7"/>
<meta name="Publisher" content="WeekandGO"/>
<meta name="Copyright" content="WeekandGO"/>
<link rel="canonical" href="https://www.weekandgo.com/" />
<meta name="keywords" content={fullSeo.metaKeywords} />
<meta name="description" content={fullSeo.metaDescription} />
<meta name="image" content={fullSeo.shareImage} />
<meta property="og:site_name" content="WeekandGO" />
<meta property="og:url" content={currentUrl || 'https://www.weekandgo.com/'} />
<meta property="og:type" content="website" />
<meta property="og:image" content={fullSeo.shareImage} />
<meta property="og:title" content={fullSeo.metaTitle} />
<meta property="og:description" content={fullSeo.metaDescription} />
<meta name="twitter:title" content={fullSeo.metaTitle} />
<meta name="twitter:description" content={fullSeo.metaDescription} />
<meta name="twitter:image" content={fullSeo.shareImage} />
</Head>
}
export default Seo
I use it in pages/_document.js:
class MyDocument extends Document {
render() {
return (
<Html lang="fr">
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap&subset=latin-ext" rel="stylesheet" />
<link rel="stylesheet" href="https://use.typekit.net/uah4cdm.css" />
<link rel="manifest" href="/manifest.json" />
<script src="https://maps.googleapis.com/maps/api/js?key=<key>" type="text/javascript"/>
</Head>
<Seo/>
<body className={ !isMobile && 'u-hover-on'}>
<Main />
<NextScript />
</body>
</Html>
)
}
}
Then I import this component in pages/_document.js as so:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { isMobile } from 'react-device-detect'
import Seo from '#/Shared/Seo'
class MyDocument extends Document {
render() {
return (
<Html lang="fr">
<Head>
<link rel="icon" href="/favicon.ico" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap&subset=latin-ext" rel="stylesheet" />
<link rel="stylesheet" href="https://use.typekit.net/uah4cdm.css" />
<link rel="manifest" href="/manifest.json" />
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDiB40c-5x-GAEBw3mIJXPTvamFHUV536I" type="text/javascript"/>
</Head>
<Seo/>
<body className={ !isMobile && 'u-hover-on'}>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Then, let me spare you some lines to just look at the return of my functional component App in pages/_app.js. There is no import of Seo component, only a ** Head coming from 'next/head' ** is used :
...
return (<SessionProvider session={session}>
<TokensRefresher/>
<Head>
<meta charSet="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<GlobalContextProvider appProps={{ global, categoryAnnexes, categoriesInfos }}>
<GlobalLayout error={error}>
<Component {...rest} />
</GlobalLayout>
</GlobalContextProvider>
</SessionProvider>)
}
...
And finally, here is a page I receive data from server side props and that I want to use to change the meta tags related to seo. Here again I don't show the part of the code that are useless for the matter :
...
const Annonce = ({ ad, ...pageProps }) => {
return <>
<Seo seo={{metaTitle: ad?.slug, metaDescription: ad?.dealerWord, shareImage: ad?.firstImage?.fileUrl}} />
<AnnonceLayout ad={ad} {...pageProps} />
</>
}
...
The result I have in the source code is there is no duplicated meta tags and I can share my links on social medias with no image, description or page tilte overlaps
Related
import React from "react";
import { Helmet } from "react-helmet";
const HotelHelmet = ({
title,
address,
images,
websiteSlug,
city,
state,
descriptions,
keywords,
}) => {
return (
<Helmet>
<title>{title}</title>
<meta name="description" content={descriptions} />
<meta name="keywords" content={keywords} />
<meta property="og:title" content={title} />
<meta property="og:image" content={images[0]?.cdnImageUrl} />
<meta property="og:description" content={descriptions} />
<link rel="preload" as="image" href={images[0]?.cdnImageUrl} />
</Helmet>
);
};
export default HotelHelmet;
I'm getting all the data dynamically from DB but I'm not able to see the link preview with updated values while sharing the values in social media. Instead the default values set is being displayed but I want to display the updated values in the preview.
Thank you.
I'm stuck on this problem, I am using next js and have 5 pages.
pages/index.js
pages/kandan-nagar.js
pages/vallimanavalan-nagar.js
pages/contact-us.js
pages/404-not-found.js
My Pages Here
Then I upload my next js static files to godaddy hosting.My application ran successfully. But, I route vallimanavalan-nagar and reload this page is to redirect index page(Home Page).
Example video is error.
My _app.js File
import SSRProvider from 'react-bootstrap/SSRProvider'
import Head from 'next/head'
import ScrollTopButton from '../components/ScrollTopButton'
import '../scss/theme.scss'
import Script from 'next/script'
const FlatLand = ({ Component, pageProps }) => {
return (
<SSRProvider>
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>FlatLand Realty</title>
<meta name='description' content='FlatLand - Directory & Listings React / Next.js Bootstrap Template' />
<meta name='keywords' content='react, nextjs, bootstrap, business, directory, listings, e-commerce, car dealer, city guide, real estate, job board, user account, multipurpose, ui kit, css3, javascript, gallery, slider, touch' />
<meta name='author' content='Createx Studio' />
<link rel='apple-touch-icon' sizes='180x180' href='/favicon/apple-touch-icon.png' />
<link rel='icon' type='image/png' sizes='32x32' href='/Share/flatlandlogo.svg' />
<link rel='manifest' href='/favicon/site.webmanifest' />
<link rel='mask-icon' color='#5bbad5' href='/favicon/safari-pinned-tab.svg' />
<meta name='msapplication-TileColor' content='#766df4' />
<meta name='theme-color' content='#ffffff' />
</Head>
<Component {...pageProps} />
<ScrollTopButton
showOffset={600}
duration={800}
easing='easeInOutQuart'
tooltip='Top'
/>
</SSRProvider>
)
}
export default FlatLand
I'm trying to render MathML into the DOM. But it's not displaying correctly as shown in the Editor.
I'm using CKEditor4
Let me just add the code below so you can understand what I have tried
App.js file:
import React from "react";
import CKEditor from "ckeditor4-react";
class App extends React.Component {
constructor() {
super();
this.state = {
data: "",
};
CKEditor.editorUrl =
"https://cdn.ckeditor.com/4.16.0/standard-all/ckeditor.js";
}
onEditorChange = (evt) => {
this.setState({
data: evt.editor.getData(),
});
};
render() {
return (
<div className="App">
<CKEditor
data={this.state.data}
onChange={this.onEditorChange}
config={{
extraPlugins: "ckeditor_wiris",
removePlugins:
"filetools,uploadimage,uploadwidget,uploadfile,filebrowser,easyimage",
allowedContent: true,
}}
onBeforeLoad={(CKEDITOR) => {
CKEDITOR.plugins.addExternal(
"ckeditor_wiris",
"/mathtype-ckeditor4/",
"plugin.js"
);
}}
/>
<div className="editor-preview">
<h2>Rendered content</h2>
<div
dangerouslySetInnerHTML={{ __html: this.state.data }}
></div>
<p>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mi>x</mi>
<mo>=</mo>
<mfrac>
<mrow>
<mo>-</mo>
<mi>b</mi>
<mo>±</mo>
<msqrt>
<msup>
<mi>b</mi>
<mn>2</mn>
</msup>
<mo>-</mo>
<mn>4</mn>
<mi>a</mi>
<mi>c</mi>
</msqrt>
</mrow>
<mrow>
<mn>2</mn>
<mi>a</mi>
</mrow>
</mfrac>
</math>
</p>
</div>
</div>
);
}
}
export default App;
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
<!-- MathJax library to render MathML in HTML -->
<script
type="text/javascript"
async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
Since Chrome doesn't support MathML, I have added MathJax library in the header section
The MathJax library works fine if I paste the MathML directly into the html. But the MathML generated from CKEditor is not displaying correctly.
Please check the below image.
Result preview
Expected result:
Render the formula exactly like the editor
Actual result:
Content generated from editor are not rendering properly. But pasting the mathml directly into the HTML are rendering properly as expected.
Here is the Sandbox link as requested...
Sandbox link
Thank you for your help in advance
If you are using just a JS frontend without plugin services, you might
link WIRISplugins.js directly from our servers, like so:
No need MathJax library. Add this script to your head:
<script src="https://www.wiris.net/demo/plugins/app/WIRISplugins.js?viewer=image"></script>
refer to this:
https://docs.wiris.com/en/mathtype/integrations/html/ckeditor
I am trying to share images and video on social media ( mostly FB,twitter,linkedIn )in reactjs app , have added react-helmet for the same but still unable to share image below is the link which i am referring and my code.
https://medium.com/camperstribe/react-social-media-integration-with-react-share-and-react-helmet-84d9def6a445
Above solution is not working
import React from "react";
import { Helmet } from "react-helmet";
// import { useLocation } from "react-router-dom";
export default function HelmetMetaData(props) {
// let location = useLocation();
let quote = props.quote !== undefined ? props.quote : "";
let title =
props.title !== undefined
? props.title
: "CampersTribe - World is yours to explore";
let image =
props.image !== undefined
? props.image
: "https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80";
let description =
props.description !== undefined
? props.description
: "CampersTribe lets you experience the camping culture. We discover the hidden gems in the nearby to help you connect with nature & yourself by learning in the woods, on the riverbank under the open sky." +
"Trust us, its million dollars experience to ride away from city life, pitch a tent, do campfire and endless talk!" +
"So, join us on this voyage, and explore the beauty and miracle of being yourself!";
let hashtag = props.hashtag !== undefined ? props.hashtag : "#camperstribe";
return (
<Helmet>
<title>{title}</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="csrf_token" content="" />
<meta property="type" content="website" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
<meta name="theme-color" content="#ffffff" />
<meta name="_token" content="" />
<meta name="robots" content="noodp" />
<meta property="title" content={title} data-react-helmet="true"/>
<meta property="quote" content={quote} data-react-helmet="true"/>
<meta name="description" content={description} data-react-helmet="true"/>
<meta property="image" content={image} data-react-helmet="true"/>
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:quote" content={quote} />
<meta property="og:hashtag" content={hashtag} />
<meta property="og:image" content={image} data-react-helmet="true"/>
<meta property="og:image:secure_url" content={image} data-react-helmet="true"/>
<meta content="image/*" property="og:image:type" data-react-helmet="true"/>
<meta property="og:site_name" content="CampersTribe" />
<meta property="og:description" content={description} />{" "}
</Helmet>
);
}
i have created helmetMetaData component and calling in top of my social share component
return (
<div className="app-content content">
<HelmetMetaData />
<FacebookShareButton
windowWidth="800"
windowHeight="500"
url={
"https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80"
}
quote={"test sharing"}
image={
"https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80"
}
imageURL={
"https://images.unsplash.com/photo-1576091160550-2173dba999ef?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80"
}
// hashtag="#camperstribe"
// className={classes.socialMediaButton}
>
<FacebookIcon size={36} />
</FacebookShareButton>
)
but not working only getting url and title on facebook share dialog,
anybody knows how to share image on social media in reactjs?
I know it's an old question, but try to insert image meta tag directly into public/index.html. As it said in this issue: adding meta on client side dynamically does not work. Crawlers (fb, tw, etc) can see only static html. And it seems like FacebookShareButton doesn't have image as an optional prop.
I am actually using the pages/_document.js hook to add Bootstrap and jQuery to my pages, by the way I set the <Head>
export default class MyDocument extends Document {
render() {
return (
<html>
<Head>
<title>Default title</title>
<link rel="stylesheet" href="/static/lib/bootstrap3/css/bootstrap.min.css" />
</Head>
<body>
<Main/>
<NextScript/>
<script src="/static/lib/jquery3/jquery-3.3.1.min.js" />
<script src="/static/lib/bootstrap3/js/bootstrap.min.js" />
</body>
</html>
)
}
}
Now I would like to set a different Title,for my pages. Is it possible to used <Head> outside of Document ? I mean in <div> like this:
const ContactPage = () => {
return (
<div>
<Head>
<title>You better contact us!</title>
</Head>
<div className="page-body">...</div>
</div>
)
}
And if possible, will it overwrite or merge what is already set in pages/_document.js ?
You want to use the next/head component:
import Head from 'next/head'
export default () =>
<div>
<Head>
<title>My page title</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<p>Hello world!</p>
</div>
See the docs: https://nextjs.org/docs/api-reference/next/head