fix: render Djot in feeds instead of shipping the raw source - #58
Open
dereuromark wants to merge 2 commits into
Open
dereuromark wants to merge 2 commits into
dereuromark wants to merge 2 commits into
Conversation
shouldFilterContent() returned false for is_feed(), so Djot was never rendered in RSS or Atom and the subscriber received the markup: headings as `# `, emphasis as asterisks, definition lists as their markers. Worse, the fallback was not even faithful. Because nothing rendered the string it reached wptexturize, which curls the fence characters - the opening backtick run arrived as a left double quote followed by a backtick. Measured on a live feed: six curly quotes where the source had none. So the reader was not getting plain source, they were getting corrupted source, in the one place they cannot click through to see the real page. Feeds are rendered now, through a 'feed' context that differs from 'article' only in what it leaves out. Two of those omissions are free: the table of contents and the heading permalinks are already gated on 'article', and a table of contents is a list of anchors into a page the reader is not on while a permalink is a hover affordance needing CSS a feed does not carry. The third is Mermaid, which needed a gate of its own. Its extension emits a container for a client script to replace, and no script runs in a reader, so the diagram would arrive as unformatted text with no explanation. Left unregistered, the same fence falls back to a plain code block. Verified on a live feed: rendered HTML, no raw markers, zero curly quotes, and the diagram as a code block - while the post's own page keeps its container. convertArticle and the new convertFeedOrArticle share one body so the contexts cannot drift apart.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates WP-Djot’s content filtering/conversion pipeline so Djot is rendered in RSS/Atom feeds instead of being shipped as raw (and wptexturize-corrupted) source, by introducing a feed-aware rendering context that omits reader-unfriendly features (TOC, heading permalinks, Mermaid hydration).
Changes:
- Route full post content and
{djot}...{/djot}block conversions through a newconvertFeedOrArticle()path. - Stop excluding feeds in
shouldFilterContent()so feed requests get Djot rendering. - Add a
'feed'context to converter configuration and disable Mermaid extension for that context (to fall back to readable code blocks).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Plugin.php |
Enables Djot filtering in feeds and uses the feed-aware conversion entry point for post content processing. |
src/Converter.php |
Introduces a feed context and a convertFeedOrArticle() helper; gates Mermaid extension (and related cache behavior) based on context. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
191
to
193
| $roundTripKey = $roundTripMode ? '_rt' : ''; | ||
| $key = $profileName . ($safeMode ? '_safe' : '_unsafe') . '_' . $softBreakSetting . ($this->markdownMode ? '_md' : '') . $tocKey . $permalinksKey . $smartQuotesKey . $headingShiftKey . $mermaidKey . $roundTripKey; | ||
|
|
Comment on lines
+412
to
+415
| public function convertFeedOrArticle(string $djot): string | ||
| { | ||
| return $this->convertInContext($djot, is_feed() ? 'feed' : 'article'); | ||
| } |
The comment claimed the diagram would arrive with no formatting and no explanation. Measured, the interactive container already carries the source as visible text, so nothing is lost either way - the difference is which element wraps it. The gate is still worth keeping: the fallback declares the block is code, and it escapes the arrow, which sits unescaped inside the interactive form and is an HTML comment closer for whatever sanitizer a feed reader runs. But that is a tidier degradation, not a rescue, and the comment should not oversell it. The rendering fix this branch is really about - feeds got raw, texturize- corrupted source - is unaffected.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/Converter.php:401
convertFeedOrArticle()is only used fromPlugin, but other render entry points (e.g.Blocks/DjotBlock.php,Shortcodes/DjotShortcode.php,src/functions.php) still callconvertArticle(). In a feed request those paths will continue to render with thearticlecontext (TOC/permalinks/Mermaid container), so the new feed-specific omissions won’t consistently apply. Consider makingconvertArticle()automatically pick thefeedcontext whenis_feed()is true, and keepconvertFeedOrArticle()as an alias to avoid missing call sites.
public function convertArticle(string $djot): string
{
return $this->convertInContext($djot, 'article');
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #57.
shouldFilterContent()returned false foris_feed(), so Djot was never rendered in RSS or Atom and the subscriber received the markup - headings as#, emphasis as asterisks, definition lists as their markers.Worse, the fallback was not even faithful. Because nothing rendered the string it reached
wptexturize, which curls the fence characters: the opening backtick run arrived as a left double quote followed by a backtick. Six curly quotes where the source had none. So the reader was not getting plain source, they were getting corrupted source - in the one place they cannot click through to see the real page.The feed context
Feeds render now, through a
'feed'context that differs from'article'only in what it leaves out.Two of those omissions are free: the table of contents and the heading permalinks are already gated on
'article', and both are meaningless in a reader - a TOC is anchors into a page the reader is not on, and a permalink is a hover affordance needing CSS a feed does not carry.Mermaid is the third, and it is a smaller point than an earlier draft of this description claimed. It is worth being accurate about: the container already carries the source as visible text, so nothing is lost either way.
Two modest reasons to keep the gate rather than drop it. The code-block form declares what the block is, so a reader that styles code styles it. And the interactive form leaves
-->unescaped inside the element, which is an HTML comment closer that a feed sanitizer may treat unpredictably; the fallback escapes it.Not a rescue, then - a tidier degradation. The rendering fix above is the substance.
Why only Mermaid
Because it is the only client-rendered fence djot-php ships. Checked rather than assumed: the extension list has no chart, vega-lite, graphviz, d2, plantuml or wavedrom equivalent.
The other JS-adjacent constructs this plugin registers do not need a gate either.
TabsandCodeGroupuse a CSS-only radio technique - no script, nohidden, no inlinedisplay: none- so without a stylesheet a feed shows every panel rather than hiding all but one. Verbose, but nothing is lost, which is the bar here.Verified on a running site
#markers in feedconvertArticleand the newconvertFeedOrArticleshare one body, so the two contexts cannot drift apart.phpunit, phpstan and phpcs green.