Skip to content

Markdown Feeds: Render comments in comment feed contexts - #1121

Open
ekamran wants to merge 4 commits into
WordPress:developfrom
ekamran:shifteq/markdown-comment-feeds
Open

ekamran wants to merge 4 commits into
WordPress:developfrom
ekamran:shifteq/markdown-comment-feeds

Conversation

@ekamran

@ekamran ekamran commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

What?

Closes #1120

Renders comments, instead of the post list, when the Markdown feed is requested in a comment feed context.

Why?

add_feed( 'markdown', ... ) registers the format for every feed context, so /comments/feed/markdown/ and /<post>/feed/markdown/ resolve, but do_feed_markdown() always used the post renderer. Those URLs returned the latest posts with full content, while the core comment feeds at the same URLs list comments. Details and sample output are in #1120.

How?

  • New Markdown_Comment_Feed_Renderer. do_feed_markdown() uses it when is_comment_feed() is true, and the post renderer otherwise.
  • Feed requests are never negotiated. is_singular() is true on a post's comment feed, so /post/feed/ previously got Vary: Accept and could be served the post's Markdown on Accept: text/markdown or ?output_format=markdown. Both gates now also require ! is_feed().
  • The document opens with # Comments on: <post title> and the post link for a post's comment feed, or # Comments for <site name> and the site URL for the site-wide feed (and other non-singular comment feed contexts, such as a category feed with withcomments=1).
  • Each approved comment is one block: a heading (Comment on <post> by <author> site-wide, By: <author> on a post, the same wording core uses for its comment feed item titles), a metadata list with the comment link and date, and the comment text run through the comment_text filters and converted to Markdown, so <strong> and auto-linked URLs come out as Markdown. Rendering runs inside the core comment loop with the comment's post set up, so those filters see the same context as in the core comment feeds.
  • Comments on password-protected posts are listed without their text, as core does in its comment feeds.
  • Which comments and how many come from the core query (comment_feed_* filters, posts_per_rss), so moderation, order and the limit match the core feeds. Last-Modified, ETag and 304 answers come from core as before.
  • A filter wpai_markdown_comment_feed_item_sections mirrors wpai_markdown_feed_item_sections for the post items. Documented in docs/experiments/markdown-feeds.md together with the comment feed URLs.

Sample, /hello-world/feed/markdown/ with this PR:

# Comments on: Hello world!

- Link: http://127.0.0.1:8971/2026/08/20/hello-world/

## By: Reader

- Link: http://127.0.0.1:8971/2026/08/20/hello-world/#comment-507
- Published: 2026-10-06T12:35:52+00:00

