| 开发者 | gregrandall |
|---|---|
| 更新时间 | 2026年2月27日 05:19 |
| PHP版本: | 8.2 及以上 |
| WordPress版本: | 6.9 |
| 版权: | GPL-2.0-only |
| 版权网址: | 版权信息 |
.md suffix: append .md to any post or page URL (e.g. example.com/my-post.md)?format=markdown to any post or page URLAccept: text/markdown in the request headerContent-Type: text/markdown and Vary: Accept response headersContent-Signal header for AI signal declaration — defaults to ai-train=no, search=yes, ai-input=yes — see contentsignals.orgX-Markdown-Tokens header with estimated token count<link rel="alternate"> in the HTML head and Link HTTP headerinit hook, before the main database query runs. No extra configuration needed.
Add a web server rewrite rule and Botkibble bypasses PHP entirely, serving .md files the same way a server would serve an image or CSS file:
| Method | Avg. response time |
|---|---|
| Standard HTML | 0.97s |
| Markdown (cold, first request) | 0.95s |
| Markdown (cached, PHP Fast-Path) | 0.87s |
| Markdown (Nginx/Apache direct) | 0.11s |
Serving directly from disk is 88% faster than a full WordPress page load. See the Performance section below for Nginx and Apache configuration.
Security:
403 ForbiddenX-Robots-Tag: noindex keeps Markdown versions out of search resultsLink: rel="canonical" points search engines back to the HTML version?botkibble_variant=slim (or any other variant name).
Variant caches are stored under:
/wp-content/uploads/botkibble/_v//.md
What it does NOT do:
botkibble directory to wp-content/plugins/.composer install inside the plugin directory to install dependencies.The plugin only serves posts and pages by default. To add a custom post type, use the botkibble_served_post_types filter in your theme or a custom plugin:
add_filter( 'botkibble_served_post_types', function ( $types ) {
$types[] = 'docs';
return $types;
} );
Be careful. Only add post types that contain public content. Do not expose post types that may contain private or sensitive data (e.g. WooCommerce orders).
Every response starts with a YAML block containing:
title — the post titledate — publish date in ISO 8601 formattype — post type (e.g. post, page)word_count — word count of the Markdown bodychar_count — character count of the Markdown bodytokens — estimated token count (word_count × 1.3)categories — array of category names (posts only)tags — array of tag names (posts only, omitted if none)Use the botkibble_frontmatter filter:
add_filter( 'botkibble_frontmatter', function ( $data, $post ) {
$data['excerpt'] = get_the_excerpt( $post );
return $data;
}, 10, 2 );
Use the botkibble_content_signal filter:
add_filter( 'botkibble_content_signal', function ( $signal, $post ) {
return 'ai-train=no, search=yes, ai-input=yes';
}, 10, 2 );
Return an empty string to omit the header entirely.
Yes, use the botkibble_token_multiplier filter. The default multiplier of 1.3 (word count × 1.3) comes from Cloudflare's implementation:
add_filter( 'botkibble_token_multiplier', function () {
return 1.5; // Adjusted for a different model's tokenizer
} );
Cache misses (when a post needs to be converted) are limited to 20 per minute globally. You can change this with the botkibble_regen_rate_limit filter:
add_filter( 'botkibble_regen_rate_limit', function () {
return 50;
} );
Yes, use the botkibble_clean_html filter. This runs after the default cleanup and before conversion:
add_filter( 'botkibble_clean_html', function ( $html ) {
// Remove a plugin's wrapper divs
$html = preg_replace( '/
(.*?)<\/div>/s', '$1', $html );
return $html;
} );
Yes. Botkibble keeps converter node removal disabled by default (for backward compatibility), but you can opt in with botkibble_converter_remove_nodes:
add_filter( 'botkibble_converter_remove_nodes', function ( $nodes ) {
$nodes = is_array( $nodes ) ? $nodes : [];
$nodes[] = 'script';
return $nodes;
} );
If you also need application/ld+json, extract it in botkibble_clean_html first, then let converter-level script removal clean up any remaining script tags.
Use the botkibble_body filter. This is the best place to add content like ld+json that you want included in the word count and token estimation:
add_filter( 'botkibble_body', function ( $body, $post ) {
$json_ld = '...';
return $body . "\n\n" . $json_ld;
}, 10, 2 );
Use the botkibble_output filter to append or modify the text after conversion:
add_filter( 'botkibble_output', function ( $markdown, $post ) {
return $markdown . "\n\n---\nServed by Botkibble";
}, 10, 2 );
Yes. Add ?botkibble_variant=slim when requesting Markdown to generate and serve a separate cached file. To ensure your variants are invalidated on post updates, return them from the botkibble_cache_variants filter:
add_filter( 'botkibble_cache_variants', function ( $variants, $post ) {
$variants[] = 'slim';
return $variants;
}, 10, 2 );
Yes, if you only want to serve Markdown via explicit URLs (.md or ?format=markdown), use the botkibble_enable_accept_header filter:
add_filter( 'botkibble_enable_accept_header', '__return_false' );
It works with the most common structures (post name, page hierarchy). Complex date-based permalink structures may require the query parameter or Accept header method instead.
They return a 403 Forbidden response. There's no point serving a password form to a bot.
Content-Type: text/markdown; charset=utf-8Vary: Accept — tells caches that responses vary by Accept headerX-Markdown-Tokens: <count> — estimated token count (word_count × 1.3)X-Robots-Tag: noindex — prevents search engines from indexing the Markdown versionLink: <url>; rel="canonical" — points search engines to the original HTML postLink: <url>; rel="alternate" — advertises the Markdown version for discoveryContent-Signal: ai-train=no, search=yes, ai-input=yes — see contentsignals.org