From 28914d06318fb4b465d5a61a827119e34b1c9a38 Mon Sep 17 00:00:00 2001 From: Michael Harp Date: Fri, 21 Aug 2026 07:00:03 -0400 Subject: [PATCH 1/2] Set absolute site url to enable full SEO output With no absolute url in _config.yml, the theme's SEO layer (added in jekyll-vitepress-theme 1.9) skips canonical URLs, JSON-LD, and sitemap.xml, warns on every build, and emits llms.txt with relative links. Setting the production origin turns all of that on: pages get self-canonicals, robots.txt advertises the sitemap, and llms.txt links become absolute. The canonical_latest plugin now reads the origin from site.url instead of only its hardcoded constant, which remains as the fallback for builds where url is overridden or unset (jekyll serve rewrites it to localhost in development). Its /latest/ canonicals still take precedence on the numbered twin collections, which search engines can now use to dedupe the /8.x/ and /latest/ copies. Co-authored-by: Claude Signed-off-by: Michael Harp --- _config.yml | 1 + _plugins/canonical_latest.rb | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/_config.yml b/_config.yml index 38826d6c6..82ec5a831 100644 --- a/_config.yml +++ b/_config.yml @@ -1,6 +1,7 @@ --- title: OpenVox Documentation description: Documentation for various OpenVox Projects. +url: https://docs.openvoxproject.org logo: /assets/images/HexagonSticker.png diff --git a/_plugins/canonical_latest.rb b/_plugins/canonical_latest.rb index 6449e0c0d..8a3da39e8 100644 --- a/_plugins/canonical_latest.rb +++ b/_plugins/canonical_latest.rb @@ -11,12 +11,14 @@ # self-canonical: once `latest` moves on, their content is unique and the # same page may not exist under /latest/. # -# The origin is hardcoded, matching llms.txt, because site.url is unset. +# The production origin is the fallback for builds where `url` is unset +# (e.g. `jekyll serve` overrides it to localhost in development). module OpenvoxDocs module CanonicalLatest ORIGIN = 'https://docs.openvoxproject.org' def self.apply(site) + origin = site.config['url'].to_s.empty? ? ORIGIN : site.config['url'] (site.data['products'] || {}).each do |product_id, product| version = Array(product['versions']).find { |v| v['id'] == product['latest'] } next unless version @@ -24,15 +26,15 @@ def self.apply(site) collection = site.collections[version['collection'].delete_prefix('_')] next if collection.nil? || collection.label.end_with?('_latest') - canonicalize(collection, version['base'], "/#{product_id}/latest/") + canonicalize(collection, origin, version['base'], "/#{product_id}/latest/") end end - def self.canonicalize(collection, base, latest_base) + def self.canonicalize(collection, origin, base, latest_base) collection.docs.each do |doc| next unless doc.url.start_with?(base) - doc.data['canonical_url'] = "#{ORIGIN}#{latest_base}#{doc.url.delete_prefix(base)}" + doc.data['canonical_url'] = "#{origin}#{latest_base}#{doc.url.delete_prefix(base)}" end end end From a16a7be6bf62f0e87fcb7dbd22623633051f8724 Mon Sep 17 00:00:00 2001 From: Michael Harp Date: Sat, 22 Aug 2026 06:43:49 -0400 Subject: [PATCH 2/2] Add seo.image config for social-card width/height/alt The theme emits og:image:width/height and a stable og:image:alt only when jekyll_vitepress.seo.image is set. HexagonSticker.png is already 1200x630, so point at it explicitly per the theme's production minimum. Co-authored-by: Claude Signed-off-by: Michael Harp --- _config.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/_config.yml b/_config.yml index 82ec5a831..399cc6a86 100644 --- a/_config.yml +++ b/_config.yml @@ -25,6 +25,14 @@ jekyll_vitepress: logo: default: 'https://github.com/voxpupuli/logos/blob/master/images/OpenVox/Sticker/HexagonSticker.svg?raw=true' alt: OpenVox Automation Framework + # Social-card image for Open Graph / Twitter tags. Falls back to `logo` + # without this, but width/height are only emitted when set here. + seo: + image: + path: /assets/images/HexagonSticker.png + alt: OpenVox Documentation + width: 1200 + height: 630 # Disabled as it adds extra size to generated HTML pages. copy_page: enabled: false