Repository navigation
Markdown Feeds: Follow Accept header preferences when negotiating - #1125
Conversation
The Accept check only looked at the first media range, so a client that listed text/html first never got Markdown, a client that put Markdown first with a lower quality than HTML got Markdown, and text/markdown;q=0 still served Markdown. Quality values were never read. prefers_markdown() now parses every media range of the header, with the usual precedence of an exact type over text/* over */*, and serves Markdown only when its quality is higher than the one for HTML. Ties, refusals, */* and text/* keep HTML, so browsers and curl are unchanged. text/x-markdown counts as text/markdown, and types and parameters are matched case-insensitively with surrounding spaces ignored.
|
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1125 +/- ##
=============================================
+ Coverage 81.62% 81.67% +0.05%
- Complexity 3088 3103 +15
=============================================
Files 129 129
Lines 12297 12334 +37
=============================================
+ Hits 10037 10074 +37
Misses 2260 2260
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
With equal quality, the more specific match now wins and then the type listed first in the Accept header. So "text/markdown, text/html, */*" keeps serving Markdown as the released version did, "text/html, text/markdown" stays HTML, and "text/*, text/html" stays HTML. A wildcard range matching both types still falls to HTML.
What?
Closes #1124
Makes the Markdown Feeds Accept-header negotiation follow the header's preferences instead of its first media range.
Why?
is_markdown_requested()matchedtext/markdownonly as the first media range and never read quality values. Sotext/markdown;q=0.9, text/htmlserved Markdown although HTML was preferred,text/markdown;q=0served Markdown although the client refused it, andapplication/json, text/markdownserved HTML although Markdown was the only acceptable type of the two. The setting's label promises Markdown "when a request prefers it". Details in #1124.How?
prefers_markdown( string $accept ): boolinMarkdown_Feeds. It walks every media range of the header, readsq(default 1, invalid values ignored), and keeps the best match fortext/htmland fortext/markdownwith the usual precedence: an exact type beatstext/*, which beats*/*.text/x-markdowncounts astext/markdown. Types and parameters are compared lowercase with surrounding spaces ignored.text/markdownbeatstext/*), then the type listed first. Sotext/markdown, text/html, */*serves Markdown as the released version does,text/html, text/markdownstays HTML,text/*, text/htmlstays HTML,*/*alone,text/*alone and browser headers (text/html,...,*/*;q=0.8) keep HTML (one range matching both types has no order), andtext/markdown;q=0can no longer serve Markdown.?output_format=markdown, the sub-toggle gate, theVary: Acceptheader and the discovery links are untouched. The setting stays off by default.docs/experiments/markdown-feeds.mddescribes the rule.Before and after on a singular URL with the setting on:
Acceptdeveloptext/markdowntext/x-markdownTEXT/MARKDOWN ; charset=utf-8 ; q = 1application/json, text/markdowntext/html;q=0.1, text/markdown*/*, text/html;q=0.2, text/markdown;q=0.9text/*, text/markdowntext/markdown;q=0.9, text/htmltext/markdown;q=0, text/html;q=0.5text/markdown, text/html, */*text/html, text/markdowntext/*, text/html*/*text/*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
curl -sI -H 'Accept: text/markdown;q=0.9, text/html' <post URL>:text/htmlwith this PR,text/markdownondevelop.curl -sI -H 'Accept: application/json, text/markdown' <post URL>:text/markdownwith this PR,text/htmlondevelop.curl -sI -H 'Accept: text/markdown' <post URL>still givestext/markdown;curl -sI <post URL>(*/*) and a browser still give HTML.Automated:
npm run test:php -- --filter test_accept_headerruns the two Accept tests, one of them a table of 21 headers. Nine rows fail ondevelopand all pass here.composer lintand PHPStan pass.Changelog Entry