[object Object]

← back to Thesetdecorator

TSD: add twitter:card=summary_large_image to 3 pages missing it

2343c923e40a040cce9d9a99c6dc50da0612d1fc · 2026-06-03 13:13:21 -0700 · Steve

games.html + _best-seller-detail.tpl.html (both indexable) + request-demo.html
(already noindex, harmless) had an og:image but no twitter:card, so their
Twitter shares rendered as a plain link instead of a large-image card. Added
the card after og:image; title/image fall back to OG. Idempotent
scripts/twitter-card-backfill.py; 0 indexable og:image pages still missing it,
no dupes. Invisible. Static — queued deploy.

Files touched

Diff

commit 2343c923e40a040cce9d9a99c6dc50da0612d1fc
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jun 3 13:13:21 2026 -0700

    TSD: add twitter:card=summary_large_image to 3 pages missing it
    
    games.html + _best-seller-detail.tpl.html (both indexable) + request-demo.html
    (already noindex, harmless) had an og:image but no twitter:card, so their
    Twitter shares rendered as a plain link instead of a large-image card. Added
    the card after og:image; title/image fall back to OG. Idempotent
    scripts/twitter-card-backfill.py; 0 indexable og:image pages still missing it,
    no dupes. Invisible. Static — queued deploy.
---
 public/_best-seller-detail.tpl.html |  1 +
 public/games.html                   |  1 +
 public/request-demo.html            |  1 +
 scripts/twitter-card-backfill.py    | 36 ++++++++++++++++++++++++++++++++++++
 4 files changed, 39 insertions(+)

diff --git a/public/_best-seller-detail.tpl.html b/public/_best-seller-detail.tpl.html
index 37b97b0..520d2a6 100644
--- a/public/_best-seller-detail.tpl.html
+++ b/public/_best-seller-detail.tpl.html
@@ -13,6 +13,7 @@
   <meta property="og:description" content="Production-vetted wallcovering. Preview on set, request swatch.">
   <meta property="og:site_name" content="The Set Decorator">
   <meta property="og:image" content="__IMAGE__">
+  <meta name="twitter:card" content="summary_large_image">
   <meta property="og:type" content="product">
   <script type="application/ld+json">{"@context":"https://schema.org","@type":"Product","name":"__TITLE__","brand":{"@type":"Brand","name":"__VENDOR__"},"sku":"__SKU__","image":"__IMAGE__","description":"Production-vetted wallcovering from the top 20% of Designer Wallcoverings' actual orders. Cleared for production use; fast-print delivery in LA basin."}</script>
   <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Inter:wght@400;500;600&display=swap">
diff --git a/public/games.html b/public/games.html
index 1365d65..9499c2f 100644
--- a/public/games.html
+++ b/public/games.html
@@ -15,6 +15,7 @@
   <meta property="og:url" content="https://thesetdecorator.com/games">
   <meta property="og:site_name" content="The Set Decorator">
   <meta property="og:image" content="https://thesetdecorator.com/img/hero/hero-rendered.jpg">
+  <meta name="twitter:card" content="summary_large_image">
   <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400;1,700&family=Inter:wght@400;500;600;700&display=swap">
   <link rel="stylesheet" href="/css/games.css">
 </head>
diff --git a/public/request-demo.html b/public/request-demo.html
index 0a76d6b..569625a 100644
--- a/public/request-demo.html
+++ b/public/request-demo.html
@@ -17,6 +17,7 @@
   <meta property="og:url" content="https://thesetdecorator.com/request-demo">
   <meta property="og:site_name" content="The Set Decorator">
   <meta property="og:image" content="https://thesetdecorator.com/img/hero/hero-rendered.jpg">
+  <meta name="twitter:card" content="summary_large_image">
   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Inter:wght@400;500;600&display=swap">
diff --git a/scripts/twitter-card-backfill.py b/scripts/twitter-card-backfill.py
new file mode 100644
index 0000000..fafb094
--- /dev/null
+++ b/scripts/twitter-card-backfill.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+"""Idempotent: add twitter:card to pages that have an og:image but no twitter:card.
+
+Twitter renders a Card only when twitter:card is present; other fields fall back
+to the OG tags. Two pages (games.html, _best-seller-detail.tpl.html) had an
+og:image (a large hero/product image) but no twitter:* tags at all, so their
+Twitter shares rendered as a plain link. Add
+<meta name="twitter:card" content="summary_large_image"> after og:image — the
+right type for a large image. Invisible (head meta). Idempotent + reversible.
+    python3 scripts/twitter-card-backfill.py
+"""
+import os, re, glob
+
+PUB = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "public")
+
+HAS_CARD_RE = re.compile(r'name=["\']?twitter:card', re.IGNORECASE)
+OG_IMAGE_RE = re.compile(r'^([ \t]*)<meta[^>]*property=["\']?og:image["\']?[^>]*>[ \t]*\n', re.IGNORECASE | re.MULTILINE)
+
+changed, skipped, noanchor = [], [], []
+for path in sorted(glob.glob(os.path.join(PUB, "*.html"))):
+    name = os.path.basename(path)
+    html = open(path, encoding="utf-8").read()
+    if HAS_CARD_RE.search(html):
+        skipped.append(name); continue
+    m = OG_IMAGE_RE.search(html)
+    if not m:
+        noanchor.append(name); continue          # no og:image — not a card candidate
+    indent = m.group(1)
+    line = f'{indent}<meta name="twitter:card" content="summary_large_image">\n'
+    html = html[:m.end()] + line + html[m.end():]
+    open(path, "w", encoding="utf-8").write(html)
+    changed.append(name)
+
+print(f"changed ({len(changed)}): {', '.join(changed) or '-'}")
+print(f"skipped/already-have-card ({len(skipped)})")
+print(f"no-og-image (skipped): {len(noanchor)}")

← c738710 backlog: loop #10 (og:site_name + WCAG autocomplete) + deplo  ·  back to Thesetdecorator  ·  backlog: loop #11 (twitter:card) + mark autonomous surface e b8de0cb →