Linux 软件免费装
Banner图

System Markdown Alternate

开发者 system4pc
更新时间 2026年9月15日 01:58
PHP版本: 7.4 及以上
WordPress版本: 7.1
版权: GPLv2 or later
版权网址: 版权信息

标签

markdown ai content discovery llm content negotiation

下载

0.51.0 0.49.4 0.43.0 0.52.0 0.45.1 0.44.0 0.53.0 0.53.1 0.35.3 0.36.0 0.39.0 0.45.0 0.46.0 0.47.0 0.48.0 0.38.0 0.49.0 0.49.1 0.49.2 0.35.4 0.37.0 0.42.0 0.47.1 0.49.3 0.50.0 0.50.1

详情介绍:

System Markdown Alternate publishes a clean, machine-readable Markdown representation of your content. Append .md to any supported permalink and you get YAML front matter plus the post body converted to Markdown — with marketing clutter, forms and navigation widgets stripped out. https://example.com/my-post/ → HTML https://example.com/my-post.md → Markdown (front matter + content) It is built for the era of AI assistants, agents and technical scrapers that prefer plain Markdown over rendered HTML. It is not a generic SEO plugin. Read the full documentation — installation, every setting in the panel, the endpoints, the shortcodes, the integrations and troubleshooting. Key features

安装:

  1. Upload the plugin to /wp-content/plugins/ or install it through the Plugins screen in WordPress.
  2. Activate the plugin.
  3. Go to Settings → Markdown Alternate and select at least one post type under Supported post types. Until you do, the plugin stays inactive.
  4. Visit any supported post and append .md to its URL.
No rewrite rules are added, so no permalink flush is required.

屏幕截图:

  • Settings — Markdown output: what stays out of the `.md`. Excluded shortcodes, blocks, CSS classes and builder elements (added to the built-in defaults), plus extra custom fields, custom taxonomies in the front matter and ACF fields.
  • Settings — Integrations: the `[sysmda_md_url]`, `[sysmda_md_download]` and `[sysmda_md_actions]` shortcodes, with the GenerateBlocks and ACF detection status.
  • Settings — Advanced: the `X-Robots-Tag` header, the opt-in LiteSpeed cache bypass rules and the `.md` hit counter, split bot vs human.
  • The `[sysmda_md_actions]` split button on the front end: copy the Markdown, view it in a new tab, or download it — no theme styling required.

升级注意事项:

0.53.1 Recommended for every site. Completes the 0.51.0 fix: the first request after a plugin update no longer tells a client that revalidates by date that its old copy of the Markdown is still current. Nothing to do after updating. 0.53.0 The /llms.txt endpoint is removed. If you had it enabled it stops being served after this update — generate that file with your SEO plugin instead, or another dedicated one. Everything else is unchanged: the .md URLs, negotiation, discovery links and shortcodes all keep working exactly as before, and no other setting is touched. 0.52.0 Recommended for sites building pages with Bricks templates: a page whose template references another template now picks up edits to that inner template immediately, instead of serving the previous Markdown for up to a day. Nothing to do after updating. 0.51.0 Recommended for every site. A plugin update now correctly invalidates cached Markdown for clients that revalidate by date, and the Last-Modified header is no longer sent when the plugin cannot back it — which stops a web server or CDN in front of WordPress from answering a revalidation with an outdated copy on its own. 0.50.1 Recommended for every site. A password on a synced pattern no longer leaks that pattern's text into the Markdown of the posts using it. Also fixes relative links carrying ../ inside a query or fragment, and definition lists whose pairs are wrapped in div elements (previously dropped from the output entirely). 0.50.0 /llms.txt now ships OFF on new installations. Existing sites keep whatever they have saved, so nothing changes for them. Only a site that never saved the settings page is affected — and it only notices if its content types come from the sysmda_markdown_supported_post_types filter; one tick in Settings - Markdown Alternate - llms.txt restores the endpoint. 0.8.0 The GenerateBlocks Dynamic Tag is now always available when GenerateBlocks is active; the enable/disable toggle was removed. No action required. 0.7.0 Integrations now appear only when ACF or GenerateBlocks are active. No action required.

