Skip to content

DOC-7128 unit 0: add image render hook and migration codemod - #4151

Merged
andy-stark-redis merged 1 commit into
mainfrom
DOC-7128-image-render-hook
Sep 29, 2026
Merged

andy-stark-redis merged 1 commit into
mainfrom
DOC-7128-image-render-hook

Conversation

@andy-stark-redis

@andy-stark-redis andy-stark-redis commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds the groundwork for replacing the image shortcode with native Markdown images. Unit 0 of DOC-7128, continuing the DOC-6909 render-hook migration series. This PR converts no content. The rollout units run the codemod.

Authors will write:

![Alt text](/images/x.png)
{width="300px" class="inline"}

Files (4):

  • layouts/_default/_markup/render-image.html (new): renders Markdown images with the width/class the shortcode accepted. It drops the shortcode's <a sdata-lightbox> wrapper, because nothing reads sdata-lightbox and static/js/index.js already makes any unwrapped <img> click-to-open (it skips #no-click images, as before). It warns at build time when an image isn't in static/.
  • config.toml: turns on markup.goldmark.parser.attribute.block and turns off wrapStandAloneImageWithinParagraph. Hugo needs both to pass an attribute line to the image hook, and only for an image that is its own paragraph.
  • build/migrate_image_shortcodes.py (new): the codemod. It converts standalone image shortcodes and rewrites every path to site-root /images/.... Anything it can't convert safely stays a shortcode and is reported.
  • layouts/partials/process-markdown-content.html: keeps the AI Markdown/JSON feed correct for converted images by using absolute URLs and dropping the attribute line.

Rendered changes from this PR alone: 7 pages with existing native standalone images lose the <p> around those images. That matches how shortcode images already render (they were never in a <p>). 3 pages with page-relative native images now get absolute paths to the same files.

Not convertible, left as shortcodes: Markdown can't attach width/class to an image inside a sentence, so the ~123 inline button icons (#no-click, class="inline") stay as shortcodes pending a decision on the ticket.

Verification

  • Full-site Hugo builds of origin/main and this branch: both succeeded, 19,661 pages each. The two parser settings capture no existing {...} line anywhere in the corpus.
  • Trial conversion of the whole corpus (not included here), built under the production baseURL (/docs/latest/) and compared image by image (src/width/alt/class) across every page. 1,646 of 1,829 shortcodes convert. The only rendered image changes are:
    • 40 alt texts lose Markdown emphasis (**Delete** becomes Delete), which reads better for screen readers.
    • 34 page-relative native images resolve to their permalinks.
    • The one dot-relative image, develop/tools/insight/insight-stream-consumer.md, is fixed. It currently renders /docs/images/... in production, which is broken.
  • The codemod is idempotent: a second run changes nothing. Every changed file has exactly one deleted line per converted shortcode.
  • AI feed: after the trial conversion, no attribute lines and no relative /images/ links remain in any .md output.
  • Not checked: the spacing of the 7 native-image pages in a browser.

🤖 Generated with Claude Code


Note

Medium Risk
Site-wide Goldmark parser and a new image render hook change how every Markdown image is parsed and emitted (including a few existing native standalone images losing a wrapping <p>); AI feed regexes must stay aligned with author syntax.

Overview
Unit 0 groundwork to replace the {{< image >}} shortcode with native Markdown plus a Hugo image render hook. No content is converted in this PR; later rollout runs build/migrate_image_shortcodes.py.

Authors will use a standalone image line plus an optional attribute line ({width="..." class="..."}), which config.toml enables via wrapStandAloneImageWithinParagraph = false and markup.goldmark.parser.attribute.block = true.

layouts/_default/_markup/render-image.html is new: it maps /images/... and /static/images/... through relURL, resolves page resources for relative paths, applies width/class from block attributes, omits the old shortcode lightbox <a> wrapper (click-to-open stays in site JS), and warnfs when a root path is missing under static/.

build/migrate_image_shortcodes.py is a conservative, idempotent codemod that only rewrites shortcodes on their own paragraph, normalizes paths to site-root form when the file exists in static/, and reports skips (inline/table, bad attrs, missing files, etc.).

process-markdown-content.html strips attribute lines and rewrites /images/ links to absolute https://redis.io/docs/latest/images/ so AI Markdown/JSON output stays clean after migration.

Reviewed by Cursor Bugbot for commit f7bab35. Bugbot is set up for automated code reviews on this repo. Configure here.

Adds render-image.html so Markdown images can replace the `image` shortcode,
the build/migrate_image_shortcodes.py codemod the rollout units will run, and
rules in process-markdown-content.html so converted images reach the AI
Markdown/JSON feed with absolute URLs and without their attribute line. No
content is converted here.

