From a24a646e7ab92e28ca52252e13a6d917b673e3ac Mon Sep 17 00:00:00 2001 From: Eric Seidel <eric@shorebird.dev> Date: Thu, 30 Jan 2025 13:57:47 -0800 Subject: [PATCH] feat: add more og tags to our blogs (#240) * feat: add more og tags to our blogs This includes the twitter tags: https://developer.x.com/en/docs/x-for-websites/cards/guides/getting-started And the "article" type tags: https://ogp.me/#type_article * fix: make image urls absolute * chore: move comment and fix cspell --- src/components/Author.astro | 9 ++++++++- src/layouts/BlogLayout.astro | 30 +++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/components/Author.astro b/src/components/Author.astro index 81b002b2..402f6f6f 100644 --- a/src/components/Author.astro +++ b/src/components/Author.astro @@ -4,31 +4,37 @@ import felixHeadshot from '../assets/images/felix-headshot.jpeg'; import bryanHeadshot from '../assets/images/bryan-headshot.png'; import shorebirdHeadshot from '../assets/images/shorebird-headshot.png'; +// cspell:words shorebirddev felangelov + interface Author { name: string; title: string; avatar: ImageMetadata; github: string; + twitter?: string; } -const authors: Record<string, Author> = { +export const authors: Record<string, Author> = { shorebirdtech: { name: 'Shorebird', title: 'The Shorebird Team', avatar: shorebirdHeadshot, github: 'shorebirdtech', + twitter: '@shorebirddev', }, eseidel: { name: 'Eric Seidel', title: 'Founder & CEO', avatar: ericHeadshot, github: 'eseidel', + twitter: '@_eseidel', }, felangel: { name: 'Felix Angelov', title: 'Founding Engineer', avatar: felixHeadshot, github: 'felangel', + twitter: '@felangelov', }, bryanoltman: { name: 'Bryan Oltman', @@ -40,6 +46,7 @@ const authors: Record<string, Author> = { const { handle } = Astro.props; const author = authors[handle]; + --- <div class="flex items-center"> diff --git a/src/layouts/BlogLayout.astro b/src/layouts/BlogLayout.astro index 58ba3190..6d4edb46 100644 --- a/src/layouts/BlogLayout.astro +++ b/src/layouts/BlogLayout.astro @@ -1,4 +1,5 @@ --- +// cspell:words shorebirddev import '@fontsource/inter'; import '@fontsource/inter/500.css'; import '@fontsource/inter/600.css'; @@ -6,7 +7,7 @@ import '@fontsource/inter/700.css'; import '@fontsource/inter/800.css'; import '@fontsource/inter/900.css'; import { config } from '~/config'; -import Author from '~/components/Author.astro'; +import Author, { authors } from '~/components/Author.astro'; import FormattedDate from '~/components/FormattedDate.astro'; import { Navbar } from '~/components/Navbar'; import { Footer } from '~/components/Footer'; @@ -15,6 +16,15 @@ import { BlogFooterPitch } from '~/components/BlogFooterPitch'; import '../styles/Theme.css'; const { title, description, author, date, cover, coverAlt } = Astro.props; + +// og:image is expected to be an absolute url beginning with http or https +const coverUrl = new URL(cover ? cover : '/open-graph.png', Astro.url.origin); +// Always use Astro.site (production url) rather than a test domain. +const canonicalUrl = new URL(Astro.url.pathname, Astro.site); +// See also https://ogp.me/#type_article +// Could also add og:tags here if we added them to the frontmatter for the +// individual blog posts. I'm not sure what, if any, sites crawl for the +// og:tags property. --- <!doctype html> @@ -27,12 +37,22 @@ const { title, description, author, date, cover, coverAlt } = Astro.props; <meta name="generator" content={Astro.generator} /> <meta name="description" content={description} /> <meta property="og:description" content={description} /> - <meta property="og:image" content={cover ? cover : '/open-graph.png'} /> + <meta property="og:image" content={coverUrl} /> <meta property="og:url" content={Astro.site} /> <meta property="og:title" content={title} /> - <meta name="twitter:image" content={cover ? cover : '/open-graph.png'} /> + <meta name="twitter:image" content={coverUrl} /> <meta name="twitter:card" content="summary_large_image" /> - <link rel="canonical" href={new URL(Astro.url.pathname, Astro.site)} /> + <link rel="canonical" href={canonicalUrl} /> + <meta property="og:type" content="article" /> + <meta property="article:published_time" content={date} /> + <meta property="article:author" content={author} /> + <meta property="article:section" content="Technology" /> + <meta name="twitter:site" content="@shorebirddev" /> + { + authors[author].twitter && ( + <meta name="twitter:creator" content={authors[author].twitter} /> + ) + } <script defer data-domain="shorebird.dev" @@ -56,7 +76,7 @@ const { title, description, author, date, cover, coverAlt } = Astro.props; } <hr class="my-8" /> <slot /> - <BlogFooterPitch /> + <BlogFooterPitch /> </div> <Footer client:load /> <style is:global>