<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Serhii Pylypenko</title>
    <description>The latest articles on DEV Community by Serhii Pylypenko (@pylypenko).</description>
    <link>https://dev.to/pylypenko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3577651%2Fff0c1db8-bfdb-4c41-b408-02224ac52145.jpg</url>
      <title>DEV Community: Serhii Pylypenko</title>
      <link>https://dev.to/pylypenko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pylypenko"/>
    <language>en</language>
    <item>
      <title>Serving llms.txt from a Dockerized WordPress + Nginx Setup</title>
      <dc:creator>Serhii Pylypenko</dc:creator>
      <pubDate>Fri, 06 Mar 2026 09:21:50 +0000</pubDate>
      <link>https://dev.to/pylypenko/serving-llmstxt-from-a-dockerized-wordpress-nginx-setup-2ka2</link>
      <guid>https://dev.to/pylypenko/serving-llmstxt-from-a-dockerized-wordpress-nginx-setup-2ka2</guid>
      <description>&lt;p&gt;If you're running WordPress in Docker with Nginx and PHP-FPM in &lt;strong&gt;separate containers&lt;/strong&gt;, you've probably hit this kind of problem before: a plugin generates a file inside the WordPress container, but Nginx can't see it because the filesystems are isolated.&lt;/p&gt;

&lt;p&gt;That's exactly what happened when I tried to enable &lt;code&gt;llms.txt&lt;/code&gt; support via AIOSEO on a typical Dockerized WordPress setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is a new standard (similar to &lt;code&gt;robots.txt&lt;/code&gt;) that helps LLMs understand and index your site's content. AIOSEO generates it automatically — and so does Yoast SEO. Both plugins follow the same pattern: they write a physical file to the WordPress root directory. In a standard single-server setup, this works fine. In Docker, it doesn't.&lt;/p&gt;

&lt;p&gt;Here's the catch:&lt;/p&gt;

&lt;p&gt;A typical Dockerized WordPress setup looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nginx container&lt;/strong&gt; — handles all incoming HTTP requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WordPress (PHP-FPM) container&lt;/strong&gt; — runs the application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;/var/www/html&lt;/code&gt; directory is &lt;strong&gt;not a shared volume&lt;/strong&gt; between them. This is intentional — keeping code immutable and containers isolated is good practice. But it means when AIOSEO writes &lt;code&gt;llms.txt&lt;/code&gt; into the WordPress container's filesystem, Nginx simply can't find it and returns a 404.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: PHP Bridge Pattern
&lt;/h2&gt;

&lt;p&gt;Instead of adding a shared volume (which would compromise the immutability design), I used a &lt;strong&gt;PHP bridge&lt;/strong&gt;: Nginx passes &lt;code&gt;llms.txt&lt;/code&gt; requests to WordPress, which intercepts and serves the file directly.&lt;/p&gt;

&lt;p&gt;Two pieces needed:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. MU-Plugin (WordPress side)
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;wp-content/mu-plugins/llms-txt-bridge.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="cd"&gt;/**
 * Plugin Name: LLMs.txt Bridge
 * Description: Serves llms.txt from WP container for Nginx
 */&lt;/span&gt;
&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'init'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REQUEST_URI'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s1"&gt;'?'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'/llms.txt'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'/llms-full.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$filename&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;ltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$uploads_dir&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wp_upload_dir&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s1"&gt;'basedir'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nv"&gt;$uploads_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$uploads_dir&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$abspath_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ABSPATH&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Sync from ABSPATH to uploads dir if ABSPATH version is newer&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$abspath_file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$abspath_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;filemtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$abspath_file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$uploads_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uploads_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;filemtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uploads_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$abspath_time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$uploads_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$abspath_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$uploads_file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Serve from uploads if available&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uploads_file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type: text/plain; charset=utf-8'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uploads_file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why sync to uploads?&lt;/strong&gt; The uploads directory is typically a mounted volume, meaning the file survives container restarts. ABSPATH files don't.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Nginx Config
&lt;/h3&gt;

&lt;p&gt;Add this &lt;code&gt;location&lt;/code&gt; block to your &lt;code&gt;nginx.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/llms(-full)?&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.txt&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="n"&gt;/index.php?&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;expires&lt;/span&gt; &lt;span class="s"&gt;30d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Cache-Control&lt;/span&gt; &lt;span class="s"&gt;"public,&lt;/span&gt; &lt;span class="s"&gt;no-transform"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;try_files $uri /index.php&lt;/code&gt; means: try to serve the file statically first; if not found, pass to PHP. Since Nginx can't see the file in the WP container, it always falls through to PHP — which is exactly what we want.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /llms.txt
      │
      ▼
┌─────────────────────────────┐
│  Nginx Container            │
│  try_files → file not found │
│  → passes to PHP            │
└─────────────────────────────┘
      │
      ▼
┌─────────────────────────────┐
│  WordPress Container        │
│  MU-plugin intercepts init  │
│  Syncs file if needed       │
│  Serves with correct headers│
└─────────────────────────────┘
      │
      ▼
  200 OK (text/plain)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Don't Commit the Generated Files
&lt;/h2&gt;

&lt;p&gt;Add these to &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wp/llms.txt
wp/llms-full.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These files are generated per environment and contain domain-specific URLs. If you accidentally committed them, clean up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;--cached&lt;/span&gt; wp/llms.txt
git &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;--cached&lt;/span&gt; wp/llms-full.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;404 on &lt;code&gt;/llms.txt&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Check that the MU-plugin is in the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;your_wp_container &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /var/www/html/wp-content/mu-plugins/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that AIOSEO generated the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;your_wp_container &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /var/www/html/llms.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the file doesn't exist, go to AIOSEO settings and toggle LLMs.txt off and on to regenerate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File returns wrong domain (e.g., &lt;code&gt;mysite.test&lt;/code&gt; instead of &lt;code&gt;mysite.com&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The file was generated on a local environment. Fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Delete the stale file&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;your_wp_container &lt;span class="nb"&gt;rm&lt;/span&gt; /var/www/html/llms.txt

&lt;span class="c"&gt;# Then regenerate via AIOSEO in WP Admin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nginx not passing requests to PHP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verify the location block is active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;your_nginx_container nginx &lt;span class="nt"&gt;-T&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;llms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why Not Just Use a Shared Volume?
&lt;/h2&gt;

&lt;p&gt;A shared volume would work technically, but it breaks the immutability model — if both containers write to the same filesystem, you lose the clean separation between "application code" and "runtime state." The PHP bridge keeps infrastructure clean while solving the practical problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Fix: Dynamic Generation
&lt;/h2&gt;

&lt;p&gt;The PHP bridge works — but it's a deliberate trade-off, not a clean solution. You're syncing files between paths, intercepting requests at &lt;code&gt;init&lt;/code&gt;, and hoping nothing breaks when AIOSEO updates.&lt;/p&gt;

&lt;p&gt;There's a cleaner approach that would eliminate the problem entirely: &lt;strong&gt;serve &lt;code&gt;llms.txt&lt;/code&gt; dynamically via WordPress rewrite rules, with no physical file involved&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;WordPress already does exactly this for &lt;code&gt;robots.txt&lt;/code&gt;. Before WordPress 5.3, you needed a physical &lt;code&gt;robots.txt&lt;/code&gt; file in the document root. Since 5.3, if no physical file exists, WordPress generates the response dynamically through a rewrite rule — no file on disk, no filesystem dependency, works everywhere including read-only environments and isolated containers.&lt;/p&gt;

&lt;p&gt;The same pattern applied to &lt;code&gt;llms.txt&lt;/code&gt; would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /llms.txt
      │
      ▼
  WordPress rewrite rule intercepts
      │
      ▼
  Check transient cache
      │
      ├── Cache hit → serve immediately
      │
      └── Cache miss → generate content → store in transient → serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits over the file-based approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No Docker filesystem isolation problem (nothing writes to disk)&lt;/li&gt;
&lt;li&gt;No permission issues on managed hosting&lt;/li&gt;
&lt;li&gt;Works on read-only filesystems&lt;/li&gt;
&lt;li&gt;Cache invalidation is explicit and controllable&lt;/li&gt;
&lt;li&gt;Generation happens on first request, not on plugin save&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For SEO plugin authors&lt;/strong&gt;, this means replacing &lt;code&gt;file_put_contents(ABSPATH . 'llms.txt', ...)&lt;/code&gt; with a rewrite endpoint and transient cache. The content generation logic stays identical — only the delivery mechanism changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For WordPress core&lt;/strong&gt;, there's a reasonable case for adding &lt;code&gt;llms.txt&lt;/code&gt; infrastructure the same way &lt;code&gt;robots.txt&lt;/code&gt; was added in 5.3: a default dynamic endpoint with filters that plugins can hook into. Given how quickly LLM indexing is becoming relevant for content sites, this seems like a natural next step.&lt;/p&gt;

&lt;p&gt;Until either happens — the PHP bridge above does the job.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Isolated Docker containers create real filesystem problems for file-based WordPress features&lt;/li&gt;
&lt;li&gt;The PHP bridge pattern (Nginx → PHP fallback) is a clean solution that doesn't require infrastructure changes&lt;/li&gt;
&lt;li&gt;MU-plugins are ideal for this: no activation needed, always loaded&lt;/li&gt;
&lt;li&gt;Nginx caches the response for 30 days after first request, so performance is fine&lt;/li&gt;
&lt;li&gt;Generated files with domain URLs should never be in git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're running a similar multi-container WordPress setup, this pattern applies to any file that WordPress generates dynamically — not just &lt;code&gt;llms.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Running a similar setup? Let me know how you handled it — or if you've seen SEO plugins already moving toward dynamic generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update: WordPress Core Proposal
&lt;/h2&gt;

&lt;p&gt;After publishing this article, I submitted a feature request to WordPress Core Trac proposing native &lt;code&gt;llms.txt&lt;/code&gt; and &lt;code&gt;llms-full.txt&lt;/code&gt; support — using the same virtual file architecture that already powers &lt;code&gt;robots.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trac Ticket:&lt;/strong&gt; &lt;a href="https://core.trac.wordpress.org/ticket/64959" rel="noopener noreferrer"&gt;#64959 — Add native llms.txt and llms-full.txt support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The patch adds rewrite rules, conditional tags (&lt;code&gt;is_llmstxt()&lt;/code&gt;, &lt;code&gt;is_llmstxt_full()&lt;/code&gt;), transient-based caching, and a full set of filters for plugin extensibility. If accepted, this would eliminate the need for the Nginx workaround described in this article — WordPress would serve &lt;code&gt;llms.txt&lt;/code&gt; through PHP, just like it does with &lt;code&gt;robots.txt&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>docker</category>
      <category>nginx</category>
      <category>php</category>
    </item>
  </channel>
</rss>
