WordPress

The Roots post-content-to-markdown plugin serves post content as Markdown when requested via the Accept header, with proper Vary, 406, and q-value handling.

Canonical source: https://github.com/roots/post-content-to-markdown

The cleanest way to content-negotiate a WordPress site is the Roots post-content-to-markdown plugin. It handles the conversion and the Accept-header routing without touching your theme.

What the plugin does

  • Parses the incoming Accept header with proper q-value ranking.
  • If Markdown is preferred, converts the rendered post HTML to Markdown on the fly (via league/html-to-markdown) and serves it with Content-Type: text/markdown; charset=utf-8 and Vary: Accept.
  • Returns 406 Not Acceptable when the client explicitly rejects every representation the plugin can serve.
  • Also exposes /feed/ and /post-slug/feed/ as Markdown feeds for single posts and the main blog, with cache invalidation on post and comment changes.
  • Accepts a ?format=markdown query parameter and a .md URL suffix as alternatives to the Accept header.
  • Advertises the Markdown sibling on every HTML response — both as an HTTP Link header and as an HTML <link rel="alternate"> in the <head> — so RFC 8288-aware crawlers and HTML-parsing clients can discover it without sending Accept: text/markdown. See advertising .md siblings.
  • Otherwise, WordPress renders the theme as normal.

Install

composer require roots/post-content-to-markdown

Or download the latest release, place it in wp-content/plugins/post-content-to-markdown/, and activate via wp-admin or WP-CLI.

Configure

Out of the box, the plugin serves Markdown for the post type only. To include pages or custom post types, filter the list:

// Posts and pages
add_filter('post_content_to_markdown/post_types', function() {
    return ['post', 'page'];
});

See the repo for the full filter surface — customizing the converter, stripping shortcodes, handling attachments.

Verify

curl -sI -H "Accept: text/markdown" https://yoursite.com/hello-world/
# Content-Type: text/markdown; charset=utf-8
# Vary: Accept