llms.txt on WordPress
WordPress routes every unknown URL through index.php, which is why an uploaded llms.txt can return your 404 template with a 200 status. Three ways to serve it, and how to tell which one your host allows.
WordPress hands every request that is not an existing file to index.php. A real file at the web root wins; anything else needs a rewrite rule.
Serving /llms.txt from WordPress.
Upload a real file to the web root
The simplest approach and the one that survives plugin changes. Put llms.txt in the same directory as wp-config.php - usually public_html or www - over SFTP or your host's file manager. Apache and nginx both serve an existing file before WordPress is consulted, so no rewrite is involved.
public_html/
wp-admin/
wp-content/
wp-includes/
index.php
wp-config.php
llms.txt ← here, beside wp-config.phpOr generate it from your content with a small snippet
If you want the file to track your published pages, register a rewrite rule and render it from a query var. This is the same mechanism WordPress uses for its own feeds. Add it to a site-specific plugin rather than functions.php so a theme update cannot remove it.
<?php
/* Plugin Name: Acme llms.txt */
add_action('init', function () {
add_rewrite_rule('^llms\.txt$', 'index.php?acme_llms_txt=1', 'top');
});
add_filter('query_vars', function ($vars) {
$vars[] = 'acme_llms_txt';
return $vars;
});
add_action('template_redirect', function () {
if (!get_query_var('acme_llms_txt')) {
return;
}
header('Content-Type: text/plain; charset=utf-8');
echo "# " . get_bloginfo('name') . "\n\n";
echo "> " . get_bloginfo('description') . "\n\n";
echo "## Pages\n\n";
foreach (get_pages() as $page) {
printf("- [%s](%s)\n", $page->post_title, get_permalink($page));
}
exit; // Without this, WordPress carries on and appends your theme.
});Flush rewrite rules once, then never again
A new rewrite rule does nothing until WordPress rebuilds its rules cache. Visit Settings → Permalinks and save - that is the flush. Do not call flush_rewrite_rules() on every init; it is an expensive write on every page load and a well-known way to slow a site down.
What WordPress gets wrong.
The failures below are specific to WordPress. A generic llms.txt guide will not mention any of them.
Your 404 page is being served with a 200 status
The WordPress-specific trap. If the file is not where the web server looks, the request reaches index.php, WordPress finds no matching post, and some themes and security plugins render the 404 template with a 200 status instead of a 404. A checker sees a 200 and a body, and reports a malformed llms.txt. Check the status code, not just that "something loads".
curl -sI https://example.com/llms.txt | head -1
# HTTP/2 200 with an HTML body → WordPress answered, not your fileA caching plugin is serving a stale copy
WP Rocket, W3 Total Cache, LiteSpeed Cache and host-level page caches all cache by URL, including this one. After adding or editing the file, purge the cache - otherwise you spend an afternoon debugging a file that was correct twenty minutes ago.
The file is in wp-content/ instead of the web root
A common misread of upload instructions. wp-content/llms.txt is served at /wp-content/llms.txt, which is not where anything looks. The file must be at the root of the domain.
A multisite install resolves the root differently
On WordPress multisite, the physical web root belongs to the network, not to an individual site. A file dropped there appears on every site in the network at once, and a subsite cannot serve its own. Use the rewrite rule approach on multisite and switch on get_current_blog_id().
Next to read.
Questions, answered.
Do I need a plugin to add llms.txt to WordPress?
Where exactly is the WordPress web root?
Why does my WordPress llms.txt show my site's 404 page?
Will Yoast or Rank Math generate an llms.txt for me?
An llms.txt will not fix a site AI cannot read.
Before writing an index for AI clients, check that they can fetch your pages at all. LintPage runs 60 checks against a URL in about 30 seconds - free, no signup.
run a full scan →