常见问题:

Why is nothing served at the .md URL?

By default no post type is enabled. Open Settings → Markdown Alternate and tick at least one post type under Supported post types.

Which content does NOT get a .md version?

Anything the endpoint would not be able to serve honestly:

  • content types not enabled in the settings page;
  • drafts, pending and private content, and password-protected posts;
  • media attachments (always excluded);
  • posts with a non-standard post format — aside, status, quote, link, gallery, image, video, audio, chat. These are short snippets, usually untitled, with no editorial body worth serving as a document. Use the sysmda_markdown_excluded_post_formats filter to change that;
  • posts rendered by an unsupported page builder — Elementor, Divi, WPBakery, Oxygen, Beaver Builder or Breakdance. Their content is stored outside post_content, or stored in it as the builder's own layout shortcodes, so the Markdown would come out either empty or full of layout wrappers converted as prose. A 404 is the honest answer; use the sysmda_markdown_unsupported_builders filter if you would rather have the empty document. Bricks pages are supported and get a real .md, rendered through Bricks' own API — see the next question;
  • WooCommerce's cart, checkout and my-account pages. They are ordinary published pages, but their body without a shopping session is WooCommerce's own placeholder text, not anything written for a reader. The shop page is unaffected — that one is real content. Use the sysmda_markdown_excluded_woocommerce_pages filter to change that.
That last rule is decided per post, from the builder's own render mode. Activating a builder does not affect posts you did not build with it, and a post you switched back to the WordPress editor keeps its Markdown version even though the builder data is still stored. Nothing is read from the post content, so an article quoting [et_pb_section] in a code sample is not mistaken for a Divi page.

How does the Bricks .md work?

The .md is built by calling Bricks' own \Bricks\Frontend::render_data() on the page's stored element tree — the plugin never re-implements Bricks' elements. The existing md-exclude CSS class already works on any Bricks element (set it in the element's CSS Classes field); a new Excluded builder elements list under Settings → Markdown Alternate → Markdown output additionally strips Bricks chrome by default — forms, nav menus, share bars, tables of contents, breadcrumbs — the same way excluded CSS classes are stripped, and it only adds to that list, never replaces it. A page switched to Render with WordPress is served from post_content as usual, whether or not Bricks data is still stored on it. Markdown is also never served for URL variants of a post — its feed, its oEmbed view, its trackback endpoint, paged comments and the sub-pages of a post split with <!--nextpage--> — even with Accept: text/markdown. Only the canonical permalink and its .md URL return Markdown.

What does the Markdown output look like?

Each .md response is a UTF-8 document with a YAML front-matter block (title, URL, Markdown URL, published/modified dates, and — when available — author, featured image, categories, tags and a description), followed by the # Title heading and the post body converted to clean Markdown. The exact keys, their order and the escaping rules are documented as a stable contract, with conformance tests, in the Markdown output format reference.

Can I include my custom taxonomies?

Yes. Open Settings → Markdown Alternate → Markdown output and tick the ones you want under Custom taxonomies: the front matter then carries a taxonomies: block with their terms, sorted alphabetically. Categories and tags already have their own keys and are not repeated. Nothing is selected by default and nothing is ever added implicitly — a taxonomy registered by a plugin you install later shows up in the list unticked, so it cannot start publishing itself. Taxonomies used for editorial classification only, with no public term archive ("publicly queryable" off), are labelled as internal in the list: they are still selectable, but only on purpose. Developers can curate the list further with the sysmda_front_matter_taxonomy_slugs filter.

How do I exclude part of a post from the Markdown?

Add one of the CSS classes no-md, md-exclude or exclude-from-markdown to a block; the element (and its children) is removed from the Markdown output. You can customize the list with the sysmda_markdown_excluded_classes filter.

Does it affect my SEO?

The .md responses are sent with X-Robots-Tag: noindex, follow and a Link: rel="canonical" header pointing back to the HTML version, so search engines are told to prefer the original page.

