PHPackages                             illodev/markdown-negotiation-for-agents - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. illodev/markdown-negotiation-for-agents

ActiveWordpress-plugin[Parsing &amp; Serialization](/categories/parsing)

illodev/markdown-negotiation-for-agents
=======================================

Content negotiation plugin for WordPress that serves Markdown to AI agents and tools via Accept header.

v1.0.1(4mo ago)20GPL-2.0-or-laterPHPPHP &gt;=8.1

Since Feb 24Pushed 4mo agoCompare

[ Source](https://github.com/illodev/markdown-negotiation-for-agents)[ Packagist](https://packagist.org/packages/illodev/markdown-negotiation-for-agents)[ Docs](https://github.com/illodev/markdown-negotiation-for-agents)[ GitHub Sponsors](https://github.com/illodev)[ RSS](/packages/illodev-markdown-negotiation-for-agents/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (16)Versions (4)Used By (0)

Markdown Negotiation for Agents
===============================

[](#markdown-negotiation-for-agents)

[![License: GPL v2](https://camo.githubusercontent.com/34fd4798bfe47593a94283d1d4fb5c522738d07b84c13f374f10485c0e0ffbbf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d47504c76322d626c75652e737667)](https://www.gnu.org/licenses/gpl-2.0)[![PHP Version](https://camo.githubusercontent.com/c0761d101b201f2531c8037e6264420e2e43705d3776a9fcfb70c8cf3d3563a3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d3737374242342e737667)](https://php.net)[![WordPress](https://camo.githubusercontent.com/9579d70cb10fb0826954832375d2776e7b5a1bef8a065d051734ef2370cd5934/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f576f726450726573732d362e302532422d3231373539422e737667)](https://wordpress.org)

**Serve your WordPress content as Markdown via HTTP content negotiation.** Ideal for AI agents, LLMs, developer tools, and any client that prefers Markdown over HTML.

Inspired by [Cloudflare's Markdown for Agents](https://blog.cloudflare.com/markdown-for-agents), but implemented at the application level within WordPress.

---

How It Works
------------

[](#how-it-works)

When a client sends a request with `Accept: text/markdown`, the plugin intercepts WordPress's template loading and responds with clean Markdown instead of HTML. The URL stays the same — this is real HTTP content negotiation.

```
# Standard browser request
GET /my-awesome-post HTTP/1.1
Accept: text/html
→ Returns: Normal HTML page

# AI agent request
GET /my-awesome-post HTTP/1.1
Accept: text/markdown
→ Returns: Clean Markdown content

```

### Response Headers

[](#response-headers)

```
Content-Type: text/markdown; charset=utf-8
Vary: Accept
X-Markdown-Source: wordpress-plugin
X-Markdown-Tokens: 1234
X-Markdown-Plugin-Version: 1.0.0
Cache-Control: public, max-age=300, s-maxage=3600

```

---

Features
--------

[](#features)

- **Real Content Negotiation** — `Accept: text/markdown` and `text/x-markdown`
- **Alternative Access** — `?format=markdown` query parameter, `.md` URL extension
- **Gutenberg Support** — Full block processing (headings, lists, tables, code, images, embeds, columns)
- **WooCommerce** — Product details, pricing, attributes, stock status
- **REST API** — `/wp-json/jetstaa-mna/v1/markdown/` endpoint + `markdown` field on post responses
- **WP-CLI** — `wp markdown generate`, `wp markdown convert`, `wp markdown cache`
- **Intelligent Caching** — Object cache, transients, or file-based. Auto-invalidation on post save
- **Security** — Rate limiting, sanitization, no private data leakage
- **Multisite** — Network activation support
- **SEO Safe** — Proper `Vary: Accept` headers, `` tags
- **Token Estimation** — `X-Markdown-Tokens` header for LLM context planning

---

Requirements
------------

[](#requirements)

- PHP 8.1 or higher
- WordPress 6.0 or higher
- Composer (for autoloading and dependencies)

---

Installation
------------

[](#installation)

### From Source

[](#from-source)

```
cd wp-content/plugins/
git clone https://github.com/illodev/markdown-negotiation-for-agents.git
cd markdown-negotiation-for-agents
composer install --no-dev --optimize-autoloader
```

### Via Composer (as dependency)

[](#via-composer-as-dependency)

```
composer require illodev/markdown-negotiation-for-agents
```

Then activate in WordPress admin or via WP-CLI:

```
wp plugin activate markdown-negotiation-for-agents
```

---

Configuration
-------------

[](#configuration)

Navigate to **Settings → Markdown Negotiation** in WordPress admin.

SettingDescriptionDefaultEnable Content NegotiationRespond to Accept: text/markdown✅Enable .md ExtensionAccess via /post-slug.md❌Enable ?format=markdownAccess via query parameter✅Post TypesWhich CPTs to enablepost, pageWooCommerce ProductsInclude product data✅REST API Markdown/wp-json endpoint &amp; field✅Token Count HeaderX-Markdown-Tokens header✅Cache EnabledCache converted Markdown✅Cache Driverauto, object, transient, fileautoCache TTLSeconds to cache3600Rate LimitingLimit requests per IP❌---

Usage
-----

[](#usage)

### Content Negotiation (Primary)

[](#content-negotiation-primary)

```
curl -H "Accept: text/markdown" https://example.com/my-post/
```

### Query Parameter

[](#query-parameter)

```
curl https://example.com/my-post/?format=markdown
```

### .md Extension (requires activation)

[](#md-extension-requires-activation)

```
curl https://example.com/my-post.md
```

### REST API

[](#rest-api)

```
# Dedicated endpoint
curl https://example.com/wp-json/jetstaa-mna/v1/markdown/42

# Standard REST with markdown field
curl https://example.com/wp-json/wp/v2/posts/42?_format=markdown

# List available posts
curl https://example.com/wp-json/jetstaa-mna/v1/markdown?post_type=post

# Plugin status
curl https://example.com/wp-json/jetstaa-mna/v1/status
```

### WP-CLI

[](#wp-cli)

```
# Convert a specific post
wp markdown convert 42

# Generate and cache all posts
wp markdown generate --all

# Generate specific post types
wp markdown generate --all --post_type=page

# Export to files
wp markdown generate --all --output=file --dir=/tmp/markdown-export

# Flush cache
wp markdown cache flush

# Show status
wp markdown status
```

---

Hooks &amp; Filters Reference
-----------------------------

[](#hooks--filters-reference)

### Filters

[](#filters)

FilterDescriptionParameters`jetstaa_mna_settings`Modify plugin settings at runtime`array $settings``jetstaa_mna_accept_header`Override the Accept header value`string $accept``jetstaa_mna_allowed_post_types`Modify allowed post types`array $types, WP_Post $post``jetstaa_mna_skip_block`Skip specific Gutenberg blocks`bool $skip, string $name, array $block``jetstaa_mna_block_html`Filter block HTML before conversion`string $html, string $name, array $block``jetstaa_mna_extracted_html`Filter extracted HTML`string $html, WP_Post $post, array $options``jetstaa_mna_converted_markdown`Filter final Markdown output`string $md, string $html, array $opts, ?WP_Post``jetstaa_mna_response_markdown`Filter Markdown before HTTP response`string $md, WP_Post $post, string $media_type``jetstaa_mna_sanitized_html`Filter sanitized HTML`string $html``jetstaa_mna_sanitized_markdown`Filter sanitized Markdown`string $markdown``jetstaa_mna_cache_key`Modify cache keys`string $key, int $post_id, string $suffix``jetstaa_mna_strip_shortcodes`Modify list of shortcodes to strip`array $shortcodes``jetstaa_mna_can_access`Override access control`bool $can_access, WP_Post $post``jetstaa_mna_trusted_proxy_headers`Override trusted proxy headers for IP`array $headers`### Actions

[](#actions)

ActionDescriptionParameters`jetstaa_mna_initialized`Plugin fully initialized`Plugin $plugin``jetstaa_mna_services_registered`After DI container setup`Container $container, Plugin $plugin``jetstaa_mna_configure_converter`Configure the HTML converter`HtmlConverter $converter``jetstaa_mna_send_headers`After response headers sent`WP_Post $post, string $markdown``jetstaa_mna_cache_invalidated`After post cache invalidated`int $post_id``jetstaa_mna_cache_flushed`After full cache flush—---

Architecture
------------

[](#architecture)

```
src/
├── Contracts/
│   ├── CacheInterface.php          # Cache driver contract
│   ├── ConverterInterface.php      # HTML→Markdown converter contract
│   ├── NegotiatorInterface.php     # Content negotiation contract
│   └── SanitizerInterface.php      # Content sanitization contract
├── Admin/
│   ├── MetaBox.php                 # Per-post controls
│   ├── SettingsPage.php            # Admin settings UI
│   └── SettingsRegistrar.php       # WordPress Settings API integration
├── Cache/
│   ├── CacheManager.php            # Cache orchestrator + invalidation
│   ├── FileCacheDriver.php         # File-based cache
│   ├── ObjectCacheDriver.php       # WP object cache (Redis/Memcached)
│   └── TransientDriver.php         # WP transients (database)
├── Cli/
│   └── MarkdownCommand.php         # WP-CLI commands
├── Converter/
│   ├── ContentExtractor.php        # Post content extraction
│   ├── GutenbergProcessor.php      # Block processing
│   ├── MarkdownConverter.php       # league/html-to-markdown wrapper
│   └── ShortcodeProcessor.php      # Shortcode handling
├── Http/
│   ├── AlternateEndpoint.php       # .md and ?format= handlers
│   ├── ContentNegotiator.php       # RFC 7231 Accept header parsing
│   ├── HeaderValidator.php         # Header security validation
│   └── ResponseHandler.php         # Markdown HTTP response
├── Multisite/
│   └── NetworkHandler.php          # Multisite support
├── Rest/
│   ├── FieldRegistrar.php          # REST API field
│   └── MarkdownController.php      # REST API endpoints
├── Security/
│   ├── AccessControl.php           # Post access enforcement
│   ├── RateLimiter.php             # IP-based rate limiting
│   └── Sanitizer.php               # HTML/Markdown sanitization
├── Container.php                   # Lightweight DI container
└── Plugin.php                      # Main orchestrator (singleton)

```

### Design Principles

[](#design-principles)

- **PSR-4** autoloading via Composer
- **Dependency Injection** via lightweight container
- **Interfaces** for all swappable components (SOLID)
- **Strict types** throughout
- **No global functions** (except bootstrap in main file)
- **WordPress Coding Standards** compatible

---

Cache Compatibility Guide
-------------------------

[](#cache-compatibility-guide)

### Vary: Accept Header

[](#vary-accept-header)

The plugin adds `Vary: Accept` to all responses. This instructs caches to maintain separate cached copies based on the Accept header.

### Plugin Caches

[](#plugin-caches)

Cache PluginCompatibleNotesWP Super Cache✅Varies by Accept header automaticallyW3 Total Cache✅Enable "Vary" header supportLiteSpeed Cache✅Add `Vary: Accept` to cache settingsWP Rocket✅Works out of the box### CDN / Edge Caches

[](#cdn--edge-caches)

CDNCompatibleNotesCloudflare✅Respects Vary headers. Consider Cache Rules for markdownFastly✅Full Vary supportCloudFront⚠️Must whitelist Accept header in cache policyVarnish✅Varies automatically on Accept**Important:** If your CDN does not vary on Accept by default, Markdown responses may be served to HTML clients. Configure your CDN to include `Accept` in its cache key.

---

SEO &amp; AI Considerations
---------------------------

[](#seo--ai-considerations)

### Search Engines

[](#search-engines)

- **No duplicate content risk** — Same URL serves different formats based on Accept header
- **Vary: Accept** — Tells search engines content varies by request headers
- **``** — HTML pages include a link to the Markdown representation
- **Link header** — HTTP `Link: ; rel="alternate"; type="text/markdown"` header

### AI Agent Discovery

[](#ai-agent-discovery)

AI agents can discover Markdown availability via:

1. **Link header** in HTTP responses
2. **``** in HTML ``
3. **REST API** `/wp-json/jetstaa-mna/v1/status` endpoint
4. **Content negotiation** — Simply request with `Accept: text/markdown`

The plugin does **not** use User-Agent sniffing to detect AI agents. This is intentional — content negotiation is the correct HTTP mechanism for format selection.

---

Security
--------

[](#security)

### Threat Model

[](#threat-model)

VectorMitigationHeader spoofingStrict Accept header validation, length limitsCache poisoning`Vary: Accept` header on all responsesXSS via MarkdownHTML/JS stripped before conversion, output sanitizedData leakagePrivate/draft/password-protected posts excludedAbuse/scrapingOptional rate limiting per IPPer-post controlDisable Markdown per post via meta box---

Performance
-----------

[](#performance)

### TTFB Impact

[](#ttfb-impact)

- **First request:** ~5-20ms overhead for HTML→Markdown conversion (depends on content size)
- **Cached request:** &lt;1ms overhead (object cache) or ~2ms (transient)
- **File cache:** ~1ms overhead

### Scalability for 100k+ Posts

[](#scalability-for-100k-posts)

- Cache is per-post-ID, not global
- Invalidation is targeted (only affected post)
- Object cache recommended for high-traffic sites
- Background generation via WP-CLI: `wp markdown generate --all`

### Moving to Background Processing

[](#moving-to-background-processing)

For enterprise sites, pre-generate Markdown on post save:

```
add_action( 'save_post', function( int $post_id ): void {
    // Schedule async generation.
    wp_schedule_single_event( time(), 'jetstaa_mna_generate_post', [ $post_id ] );
}, 20 );
```

---

Development
-----------

[](#development)

```
# Install dependencies
composer install

# Run tests
composer test

# Run unit tests only
composer test:unit

# Run PHPCS
composer phpcs

# Fix coding standards
composer phpcbf
```

---

Changelog
---------

[](#changelog)

### 1.0.0 (2026-02-24)

[](#100-2026-02-24)

- Initial release
- HTTP content negotiation (Accept: text/markdown, text/x-markdown)
- Gutenberg block processing
- WooCommerce product support
- REST API endpoint and field
- WP-CLI commands
- Multi-driver caching (object cache, transients, file)
- Rate limiting
- Multisite support
- Per-post disable control
- Comprehensive sanitization

---

Roadmap
-------

[](#roadmap)

- llms.txt endpoint generation
- Sitemap for Markdown URLs
- Background async conversion on post save
- Edge Worker integration examples (Cloudflare Workers, Lambda@Edge)
- Pro version: API key authentication, analytics, custom templates
- OpenAPI/MCP schema endpoint
- Markdown template customization
- Bulk export to static site generator formats

---

License
-------

[](#license)

GPL-2.0-or-later. See [LICENSE](LICENSE) for details.

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance77

Regular maintenance activity

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

2

Last Release

126d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/894b56d207d5574ee46cd328696b60c95c3dfafad535385464b49db484abe55f?d=identicon)[illodev](/maintainers/illodev)

---

Top Contributors

[![illodev](https://avatars.githubusercontent.com/u/55558169?v=4)](https://github.com/illodev "illodev (17 commits)")

---

Tags

accept-headerai-agentscontent-negotiationgutenberghtml-to-markdownhttp-headersllmmarkdownphprest-apiwoocommercewordpresswordpress-pluginwp-cliwordpressaimarkdownwordpress pluginREST APIcontent negotiationllm

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/illodev-markdown-negotiation-for-agents/health.svg)

```
[![Health](https://phpackages.com/badges/illodev-markdown-negotiation-for-agents/health.svg)](https://phpackages.com/packages/illodev-markdown-negotiation-for-agents)
```

###  Alternatives

[spatie/laravel-markdown-response

Serve markdown versions of your HTML pages to AI agents and bots

7655.9k6](/packages/spatie-laravel-markdown-response)[terrylinooo/githuber-md

An all-in-one WordPress Markdown plugin.

6892.1k](/packages/terrylinooo-githuber-md)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
