Class: Abqari::OgImageGenerator
- Inherits:
-
Object
- Object
- Abqari::OgImageGenerator
- Defined in:
- lib/abqari/og_image_generator.rb
Overview
Auto-generated OG share images. When og_images.auto: true in
config/site.yml, the build emits a styled SVG card per content
page at <page-url>og.svg — so a post at /posts/hello/ gets
/posts/hello/og.svg. The head template's share_image
resolution chain falls through to this URL when no explicit
share_image: or image: is set on the page.
Output is SVG, not PNG. Modern social platforms (Facebook, LinkedIn, Mastodon, Discord, Slack) render SVG og:image fine in 2026; Twitter/X can be finicky, but its share cards have been generally improving on this front. Users that need PNG for max compatibility can convert via vips/magick — or supply their own hero, which always takes precedence.
Card layout:
1200×630 (standard OG dimensions, ~1.91:1 aspect)
theme-coloured gradient background (from config/site.yml's
manifest.theme_color — falls back to a tasteful default)
site title (small, top-left)
page title (large, centred, wrapped at ~22 chars)
author + date (small, bottom-left)
Why SVG instead of pre-rendered PNG? Three reasons:
- Zero external dependencies (vips/magick not required)
- Tiny output (~1-2 KB per page vs. 30-80 KB PNG)
- Themed via existing site colors — no separate design system
Constant Summary collapse
- OG_WIDTH =
1200- OG_HEIGHT =
630- TITLE_CHARS_PER_LINE =
Approximate character widths at the chosen font size, used for naive word-wrapping. Sans-serif at 72px renders ~22 chars per line within the safe content area; lower for narrow lines.
22- TITLE_MAX_LINES =
4
Class Method Summary collapse
-
.auto_card?(page) ⇒ Boolean
Single source of truth for "does this page get an auto card?".
Instance Method Summary collapse
- #enabled? ⇒ Boolean
-
#initialize(site) ⇒ OgImageGenerator
constructor
A new instance of OgImageGenerator.
- #write ⇒ Object
Constructor Details
#initialize(site) ⇒ OgImageGenerator
Returns a new instance of OgImageGenerator.
43 44 45 |
# File 'lib/abqari/og_image_generator.rb', line 43 def initialize(site) @site = site end |
Class Method Details
.auto_card?(page) ⇒ Boolean
Single source of truth for "does this page get an auto card?".
The head partial calls this before emitting the <page-url>og.svg
og:image URL, and write below calls it before generating the
file — sharing the predicate is what keeps the two from drifting
(drift means pages advertising og:image files that 404).
Only real content Pages qualify. Generated pages (TaxonomyPage,
PaginatedShard, RelatedIndexPage, PublisherShowPage) don't carry
their own titles the same way and mostly shouldn't be SHARED
directly; flat-file URLs (/404.html) can't host a sibling
og.svg because their path isn't a directory. Pages opt out with
og_image: false, and a page with its own share_image: or
image: hero doesn't need a card (the hero IS the share image).
64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/abqari/og_image_generator.rb', line 64 def self.auto_card?(page) return false unless page.is_a?(Abqari::Page) return false unless page.url.to_s.end_with?('/') return false if page.title.to_s.empty? fm = page.frontmatter return false if fm['og_image'] == false return false unless fm['share_image'].to_s.empty? return false unless fm['image'].to_s.empty? true end |
Instance Method Details
#enabled? ⇒ Boolean
47 48 49 |
# File 'lib/abqari/og_image_generator.rb', line 47 def enabled? @site.config.dig('og_images', 'auto') == true end |
#write ⇒ Object
77 78 79 80 81 82 83 84 85 |
# File 'lib/abqari/og_image_generator.rb', line 77 def write return unless enabled? Array(@site.pages).each do |page| next unless self.class.auto_card?(page) svg = render_svg(page) write_file(page, svg) end end |