Add more structured metadata

This commit is contained in:
Kevin Kandlbinder 2021-09-25 14:00:50 +02:00
parent df9e2b2bb8
commit 412ee72112
10 changed files with 148 additions and 5 deletions

View file

@ -2,9 +2,11 @@ import React from "react";
import PropTypes from "prop-types";
import { Helmet } from "gatsby-plugin-react-i18next";
import { useStaticQuery, graphql } from "gatsby";
import { useLocation } from "@reach/router"
import { useTranslation } from "gatsby-plugin-react-i18next";
import useSiteMetadata from "../helpers/useSiteMetadata";
function SEO({ description, meta, title }) {
function SEO({ description, meta, title, speakable, image, children }) {
const { t } = useTranslation();
const { site } = useStaticQuery(
graphql`
@ -22,6 +24,10 @@ function SEO({ description, meta, title }) {
const metaDescription = description || t("siteDescription");
const siteMeta = useSiteMetadata();
const location = useLocation();
return (
<Helmet
title={title}
@ -79,6 +85,45 @@ function SEO({ description, meta, title }) {
data-domain="kevink.dev"
src="https://analytics.kevink.dev/js/plausible.js"
></script>
{
image && [
<meta name="twitter:image" content={meta.siteUrl + image} key="twimg"/>,
<meta name="og:image" content={meta.siteUrl + image} key="ogimg"/>,
]
}
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org/",
"@type": "WebPage",
"name": title,
"url": siteMeta.siteUrl+location.pathname,
"speakable": speakable,
"image": meta.siteUrl + image,
"about": {
"@type": "Person",
"name": siteMeta.givenName + " " + siteMeta.familyName,
"givenName": siteMeta.givenName,
"familyName": siteMeta.familyName,
"birthDate": siteMeta.birthDate,
"address": siteMeta.address,
"email": siteMeta.contactEmail,
"telephone": siteMeta.contactPhone,
"gender": siteMeta.gender,
"height": siteMeta.height,
"nationality": {
"@type": "Country",
"name": siteMeta.nationality
},
"image": siteMeta.siteUrl + "/owner.jpg",
"sameAs": siteMeta.sameAs
}
})}
</script>
{children}
</Helmet>
);
}
@ -92,6 +137,9 @@ SEO.propTypes = {
description: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
speakable: PropTypes.any,
image: PropTypes.string,
children: PropTypes.any
};
export default SEO;

View file

@ -0,0 +1,37 @@
import { useStaticQuery, graphql } from 'gatsby';
const useSiteMetadata = () => {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
keywords
author
siteUrl
payPalMail
contactEmail
contactPhone
mapsLink
contactTwitter
contactGitHub
contactMastodon
contactMastodonHref
givenName
familyName
birthDate
address
gender
height
nationality
sameAs
}
}
}
`,
);
return site.siteMetadata;
};
export default useSiteMetadata;

View file

@ -16,7 +16,9 @@ class Layout extends React.Component {
lang={this.props.lang}
meta={this.props.meta}
title={this.props.title}
/>
image={this.props.image}
speakable={this.props.speakable}
>{this.props.seoAdditional ?? null}</SEO>
<Navigation isHome={this.props.transparentTopbar} />
<div id="content" role="main">
{this.props.children}
@ -57,6 +59,9 @@ Layout.propTypes = {
title: PropTypes.string.isRequired,
transparentTopbar: PropTypes.bool,
children: PropTypes.any.isRequired,
seoAdditional: PropTypes.any,
image: PropTypes.string,
speakable: PropTypes.any
};
export default Layout;

View file

@ -112,7 +112,16 @@ const IndexPage = (props) => {
let file = props.data.file;
return (
<Layout title="Kevin Kandlbinder" transparentTopbar={true} description={t("siteDescription")}>
<Layout title="Kevin Kandlbinder" transparentTopbar={true} description={t("siteDescription")}
image={meta.siteUrl + "/owner.jpg"}
speakable={{
"@type": "SpeakableSpecification",
"xPath": [
"/html/head/title",
"/html/head/meta[@name='description']/@content",
"article"
]
}}>
<section className={styles.heroSection}>
<div
className={styles.heroSectionBg}

View file

@ -6,6 +6,7 @@ import PropTypes from "prop-types";
import * as styles from "./projects.module.scss";
import { GatsbyImage } from "gatsby-plugin-image";
import useSiteMetadata from "../helpers/useSiteMetadata";
export const query = graphql`
query GetProjects($language: String) {
@ -21,6 +22,7 @@ export const query = graphql`
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
publicURL
}
shortDescription
}
@ -39,8 +41,29 @@ export const query = graphql`
const ProjectsPage = ({ data }) => {
const { t } = useI18next();
const meta = useSiteMetadata();
return (
<Layout title={t("projects")} description={t("projectsDescription")}>
<Layout title={t("projects")} description={t("projectsDescription")} seoAdditional={
<script type="application/ld+json">
{JSON.stringify(
{
"@context":"https://schema.org",
"@type":"ItemList",
"itemListElement":data.allProjectsJson.nodes.map((project, i) => {
return {
"@type":"ListItem",
"position":i,
"url": meta.siteUrl+"/projects/"+project.urlname,
"image": project.image.publicURL,
"name": project.name,
"description": project.shortDescription
}
})
}
)}
</script>
}>
<section>
<article>
<h1>

View file

@ -26,6 +26,7 @@ export const query = graphql`
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
publicURL
}
shortDescription
}
@ -64,6 +65,7 @@ const ProjectTemplate = ({ data }) => {
description={project.shortDescription}
title={t("project") + ": " + projectName}
transparentTopbar={true}
image={project.image.publicURL}
>
<section className={styles.projectHeader}>
<div style={{ paddingTop: 0 }}>