How do I get the Markdown URL in a button or template?

Use the [sysmda_md_url] shortcode. If you run GenerateBlocks 2.x, the {{sysmda_md_url}} Dynamic Tag is available automatically — use it in element fields such as a Button URL. When the post has no .md, the tag resolves to an empty value so GenerateBlocks can hide the element instead of leaving a broken link.

How do I add Copy as Markdown actions for readers?

Use [sysmda_md_actions]. It renders a GitHub-style split button: the main action copies the complete Markdown document, while the dropdown offers Copy as Markdown, View as Markdown in a new tab and Download Markdown. Use [sysmda_md_actions id="123"] for a specific post. The component renders only where the shortcode is placed. Its small stylesheet and dependency-free script are loaded only on pages that actually render it, including placements in templates, widgets and secondary loops. The menu opens aligned to the button and drops below it, moving to the opposite side or above only when the screen edge leaves no room. Like the other shortcodes, it outputs nothing when the target post has no Markdown version.

How do I let readers download the .md instead of opening it?

Use the [sysmda_md_download] shortcode. It prints a link that saves the file: [sysmda_md_download] [sysmda_md_download text="Save the Markdown"] [sysmda_md_download id="123"] The link carries the HTML download attribute, which is what tells the browser to save the file instead of displaying it. The file name comes from the post slug. Nothing changes on the server side: the .md URL itself behaves exactly as it always has, so opening it directly still shows whatever your browser normally does with a Markdown file. The shortcode outputs a plain link with a single sysmda-md-download class, and the plugin loads no CSS and no JavaScript on your site for it. Any styling is your theme's job. Like [sysmda_md_url], it outputs nothing when the post has no Markdown version, so it can never produce a link to a 404.

Is the .md content cached?

Yes (default 24h). It uses a persistent object cache when one is available and falls back to transients otherwise. The cache is regenerated automatically when the post is edited, when the plugin is updated, or when you save the settings — and also when something outside the post changes what the Markdown says: a synced pattern, the featured image, the description, an ACF field, the author's display name, the permalink structure or the site address. That is the cache inside WordPress. Caches outside it — your browser, a page cache, Varnish, a CDN — are told Cache-Control: public, max-age=0, must-revalidate: they may keep a copy, but they must ask the site whether it is still current before serving it, and the answer is a small 304 Not Modified when nothing changed. So a .md cannot keep circulating after you edit the article, without depending on anyone purging it — which matters, because page caches purge the article's URL and do not know its .md version exists. If your infrastructure has its own purge mechanism and you would rather trade that guarantee for raw speed, the sysmda_cache_control filter lets you set a real lifetime.

Can I customize the plugin from my own code?

Yes: the plugin is developer-extensible through WordPress filters — which content is served, the HTTP headers, the caching, every stage of the conversion pipeline and the front matter can all be changed from a theme or a site plugin. A few examples: add_filter( 'sysmda_markdown_output', fn( $md, $post ) => $md . "\n---\nCustom footer.\n", 10, 2 ); add_filter( 'sysmda_markdown_excluded_classes', fn( $classes ) => array_merge( $classes, array( 'my-private-block' ) ) ); add_filter( 'sysmda_markdown_extra_meta_keys', fn( $keys ) => array_merge( $keys, array( 'my_field' ) ) ); Every filter, with its default value, what changing it does and how much compatibility it promises, is documented here: Developer extension API. Hooks are labelled Stable or Advanced: the Advanced ones are supported and documented, but may still evolve while the plugin is pre-1.0. The Markdown output format itself is a separate, stronger contract.

Content negotiation misbehaves behind LiteSpeed cache. What can I do?

