I added an SEO component to my blog recently and on top of that I decided to set up infrastructure to pull in images for Twitter, etc. The SEO component already handled titles and descriptions for cards on Twitter, but I wanted something a bit more... interesting. I like large images and I eventually want to start drawing images for my blog posts. So I dove into gatsby-transformer-sharp.
The sharp transformer makes it absolutely trivial to handle an image described in frontmatter and post it as a Twitter meta card.
First I jacked the
SEO component
from the Gatsby starters. Then I added a couple key
components. Notably twitter:image
and the switch that
enabled the summary_large_image
card type.
import React from "react";import PropTypes from "prop-types";import Helmet from "react-helmet";import { StaticQuery, graphql } from "gatsby";function SEO({description,lang = "en",meta = [],keywords = [],title,image}) {return (<StaticQueryquery={detailsQuery}render={data => {const metaDescription =description || data.site.siteMetadata.description;return (<HelmethtmlAttributes={{lang}}title={title}titleTemplate={`%s | ${data.site.siteMetadata.title}`}meta={[{name: `description`,content: metaDescription},{property: `og:title`,content: title},{property: `og:description`,content: metaDescription},{property: `og:type`,content: `website`},{property: `twitter:site`,content: "@chrisbiscardi"},{name: `twitter:card`,content: !!image? `summary_large_image`: `summary`},{name: `twitter:creator`,content: data.site.siteMetadata.author},{name: `twitter:title`,content: title},{name: `twitter:description`,content: metaDescription}].concat(keywords.length > 0? {name: `keywords`,content: keywords.join(`, `)}: []).concat(image? {name: `twitter:image`,content: `https://www.christopherbiscardi.com${image}`}: []).concat(meta)}/>);}}/>);}SEO.propTypes = {description: PropTypes.string,lang: PropTypes.string,meta: PropTypes.array,keywords: PropTypes.arrayOf(PropTypes.string),title: PropTypes.string.isRequired};export default SEO;const detailsQuery = graphql`query DefaultSEOQuery {site {siteMetadata {titledescriptionauthor}}}`;
Then I stuck an image in my frontmatter for a blog post. The addition of gatsby-transformer-sharp enabled the following query to get the processed image.
export const pageQuery = graphql`query($id: String!) {mdx(id: { eq: $id }) {idcode {body}excerptfrontmatter {titlefeaturedImage {childImageSharp {fixed {src}}}}}}`;
Then it's a matter of using that query and passing it into the SEO component.
const imageRoot = data.mdx.frontmatter.featuredImage;let src = undefined;if (imageRoot) {src = imageRoot.childImageSharp.fixed.src;}return (<SiteLayoutsidebar={<aside css={{ minWidth: "200px" }}>some stuff</aside>}><SEOdescription={data.mdx.excerpt}title={data.mdx.frontmatter.title}image={src}/>
Now to add a new "featured image" that shows up on Twitter, we only need to add a pointer to the image in our frontmatter.
I currently use Netlify CMS to edit my blog posts and I'm
starting to feel the need for something a bit more custom.
Currently, Netlify CMS will blow away the featuredImage
key on updates, erasing the Twitter opengraph image from
being presented.