The config pair was the surprise. The obvious key (`attribute.title`) does
nothing for images. Width and class reach the hook only with `attribute.block`
on AND `wrapStandAloneImageWithinParagraph` off, and even then only for an
image that is its own paragraph. A scratch-site test showed it plainly: with
wrap on, the attribute lands on the surrounding <p>, not the image. That makes
inline icons unconvertible by design, and the codemod skips them rather than
emit an attribute line Goldmark would silently drop. Turning block attributes
on site-wide captured nothing in a full build diff; the only change was the
<p> dropping from 7 pages of existing native images, which brings them in line
with shortcode images (those never had a <p>, because a line opening with <a
is an HTML block).

The shortcode's `TrimLeft "/"` before relURL looked redundant but isn't:
relURL leaves a leading-slash path unprefixed, so under the production
baseURL (/docs/latest/) it would drop the subpath. The hook keeps that trim.
The dropped <a> wrapper was not load-bearing: static/js/index.js already opens
any unwrapped <img> on click and skips #no-click sources.

The codemod first read files in Python's default newline mode, which quietly
rewrote a stray CRLF in an embed. It now reads and writes with newline="".
Trial run over the whole corpus, then built under the production baseURL and
compared img src/width/alt/class per page: 1,646 of 1,829 convert, and the
only rendered changes are 40 alts losing Markdown emphasis, 34 native
page-relative srcs resolved to permalinks, and the one dot-relative image
(insight-stream-consumer) fixed from /docs/images to /docs/latest/images.

Learned: image attributes need parser.attribute.block plus wrapStandAloneImageWithinParagraph=false, standalone images only
Constraint: render-image.html must strip the leading slash before relURL or the /docs/latest/ baseURL subpath is lost
Constraint: migrate_image_shortcodes.py must keep newline="" on read and write, or CRLF lines get rewritten silently
Rejected: converting inline or paragraph-joined images | Goldmark drops their attribute line, so width and class would vanish
Rejected: keeping the <a sdata-lightbox> wrapper | nothing reads sdata-lightbox and index.js already handles click-to-open
Directive: verify rollout units by comparing parsed img attributes page by page under the production baseURL, not by grepping <img
Gaps: visual spacing of the 7 native-image pages that lose their <p> wrapper was not checked in a browser
Ticket: DOC-7128
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

DOC-7128

@github-actions

Copy link
Copy Markdown
Contributor

@andy-stark-redis

Copy link
Copy Markdown
Contributor Author

Thanks @dwdougherty !

@andy-stark-redis
andy-stark-redis merged commit ce2c68e into main Sep 29, 2026
99 checks passed
@andy-stark-redis
andy-stark-redis deleted the DOC-7128-image-render-hook branch September 29, 2026 15:10
EliShteinman added a commit to EliShteinman/docs that referenced this pull request Sep 29, 2026
Adds the image render hook, its Goldmark settings and the image-shortcode migration codemod.

# Conflicts:
#	layouts/partials/process-markdown-content.html
EliShteinman added a commit to EliShteinman/docs that referenced this pull request Sep 29, 2026
Adds the image render hook, its Goldmark settings and the image-shortcode migration codemod.

# Conflicts:
#	layouts/partials/process-markdown-content.html
andy-stark-redis added a commit that referenced this pull request Oct 5, 2026
Every image on the site is now Markdown, rendered by
layouts/_default/_markup/render-image.html: 1,829 shortcodes converted across
#4151 to #4206. No content file calls {{< image >}}, so the shortcode is deleted,
along with the two process-markdown-content.html rules that rewrote it for the
AI Markdown/JSON feed (the Markdown-image rules stay).

It also deletes five embeds that nothing includes and that never rendered,
because content/embeds/ is build: render: never: account-role-table.html,
create-db.md, rc-create-db-use-cases.md, rc-version-upgrade.md, and
tls-configuration-procedure.md. README.md's Images section now shows the
Markdown forms (plain, with an attribute line, and inline icon), and
HUGO_DEPENDENCY_ASSESSMENT.md's link to the deleted template points at
render-image.html.

A throwaway site confirmed that Hugo fails the build on a call to a missing
shortcode (exit 1), so clean builds under the production baseURL, both normal
and with drafts, show that nothing still calls it. Against main: 0 image
differences, and the AI feed files are identical apart from Git dates that
come from the baseline build.

Learned: Hugo fails the build on a call to a missing shortcode, but --quiet plus a pipe hides both the error and the exit code; check $? directly
Constraint: write images as Markdown; the image shortcode no longer exists, and any {{< image >}} call fails the build
Ticket: DOC-7128
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants