Added optional per-tag descriptions seeded in _data/tags.yaml, rendered as body blurbs on tag archive pages (blog and garden) and injected as plain-text SEO metadata via a Jekyll :pages, :pre_render hook. Descriptions support Markdown and inline HTML in the body, with plain-text extraction for SEO meta tags.
_data/tags.yaml — flat mapping of tag slug to description string (YAML block scalar). Descriptions may contain HTML and/or Markdown._layouts/tag-archive.html and _layouts/garden-tag-archive.html — if a description exists for the current tag, render it between the heading and the post/note list.| markdownify) so both Markdown and inline HTML are supported in the body.<meta name="description">, og:description, and JSON-LD description via jekyll-seo-tag.Files created/modified:
_data/tags.yaml (new) — Single source of truth for tag descriptions. Keys must exactly match tag strings used in post/page front matter. Values are YAML block scalars (use >- for single-paragraph, | for multi-paragraph).
_layouts/tag-archive.html — Added conditional Liquid block after <h1> that looks up site.data.tags[page.title] and renders through | markdownify if present.
_layouts/garden-tag-archive.html — Same conditional block as above. _data/tags.yaml is global — same description applies to blog tags, garden tags, and any future tag archive.
_plugins/tag_descriptions_seo.rb (new, rework) — :pages, :pre_render hook that:
tag-archive or garden-tag-archive
site.data['tags'] using page.title (method, not page.data['title'])CGI.unescapeHTML, normalizes whitespacepage.data['description'] so jekyll-seo-tag picks it up for meta tagsKey implementation detail: Jekyll::Archives::Archive objects store the tag name via a title method, not in page.data['title']. The hook must use page.title for the lookup.
Original build verification:
bundle exec jekyll build
Rework verification:
QA: Both passes found no issues. Code follows KISS, DRY (acceptable duplication), YAGNI principles.
Technical:
Jekyll::Archives::Archive stores page metadata (title, tag, type) as instance methods, not in the page.data hash. When writing hooks that target archive pages, always use page.title / page.type rather than page.data['title']. This is a gotcha that arises specifically from the jekyll-archives gem’s class design and is not documented in the gem’s README.!= blank idiom handles nil, empty string, and whitespace-only uniformly — preferable to chaining and conditions for Jekyll data file lookups where a key may be absent, empty, or whitespace.CGI.unescapeHTML after tag-stripping to avoid double-encoding when jekyll-seo-tag applies its own xml_escape filter.Process:
Jekyll.logger.debug pass listing available attributes would have caught the page.data['title'] issue at plan time rather than build time.None — clean execution with one debugging iteration during rework build to discover the Archive class data model difference.
If tag descriptions had been a foundational assumption, the ideal design would be the same — _data/tags.yaml as the single source, with a pre-render hook injecting into page.data['description'] for SEO and Liquid markdownify for the body. The only improvement would be to extract the tag lookup into a shared utility if more consumers emerge (e.g., a tags index page showing descriptions). For now, two independent access paths (Liquid and Ruby) is the right level of coupling.
None.