> Articolo disponibile anche su **Roots**, scritto da Ben Word. Versione in inglese su [roots.io/serve-your-wordpress-posts-as-markdown](https://roots.io/serve-your-wordpress-posts-as-markdown/).

Gli LLM e gli agenti AI lavorano meglio con Markdown rispetto all'HTML renderizzato, perché consumano meno token e non devono estrapolare il contenuto dal markup. Il plugin [`roots/post-content-to-markdown`](https://github.com/roots/post-content-to-markdown) aggiunge una rappresentazione Markdown a qualsiasi sito WordPress, senza un'API dedicata o una _route_ separata da gestire.

Su Roots era già stato spiegato che [diversi plugin SEO dicono di servire "Markdown per l'AI" ma in realtà ignorano del tutto l'header `Accept`,](https://roots.io/some-seo-plugins-claim-markdown-for-ai-but-ignore-the-accept-header/) e finiscono per rispondere sempre in HTML, anche a chi sta chiedendo esplicitamente Markdown. **Post Content to Markdown** invece gestisce le risposte nel modo giusto: content negotiation, conversione dei blocchi, header `Link` e tag `<link>` in `<head>`, in modo che anche gli LLM che non inviano `Accept: text/markdown` possano comunque trovare la versione Markdown.

> **Il tuo sito WordPress è pronto per l'AI?**
> Verifica qualsiasi URL con [acceptmarkdown.com](https://acceptmarkdown.com/): ti dice cosa manca per agenti e LLM, con i link alle guide collegate. Su [acceptmarkdown.com/status](https://acceptmarkdown.com/status) trovi come si comportano oggi i principali agenti AI.

## Cosa fa

Il plugin assegna a ogni post e a ogni feed una versione Markdown che i client possono richiedere in tre modi diversi:

- Un header di richiesta `Accept: text/markdown`, ideale per agenti e script
- Un parametro in query string `?format=markdown`
- Un suffisso `.md` aggiunto all'URL, per esempio `/hello-world.md`. La versione HTML del post espone questo URL sia tramite un header di risposta `Link: rel="alternate"; type="text/markdown"`, sia con un tag `<link>` corrispondente in `<head>`, così gli agenti che [non supportano ancora l'header `Accept: text/markdown`](https://acceptmarkdown.com/status) possono raggiungere comunque la versione Markdown seguendo quel link.

Ecco lo stesso post `Hello world!` in due forme diverse:

```bash
$ curl https://example.com/hello-world/
<html lang="it-IT">…2.400 righe di markup del tema…</html>

$ curl -H "Accept: text/markdown" https://example.com/hello-world/
# Hello world!

Benvenuto in WordPress. Questo è il tuo primo articolo. Modificalo o eliminalo, poi inizia a scrivere.
```

## La conversione non perde i contenuti

- Esegue prima il rendering dei blocchi Gutenberg e solo dopo converte, così blocchi dinamici, _embed_ e tabelle finiscono nel Markdown senza perdere pezzi per strada
- Rimuove il markup aggiunto dagli highlighter di sintassi (Prism, highlight.js, ecc.), così i blocchi di codice arrivano belli puliti, senza il "rumore" prodotto dai tag HTML tipo `<span class="token …">`
- Salva il risultato della conversione nell'object cache (Redis/Memcached) usando un hash del contenuto come chiave: le richieste successive non rifanno il rendering dei blocchi, non espandono gli _shortcode_ e non rieseguono il passaggio HTML → Markdown, ma leggono direttamente dalla cache

## Feed e commenti

La stessa _content negotiation_ funziona anche sui feed:

- `/feed/markdown/` è un feed Markdown dedicato, con metadati del sito, titoli dei post, autori, date, categorie, tag e contenuto completo
- `/feed/` con `Accept: text/markdown` restituisce il feed principale in Markdown
- `/post-slug/feed/` con `Accept: text/markdown` restituisce il post con tutti i suoi commenti

Il feed Markdown viene anche esposto nel feed RSS, tramite un `<atom:link rel="alternate" type="text/markdown">`. In questo modo feed reader e agenti riescono a trovarlo da soli, senza bisogno di sapere dove cercare.

## Filtri

I filtri coprono i casi più comuni:

- `post_content_to_markdown/post_types` permette di estendere la conversione a pagine o custom post type (di default: `['post']`)
- `post_content_to_markdown/post_allowed` è una _allowlist_ per singolo post, applicata dopo il controllo sul post type
- `post_content_to_markdown/converter_options` configura lo stile degli header, gli _hard break_ e i nodi da rimuovere
- `post_content_to_markdown/conversion_cache_duration` permette di abbassare la durata della cache (TTL) se hai blocchi che variano in base alla richiesta
- `post_content_to_markdown/markdown_output` esegue una passata finale sul Markdown già convertito, fuori dalla cache, a ogni richiesta. È il punto in cui inserire personalizzazioni _per-request_ senza dover invalidare le voci in cache.

Nel README trovi la [lista completa](https://github.com/roots/post-content-to-markdown#filters) dei filtri disponibili.

## Content negotiation conforme agli standard

Molti plugin che promettono di gestire "Markdown per l'AI" trascurano i dettagli HTTP. Post Content to Markdown invece segue alla lettera la [RFC 9110 §12.5.1](https://www.rfc-editor.org/rfc/rfc9110#name-proactive-negotiation):

- interpreta correttamente i q-value: una richiesta del tipo `Accept: text/html;q=0.9, text/markdown;q=1.0` riceve correttamente il Markdown
- ogni risposta del front-end include `Vary: Accept`, così browser, proxy e CDN tengono conto dell'header Accept e non finiscono per restituire HTML a un client che ha chiesto Markdown
- quando l'header `Accept` del client esclude tutte le rappresentazioni che il sito può fornire, viene restituito un `406 Not Acceptable`, invece di ripiegare silenziosamente sull'HTML
- ogni risposta in Markdown espone un header `X-Markdown-Source: accept | md-url | query`, così dai log di accesso capisci in che modo i client stanno richiedendo il Markdown
- le risposte agli URL `.md` aggiungono `X-Robots-Tag: noindex, nofollow`, così i motori di ricerca non indicizzano l'alias Markdown affiancandolo alla pagina HTML canonica

## Release recenti

Alcune novità recenti del plugin:

- **v1.3** ([\#5](https://github.com/roots/post-content-to-markdown/pull/5)) esegue il rendering dei blocchi Gutenberg prima della conversione e gestisce correttamente le tabelle
- **v1.5** ([\#8](https://github.com/roots/post-content-to-markdown/pull/8), [\#9](https://github.com/roots/post-content-to-markdown/pull/9)) allinea la content negotiation alla specifica: parsing dei q-value, `Vary: Accept` e `406 Not Acceptable`
- **v1.6** ([\#11](https://github.com/roots/post-content-to-markdown/pull/11)) introduce il suffisso `.md` con annuncio via header `Link` e tag `<link>`
- **v1.7** ([\#12](https://github.com/roots/post-content-to-markdown/pull/12)) aggiunge la memoization su object cache, l'autodiscovery `<atom:link>` nel feed RSS e l'header di risposta `X-Markdown-Source`

La storia completa è su [GitHub](https://github.com/roots/post-content-to-markdown/releases).

## Come installare il plugin

```
composer require roots/post-content-to-markdown
```

Il sorgente è su [GitHub](https://github.com/roots/post-content-to-markdown): _issue_ e _pull request_ sono benvenuti.