A thoughtful comment with **bold** text and a link [https://example.com/](https://example.com/).

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code and Codex
Used for: Investigation, implementation, tests, verification, and PR wording. I reviewed the reasoning and test results, and I take responsibility for the contribution.

Testing Instructions

  1. Enable the Markdown Feeds experiment and approve a comment on a post.
  2. Open /comments/feed/markdown/. On develop it lists posts. With this PR it lists the comments, newest first, each with a link and date.
  3. Open /<post-slug>/feed/markdown/. With this PR it lists only that post's comments under # Comments on: <title>.
  4. Open /feed/markdown/. It still lists posts.
  5. Optional: add a comment to a password-protected post. Its block appears in /comments/feed/markdown/ without the comment text.

Automated:

  • npm run test:php -- --filter 'Markdown_Comment_Feed_RendererTest|test_feed_callback_renders_comments' runs the seven new tests. On develop five stop with the missing class and the others fail; all pass here.
  • The full PHP suite passes on single site and on multisite (1775 tests).
  • composer lint and PHPStan pass.
  1. With the Accept setting on, curl -sI -H 'Accept: text/markdown' <post URL>feed/ returns application/rss+xml without a Vary: Accept header (on develop it returns the post's Markdown).

Changelog Entry

Fixed - Markdown Feeds: the comment feed URLs list comments instead of the post list.
Fixed - Markdown Feeds: Feed requests are no longer served the post's Markdown by Accept negotiation or ?output_format=markdown.

Open WordPress Playground Preview

add_feed() registers the markdown format for every feed context, so
/comments/feed/markdown/ and /<post>/feed/markdown/ resolve, but
do_feed_markdown() always used the post renderer. Those URLs returned the
post list instead of comments, unlike the core comment feeds at the same
URLs.

Comment feed contexts now use Markdown_Comment_Feed_Renderer: a heading for
the site or the post, then one block per approved comment with the author
(and the post, in the site-wide feed), the comment link and date, and the
comment text converted to Markdown. Comments on password-protected posts
are listed without their text, as in core. A new filter,
wpai_markdown_comment_feed_item_sections, mirrors the post item filter.
@ekamran
ekamran requested a review from a team October 6, 2026 13:45
@ekamran
ekamran requested a review from jeffpaul as a code owner October 6, 2026 13:45
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ekamran <ekamran@git.wordpress.org>
Co-authored-by: dkotter <dkotter@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.46835% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.80%. Comparing base (19d5670) to head (8bcb561).

Files with missing lines Patch % Lines
.../Markdown_Feeds/Markdown_Comment_Feed_Renderer.php 97.36% 2 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #1121      +/-   ##
=============================================
+ Coverage      81.67%   81.80%   +0.12%     
- Complexity      3103     3118      +15     
=============================================
  Files            129      130       +1     
  Lines          12334    12410      +76     
=============================================
+ Hits           10074    10152      +78     
+ Misses          2260     2258       -2     
Flag Coverage Δ
unit 81.80% <97.46%> (+0.12%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread includes/Experiments/Markdown_Feeds/Markdown_Comment_Feed_Renderer.php Outdated
…ents

The comment feed renderer iterated the comments array directly, so the
comment_text filters ran without the global comment and with the main
query's post as the current post. Use the comment loop and set up each
comment's post before filtering, like the core comment feeds do, and reset
the post data after the loop.
…omment-feeds

# Conflicts:
#	tests/Integration/Includes/Experiments/Markdown_Feeds/Markdown_FeedsTest.php
$this->send_header( 'Content-Type: text/markdown; charset=' . get_option( 'blog_charset' ) );

$renderer = new Markdown_Feed_Renderer();
$renderer = is_comment_feed() ? new Markdown_Comment_Feed_Renderer() : new Markdown_Feed_Renderer();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies but testing again, this does not seem to work the way I'd expect. With these changes in place, the main post markdown feed only renders comments, not the actual post itself. That seems broken, shouldn't there be a specific comment feed that is used instead?

I also think header negotiation is broken for these feeds so that needs looked at

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, agreed on all of these.

For the per-post feed shape: I read core's /post/feed/ as the post's comment feed, which is why I switched /post/feed/markdown/ to comments. But I agree this changes the Markdown feature's existing behaviour, where that URL rendered the post itself.

The header negotiation problem is real and pre-existing: is_singular() is true on a post's comment feed, so /post/feed/ got Vary: Accept and was served the post's Markdown on Accept: text/markdown or ?output_format=markdown. Fixed here so feed requests are never negotiated, plus the smaller renderer fixes.

For the route shape, my suggested direction is to keep /post/feed/markdown/ rendering the post as before, keep /comments/feed/markdown/ for the site-wide comment feed, and add a separate explicit path or query for per-post comments only if you want that supported. Happy to go whichever way you prefer.

Comment thread includes/Experiments/Markdown_Feeds/Markdown_Comment_Feed_Renderer.php Outdated
A post's comment feed is a singular request too, so "/post/feed/" was
getting a "Vary: Accept" header and was served the post's Markdown when
the client sent "Accept: text/markdown" or "?output_format=markdown".
Both gates now also require the request not to be a feed.

In the comment feed renderer, escape the comment author in the item
heading, rewind the comment loop after rendering, and drop a redundant
assignment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Markdown Feeds: comment feed URLs return the post list instead of comments

2 participants