Some LiteSpeed cache configurations key the page cache by URL only and ignore Vary: Accept, so a cached representation can be served regardless of the Accept header. The plugin already tells the cache not to store the negotiated Markdown; if requests for Markdown on the permalink still receive cached HTML, enable LiteSpeed cache compatibility in Settings → Markdown Alternate → Advanced: it adds .htaccess rules that make Markdown-negotiating requests bypass the LiteSpeed page cache (normal browser traffic stays cached; on other servers the rules are inert). Then purge the LiteSpeed cache. The explicit .md URLs are not affected and remain fully cacheable. Not sure whether your host is affected? Whether a LiteSpeed server honours Vary: Accept depends on the host and cannot be detected automatically, so if in doubt simply enable the option: it is the safe choice, and on hosts that already behave correctly the rules are just redundant. To test it yourself: open a post in a normal browser first (so its HTML gets cached), then request the same permalink with a Markdown Accept header, for example: curl -A "Mozilla/5.0" -H "Accept: text/markdown" https://example.com/my-post/ If the response is HTML (often with an x-litespeed-cache: hit header) instead of Markdown, your server ignores Vary: Accept and you need the option. The browser-like -A value matters: a WAF/CDN may block non-browser user agents.

Does it work behind a CDN (Cloudflare, Fastly, Varnish)?

The .md URLs need nothing from you. The negotiated permalink depends on your CDN, and the difference matters:

  • the dedicated .md URLs are their own cache key — one URL, one representation, nothing to mix up. Any CDN may store them, and Cache-Control: public, max-age=0, must-revalidate means it must revalidate before reuse, which is a cheap 304 Not Modified when nothing changed. This route works everywhere, with no configuration;
  • the negotiated permalink (Accept: text/markdown on the HTML page's own URL) is sent no-store, so a Markdown response is never stored and can never be handed to a browser that asked for HTML. That closes the harmful direction, but it cannot fix the opposite one: if your CDN caches the HTML page by URL and ignores Vary: Accept, a later Markdown request is answered at the edge, PHP never runs, and the client simply gets HTML. Vary: Accept is sent on every negotiable response, which is all a cache that honours it needs.
So for the negotiated route one of these has to be true: your CDN honours Vary: Accept, or you configure it to bypass the cache — or to vary its cache key — for requests whose Accept mentions text/markdown. On LiteSpeed the plugin ships that bypass for you: see the previous entry. If you are not sure which case you are in, the three-request test below tells you in a few seconds. And the .md URL keeps working regardless — it is what the rel="alternate" link advertises, so agents following it are unaffected. Two more things worth knowing. Some CDNs rewrite validators in transit — Cloudflare turns a strong ETag into a weak one — which the plugin handles: incoming validators are compared with the weak-comparison rules, so revalidation keeps working either way. And if you would rather have the CDN really cache the .md instead of revalidating it, set a lifetime with the sysmda_cache_control filter, keeping in mind that nothing purges a .md when you edit the post.

How do I check my cache is not mixing HTML and Markdown?

Send three requests to the same permalink, in this order, and compare the content-type of each: curl -sI -A "Mozilla/5.0" -H "Accept: text/markdown" https://example.com/my-post/ curl -sI -A "Mozilla/5.0" -H "Accept: text/html" https://example.com/my-post/ curl -sI -A "Mozilla/5.0" -H "Accept: text/markdown" https://example.com/my-post/ The first and third must answer text/markdown, the second text/html. If the second returns Markdown, or the third returns HTML, something in front of PHP is serving one stored representation to everyone: look at the age, x-cache, cf-cache-status or x-litespeed-cache headers to see which layer, and purge it (on LiteSpeed, see the entry above). To check revalidation on a .md URL, read its etag and send it back: curl -sI -A "Mozilla/5.0" https://example.com/my-post.md curl -sI -A "Mozilla/5.0" -H 'If-None-Match: W/"paste-the-etag-here"' https://example.com/my-post.md The second request should answer 304 with no body. A 200 instead is usually not the plugin: some stacks strip conditional headers from the request before PHP ever sees them (observed with nginx configured to cache the location). It is a missed optimisation, not a correctness problem — the response is still current. As above, the browser-like -A value matters: a WAF/CDN may block non-browser user agents outright, and a block page is easy to mistake for a plugin bug.

更新日志:

0.53.1 0.53.0 0.52.0 View the full changelog