=== LLMs.txt Curator === Contributors: seanmullins Tags: llms.txt, ai seo, llm, ai visibility, chatgpt Requires at least: 6.2 Tested up to: 7.1 Requires PHP: 7.4 Stable tag: 2.2.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Curate what your site tells machines: decide what is represented, arrange it visually, and see why every decision was made. == Description == **LLMs.txt Curator** gives you control over what your website tells AI systems and other machines about itself. It finds the public content on your site, publishes it to `llms.txt` and `llms-full.txt`, and then lets you curate that representation: review what was found, write descriptions, arrange the order machines read, mark what matters most, and ask Curator why any individual page is or is not included. Version 2.0 is a rebuild around that idea. Every page, custom URL and fact is a Resource with its own editorial state and a recorded origin, so Curator can always answer three questions: what am I publishing, where did it come from, and why. = New in 2.2 = * **Markdown pages that match the page.** With Markdown pages on, Curator takes a snapshot of each page in your llms.txt as a logged-out visitor sees it, in the background, and builds the Markdown from that. Content added by page builders and block templates, which is not in the stored post, is now included. Menus, headers, footers, comments, share buttons and "More posts" lists are left out. * **A better converter.** Tables come out as tables, code keeps its indentation, numbered lists keep their numbers and nested lists stay nested. The same converter writes llms-full.txt and every .md address, so they always agree. * **See what machines receive.** Open "Markdown" on any page in Your llms.txt to see its Markdown version laid out for reading, exactly as served, and how it was made: whether it came from a snapshot or the stored content, which part of the page was used, what was removed, and what was kept. "Take a snapshot now" refreshes it on the spot. * **Checks for every page.** A new Pages group in Checks reports pages built from stored content because a snapshot failed (and why), pages with very little text, unrendered shortcodes, leftover markup, repeated text, uneven tables and menus that leaked into the content. "Check what visitors receive" now also checks a sample of .md addresses for the right type, the noindex and canonical headers, and revalidation. * **Never out of date.** A snapshot is retired the moment its page, its approved comments or a synced pattern it uses changes, and the stored content is served until a new one is taken. When a post is unpublished, made private or given a password, every snapshot that links to it is retired too, so it leaves lists of posts straight away. Changes to your theme, templates, menus or plugins renew snapshots in the background. * **Answer requests for Markdown at the page's own address (optional, off).** A request for the normal page that asks for text/markdown in its Accept header gets the Markdown version. These replies are never stored by shared caches, and "Check what visitors receive" tells you if a CDN mixes them up. * **Read-only access for tools and agents.** Through WordPress's own Abilities API, signed-in tools can list what your llms.txt publishes, get a page's Markdown version exactly as its .md address serves it, and ask what changed since they last looked. With WordPress's MCP Adapter installed, AI clients such as Claude can use the same abilities. Nothing they do can change your curation, settings or what you publish, and they see only what you already publish. A new Agents group in Checks shows whether this is working. = New in 2.1 = * **Notes for machines:** your own answer to "What would a machine get wrong about your site?", published as written. * **Checks:** Structure, Content, Delivery and Ownership. Observed facts, not a score. * **Ownership:** anything else that answers, or could answer, /llms.txt. * **Bring in an existing llms.txt:** staged for review, approved in one step, undoable. * **Also:** links to Markdown pages, the Optional section, Site Health, a block editor panel and the Abilities API. = What 2.0 gives you = * **Automatic discovery, human curation.** Curator finds your public content and publishes it straight away, marked as found automatically rather than reviewed. You promote what you have checked, exclude what you do not want, and nothing waits on you to be represented. * **Your llms.txt.** Arrange sections and pages with exactly what machines receive shown beside you as you work, in readable form or as the Markdown that gets published. Drag if you like; every move is also a button. * **Why?** Open any resource and see the decisions behind it, separated into what Curator observed about the page and what you decided, ending with the exact line it contributes to the file. * **Representation coverage.** Not a score. Curator tells you whether it can account for every resource it found: represented, excluded by you, unavailable to visitors, or not yet checked. The goal is zero unexplained. * **Unpublished changes.** When your curation differs from the published file, Curator says so, shows what changed including the old and new wording, and publishes when you are ready. * **Check what visitors receive.** After publishing, Curator looks at your public file and tells you plainly whether visitors get the new version, or whether a cache or an old file is serving an older copy. * **Markdown pages (optional).** Switch on to offer each page in your llms.txt as Markdown at its address plus index.md, for example /about/index.md, following the llms.txt proposal. Off by default. * **Suggested descriptions, honestly labelled.** Curator can fill empty descriptions from what the page already publishes (schema, SEO meta, excerpt, Open Graph, page content) and tells you which one it used. A suggestion stays marked as a suggestion until you accept or edit it. Curator does not write text for you. * **Site details.** Describe the organisation behind the site once, and Curator publishes it above the first section. Where WordPress or your SEO plugin says something different, Curator shows you both and publishes your choice. * **Facts and custom URLs.** Publish a short factual statement that does not deserve its own page, or a URL Curator did not find on its own. Curator stores and represents a URL; it never fetches it. = Safe by default = * Both files are generated as a logged-out visitor, not with the permissions of the administrator who publishes. * Drafts, private pages, password-protected pages and noindex pages are left out, and so are pages restricted by Paid Memberships Pro, MemberPress, Restrict Content Pro or WooCommerce Memberships. Any other membership or access plugin can mark content as restricted through the `llmscu_is_restricted` filter. Curator explains each exclusion. * An `llms.txt` this plugin did not create is never overwritten. * No AI ranking claims, no scores, no data sent anywhere. The only requests Curator makes are to your own site: to check what visitors receive, and, with Markdown pages on, to take snapshots of your own public pages in the background. Snapshots come from your server's own address, so if your site shows extra content to requests from the server itself (an IP allow list, or a maintenance mode that lets the server through), leave Markdown pages off. = What llms.txt is, and what it isn't (June 2026) = Being straight with you matters more than overselling. Google Search **ignores** `llms.txt`: it will not help or harm your Google rankings, and Google confirmed in June 2026 that it is fine to maintain the file for other systems that do read it. So this plugin is not an "AI ranking" tool. Where the file genuinely earns its place: on-site navigation for agents already on your site, the surfaces that actually read it (such as Perplexity and coding agents), and passing Chrome's Agentic Browsing audit. The honest, useful question is not "does this rank me" but "which AI bots are actually reading my file", and this plugin answers it from your own server logs. = What makes this different = Most llms.txt plugins treat the file as a static output. LLMs.txt Curator treats it as a living asset: * **Description coverage**: Curator shows how many published resources have a description and which still need one. It is a count, not a score. * **Suggested descriptions**: fills empty descriptions from what the page already publishes (schema, SEO meta, excerpt, Open Graph, page content), names the source it used, and leaves each one marked as a suggestion until you accept or edit it. Never overwrites what you wrote. * **Change detection**: the header tells you when your curation differs from the published file, and Publish brings it up to date. * **Per-Page Title Override**: set a different title for each page specifically for AI consumption, without touching your on-site SEO. * **Safety checks**: Curator will not publish a file with missing or duplicated pages or broken formatting. Includes an on-demand format check with plain-English results. * **AI Crawler Analytics**: see which bots visited in the last 7 days, with a visual bar chart. OpenAI, Anthropic, Perplexity, Google: know who is actually reading your file. = Core features = * **Visual composition**: arrange sections and pages in Your llms.txt, with the resulting file shown beside you; each section becomes an `##` heading per the spec * **llms-full.txt generation**: the companion file with full Markdown content for each curated page * **Five SEO plugin integrations**: Rank Math, Yoast SEO, All in One SEO, SEOPress, The SEO Framework * **Schema-aware descriptions**: uses structured data before falling back through the description chain * **When to publish**: Instant (about 30 seconds after a change), Daily, Weekly, or only when you click Publish * **WooCommerce support**: SKU, price, stock, categories, dimensions; respects product visibility * **WordPress Multisite**: network-activate across all sites; each site manages its own independent llms.txt; a network screen to publish each site or all of them * **Pre-built templates**: Business, E-commerce, SaaS, Blog, Local Business * **Show the whole file**: read the exact file before you publish, in readable form or as Markdown * **Markdown pages**: optional per-page Markdown for everything in your llms.txt, built from a snapshot of the public page, with excluded and non-public pages returning not found * **Import / export**: move your configuration between sites as JSON * **WP-CLI**: `wp llms-txt regenerate`, `wp llms-txt status`, `wp llms-txt crawler-log` * **REST API**: `POST /wp-json/llms-txt/v1/regenerate`, `GET /wp-json/llms-txt/v1/status`, plus the `llms-txt/v2` resource endpoints the workspace itself uses * **Atomic file writes**: temp file → rename; no half-written files served to bots * **ETag/304 caching**: proper HTTP headers for CDN revalidation * **Subdirectory / Bedrock support**: correctly finds the site root on non-standard installs * **Robots.txt reference**: automatically adds a spec-compliant comment = Description Suggestions in detail = When pages lack descriptions, AI systems get less context. The suggestion engine fills the gap automatically: 1. Schema markup (Rank Math, custom `_schema_json`) 2. SEO plugin meta description 3. WordPress excerpt 4. Open Graph description (`_og_description` / `og_description`) 5. First 160 characters of post content Already-set descriptions are never touched. Pages that can't be filled automatically are listed for manual review. = Description coverage = Curator shows how many published resources have a description, and **Review** lists the ones that still need one. None of this is published in the file. Up to 2.0.0 the file ended with a coverage report; 2.1.0 removed it, because the llms.txt proposal makes every `##` section a list of links, and the reference parser published with the proposal could not read a file that ended any other way. = AI Crawler Analytics = Track 12 known bots: GPTBot, ChatGPT-User, ClaudeBot, PerplexityBot, Google-Extended, Applebot-Extended, Meta-ExternalAgent, Bytespider, CCBot, Cohere, DeepSeek, Amazonbot. The 7-day analytics card shows a visual bar chart of recent activity. All-time totals are kept separately. IP addresses are anonymised before storage: last octet zeroed for IPv4, last 80 bits for IPv6. No data leaves your server. = Safety checks and the format check = Before publishing, the safety checks look for: * Pages missing or unpublished * Duplicate URLs across sections * Members-only pages (always left out) * Noindex pages (left out of both files by default) * Items whose content type is not ticked * Canonical mismatches * Password-protected pages (always left out) * Thin content (< 100 words, no meta, no excerpt) * File size > 50 KB * Too many pages (> 80) When safety checks are on (Settings), errors stop the file being published and the results are shown immediately. Warnings are shown but don't block. **Check the file's format** in Settings runs the same checks on demand. Everything is explained in plain English. = When to publish = * **Instant**: about 30 seconds after any page is published or trashed (default) * **Daily**: once a day, via a WP-Cron recurring event * **Weekly**: once a week * **Manual only**: only when you click Publish = How to get started = 1. Install and activate. Curator finds your public pages and publishes them straight away. 2. In **Your llms.txt**, arrange your sections and remove anything you do not want. Aim for the pages that best represent your site. 3. In **Review**, decide on anything Curator flags, such as page-builder templates carried over from an earlier setup. 4. Click **Suggest descriptions from your pages**, then accept or edit each suggestion. 5. Click **Publish**, then **Check what visitors receive** to confirm the public file is current. 6. Optional, in **Settings**: llms-full.txt, Markdown pages, and the AI crawler log. = WooCommerce integration = When WooCommerce is active, the plugin automatically includes SKU, price, and stock status in `llms.txt` descriptions, and full product details in `llms-full.txt`. Products with "hidden" visibility are excluded, and you can optionally exclude out-of-stock products. = Developer hooks = * **`llmscu_capability`** filter: override the required capability (default: `manage_options`) * **`llmscu_post_limit`** filter: scanner post limit per type (default: 500) * **`llmscu_full_word_limit`** filter: per-page word cap in `llms-full.txt` (default: unlimited) * **`llmscu_full_max_bytes`** filter: size ceiling for `llms-full.txt` in bytes (default: 5 MB, minimum 256 KB) * **`llmscu_max_sections`** / **`llmscu_max_entries`** filters: limits for saved or imported settings (defaults: 200 sections, 5,000 entries) * **`llmscu_is_restricted`** filter: mark a post as members-only so it is left out of both files (`function ( bool $restricted, int $post_id )`) * **`llmscu_backup_dir`** filter: where replaced files are backed up (default: `uploads/llms-txt-curator-backups`; point it outside the web root if your host allows) * **`llmscu_regenerated`** action: fires after each successful regeneration with the content string == Installation == 1. Upload the `llms-txt-curator` folder to `/wp-content/plugins/`. 2. Activate through the 'Plugins' menu. 3. Open **LLMs.txt** in the admin menu to begin curating. Settings are under **LLMs.txt -> Settings**. Or install directly from the WordPress plugin repository by searching for "LLMs.txt Curator". == Frequently Asked Questions == = What is llms.txt? = `llms.txt` is a proposed standard (llmstxt.org) that provides AI systems with a curated, Markdown-formatted overview of a website's most important content. A strategic selection of the pages you want AI to know about, not a sitemap. = Can AI tools and agents use Curator? = Yes, read only, and only when signed in as a user who can manage Curator. Curator registers abilities with the WordPress Abilities API (WordPress 6.9 or later): get-site, list-resources, get-resource, get-representation, get-changes, get-published-file, explain-resource and get-diagnostics. They are available through PHP and the REST API. If you install WordPress's MCP Adapter plugin, AI clients that speak MCP can use four of them: get-site, list-resources, get-representation and get-changes. Curator does not include an MCP server of its own. "Public" in an ability's settings means listed for tools; it never means anyone can call it. Every call checks the signed-in user. To keep Curator's abilities out of MCP lists, return false from the `llmscu_abilities_public` filter. The abilities answer only from what you publish. A draft, private, password-protected or excluded page gets the same "not available" answer as an address that does not exist. A page's Markdown is returned only if a logged-out visitor can read the page now, and only if you publish Markdown (Markdown pages or llms-full.txt). Calling them never changes your settings, curation or what you publish, and Curator takes no snapshots and makes no requests to answer them. (When a page's Markdown comes from its stored content, its blocks are rendered as they are when the page is viewed, and a block that fetches something, such as an RSS block, still does.) get-changes counts publishes, not time. Each publish has a number; a tool keeps the number it was given and asks what was added, changed or removed since. Pages whose content changed without their llms.txt line changing have a new fingerprint in list-resources, so a tool can tell what to fetch again. Page text in a returned Markdown version is written by your site's authors and visitors, and tools should treat it as content, not instructions. = What is llms-full.txt? = A widely used companion to `llms.txt`, rather than part of the llms.txt proposal itself. While `llms.txt` contains links and short descriptions, `llms-full.txt` contains the full Markdown content of each page. Optional: enable it in Settings when ready. = Do I need both files? = No. `llms.txt` alone is sufficient. `llms-full.txt` is useful if you want AI systems to have immediate access to your full content without additional crawling. = What does Description Suggestions do? = Scans every curated page and fills missing descriptions using a five-step fallback chain: schema markup -> SEO meta -> excerpt -> Open Graph -> page content. Pages with descriptions already set are never touched. = What is description coverage? = A count of how many listed pages have descriptions, shown in the admin with the pages that still need one. It is not published in the file. = What does Title Override do? = Lets you set a different title for a page in your llms.txt output without changing it on your site. Useful when your WordPress title includes your site name but you want AI to see a cleaner, more descriptive title. = What do the safety checks do? = They run before every publish. If errors are found, the file is not published and the results are shown immediately, so a broken or malformed file never goes live. Switch them on or off in Settings. = Which SEO plugins are supported? = Rank Math, Yoast SEO, All in One SEO, SEOPress, and The SEO Framework. = Which AI bots does the crawler log detect? = GPTBot (OpenAI), ChatGPT-User, ClaudeBot (Anthropic), PerplexityBot, Google-Extended, Applebot-Extended, Meta-ExternalAgent, Bytespider (ByteDance), CCBot (Common Crawl), Cohere, DeepSeek, and Amazonbot. = What if my host blocks file writes? = The plugin has a rewrite rule fallback that serves both files via WordPress. Choose between "Direct file", "Rewrite rule only", or "Both" (recommended) in Settings. = Does this work on multisite? = Yes. Activate network-wide from Network Admin > Plugins, or activate per-site on individual sub-sites. Each site manages its own independent `llms.txt`; there is no shared network file. The Network Admin overview page (Network Admin > Settings > LLMs.txt Curator) shows every site's generation status and lets you regenerate any site, or all sites at once, without leaving the network admin. The main site writes a physical file. Sub-sites, on both subdirectory networks (`example.com/site1`) and subdomain networks (`site1.example.com`), share the main site's document root, so they serve `llms.txt` via WordPress rewrite rule from the database instead. This is correct and functionally identical. WP-CLI works per-site using the standard `--url=` flag: `wp llms-txt regenerate --url=https://site1.example.com` = Which pages are left out of the files? = Password-protected pages are always left out, and so are pages your membership plugin restricts. Both files are generated as a logged-out visitor, so members-only sections inside a public page are left out too. Pages your SEO plugin marks as noindex are left out while "Leave out noindex pages" is ticked (the default). Items whose content type is not ticked under Content Types are left out too, and the validator lists each one so nothing disappears silently. = My SEO plugin also makes llms.txt. What happens? = Rank Math, Yoast SEO and All in One SEO can generate llms.txt too. This plugin never overwrites a physical llms.txt it did not create. If it finds one, the status panel says so and offers "Replace existing file", which writes and checks the new file first, then moves the old one to a protected backup folder in uploads (with a random file name). If anything fails part-way, the original is put back. Switch the llms.txt feature off in one of the two plugins so they do not compete. = How are the Markdown pages made? = With Markdown pages on, Curator requests each page in your llms.txt from your own site, as a logged-out visitor with no cookies, in the background. It uses the page's main content area, leaves out menus, headers, footers, comments and share buttons, and converts what remains. If a snapshot cannot be taken (a password-protected staging site, a maintenance page, a host that cannot answer its own requests), the page's stored content is used instead and the Markdown page says which. A snapshot is never used after its page has changed. = Does Curator request my pages? Will it slow my site? = Only with Markdown pages on, only for pages in your llms.txt, and only in the background: never while a visitor is waiting. Up to 20 pages are requested at a time, a minute or so apart, until all have a snapshot; then each is renewed about once a day, or sooner when the page changes. If your site cannot answer its own requests, Curator stops trying and waits longer each time. With llms-full.txt on and Instant publishing, llms-full.txt is rebuilt after new snapshots; on Daily, Weekly or Manual it changes only when you publish. = Can I change what is left out of a page's Markdown? = Yes, with the `llmscu_extraction_noise` filter. Each rule names a tag, id, class or attribute to remove from the content area. The Inspector's Diagnostics view lists what was removed from each page. = Is any data sent externally? = No. Everything stays on your server. No telemetry, no external API calls, no cookies. Crawler IP addresses are anonymised before storage. == Screenshots == 1. Your llms.txt: arrange your sections, with exactly what machines receive shown beside them 2. Review: what needs a decision, such as templates carried over from an earlier setup 3. Settings: publishing, site details, the format check, the AI crawler log, and import and export 4. Why?: what Curator observed, what you decided, and the line it publishes 5. Check what visitors receive: whether the public file is current, and a cache named if one is in the way 6. The whole file: exactly what machines receive, readable or as Markdown 7. AI crawler log: which bots are actually reading your file 8. Markdown: a page's Markdown version laid out for reading, with how it was made == Changelog == = 2.2.0 = Markdown pages that match what visitors see, and read-only access for tools. llms.txt changes on upgrade only if it was damaged (see the fixes below); llms-full.txt is rebuilt once. If you publish manually, both wait for your next Publish. * New: snapshots. With Markdown pages on, each page in your llms.txt is fetched from your site as a logged-out visitor, in the background, and converted from its main content area. Content added by page builders and templates is included. Visitor requests never trigger a snapshot. * New: snapshot safeguards. A snapshot is used only when WordPress itself answered for that page in its current state: Curator signs its request and the page answers with a marker. Caches, maintenance and login pages, redirects elsewhere, non-HTML replies and pages over 2 MB are rejected, and the stored content is used instead. * New: the content area is chosen from the page's own markup (main, role="main", article, then the post content). Menus, headers, footers, comments, share buttons, related posts, breadcrumbs and "More posts" lists are removed. The `llmscu_extraction_noise` filter changes the rules. * New: the Markdown view, from "Markdown" on any page in Your llms.txt: Readable, Markdown and Diagnostics, plus "Take a snapshot now". * New: a Pages group in Checks, from stored snapshots. * New: "Check what visitors receive" also checks up to five .md addresses: status, content type, an HTML page served instead, missing noindex or canonical headers, and revalidation. * New: "Also answer requests that ask for Markdown at the page's own address", off by default. Only an Accept header that ranks text/markdown at least as high as text/html counts; browsers always get the page. Replies are private and vary by Accept; the check above detects a cache that mixes them up. * New: .md replies carry an ETag, answer If-None-Match with 304, send nosniff and say whether they came from a snapshot. * Change: a new converter for llms-full.txt and every .md address. Pipe tables, fenced code with its indentation and language, numbered lists with their numbers, nested lists, details, captions and definition lists. Text that looks like an HTML tag is escaped. PHP 8.4 uses the HTML5 parser; earlier versions give the same output on well-formed pages. * Change: with pretty permalinks, ?format=md on a page redirects to its .md address, so Markdown is never answered at the page's own address unless you switch that on. * Change: the Markdown link header is sent only for pages that are actually served as Markdown. Noindex and password-protected pages were advertised and then answered "not found". * Fix: letters in Arabic, Persian, Hebrew, Hindi and other scripts, and some accented Latin letters, were cut in half in titles and descriptions, damaging llms.txt and llms-full.txt. Sites with a damaged file publish once after updating. Reported by Saeid Afshari. * Fix: the Settings link on the Plugins screen opens Curator's settings again. Reported by Saeid Afshari. * Fix: with Markdown pages off, ?format=md showed "Not found." instead of the page. * Privacy: a snapshot is retired when a comment on its page is approved, or an approved one is edited or removed. Pending and spam comments change nothing. * Privacy: when a post is unpublished, made private, trashed, deleted or given a password, every snapshot that links to it is retired at once. * New: read-only abilities for tools and agents (WordPress Abilities API): get-site, list-resources, get-resource, get-representation and get-changes, alongside 2.1's three. All are read-only, so REST runs them only by GET, and all require Curator's capability. get-representation returns exactly what the .md address serves, with the same ETag. Anything not published gets one "not available" answer. * New: get-changes: what was added, changed or removed since a given publish. * New: works with WordPress's MCP Adapter (tested with 0.7.0, not included); the `llmscu_abilities_public` filter withdraws it. * New: an Agents group in Checks. * Change: the stored-content fallback renders with that page as the current post. * Performance: on 10,000 pages, a .md page is served in under 2 ms, llms-full.txt builds in about 6 s and Checks take under 5 s. = 2.1.0 = Control over what you publish: notes for machines, checks, ownership, and bringing in an existing llms.txt. It also makes your published file read correctly with the reference parser that accompanies the llms.txt proposal, so the file itself changes on upgrade: the coverage report is no longer published, and the summary sits directly under the heading. Your curation does not change. Sites that publish automatically (Instant, Daily or Weekly) publish once shortly after updating; if you publish only when you click Publish, click it once. * New: Notes for machines, under Site details. Published after the site details and before the first section. Headings are refused on save and neutralised on output. Empty notes publish nothing. Included in export and import. * New: Checks, at the top of Your llms.txt, grouped as Structure, Content, Delivery and Ownership. Computed from stored data and the file Curator would publish, with no requests. Advisory only. Built as an engine that other code can extend through the `llmscu_diagnostics_checks` filter. * New: Structure check reads your file the way the reference parser published with the llms.txt proposal does (a PHP port of its patterns, checked against the original). * New: Ownership checks: a physical llms.txt Curator did not write, another plugin's rewrite rule for /llms.txt (including one registered for exactly the same address, which WordPress otherwise replaces silently), what the last check of the public file found, and active plugins known to be able to make llms.txt. * New: Bring in an existing llms.txt (Settings, Import and export). Staged for review, approved in one step, undoable. Links to your pages become those pages' entries; other links become URL entries and are never fetched; descriptions arrive as suggestions labelled "Suggested from your previous llms.txt"; your own descriptions and anything you have already reviewed are kept; lines Curator cannot read are listed, not dropped. * New: "Link entries in llms.txt to the Markdown pages" setting, off by default. Custom URLs, facts and llms-full.txt are unchanged, and a page whose SEO canonical is a different address keeps that canonical. * New: a section named Optional is always last in the arrangement, the preview and the published file, and is labelled as skippable. If you already have a section named Optional, it moves to the end of your file when you next publish. * New: Site Health tests for llms.txt ownership and delivery. They recommend; they never report a critical problem. * New: a read-only llms.txt panel in the block editor's document sidebar, for users who can manage Curator. * New: read-only abilities for the WordPress Abilities API (6.9+): get the published file, explain an entry, get the checks. Each requires Curator's capability. * New: a notice in Checks when WPML, Polylang or TranslatePress is active, since Curator publishes one file for the whole site. * Change: notes are part of unpublished changes, so editing them shows up before you publish. * Change: committing an import in Settings, Import and export no longer publishes. Like every other change, it waits for Publish or your publishing schedule. * Change: Curator's requests to your own site (Check what visitors receive, and bringing in an existing llms.txt) now follow redirects only while they stay on your site. A redirect to another address stops the request and says where it was going. * Change: Checks show "Not checked" rather than "clear" for anything that depends on what visitors receive, until you check it. * Change: Site details are grouped into Identity, What you cover and Useful references, each opening when you need it. * Fix: the coverage report is no longer published at the end of llms.txt. Its lines were not links, and the reference parser could not read any file that contained it. Description coverage is still shown in the admin. * Fix: the site summary blockquote now comes directly after the heading, with Curator's two comment lines after it. With the comments in between, the reference parser found no summary. * Fix: the site summary is published on one line. The reference parser reads only the first line of the blockquote, so a summary wrapped at 80 characters was cut short. Line breaks and repeated spaces in the summary become single spaces; the wording is unchanged. * Fix: Undo after publishing. Up to 2.0.0, publishing recorded each page's eligibility as if it were an edit, so Undo was refused after any publish, and an edit started before a publish could be refused as a conflict. * Fix: a page title containing square brackets, such as "Pricing [2026]", or an untitled page, stopped the reference parser reading the whole file. Brackets in link text are now round brackets, and an untitled entry uses its address. * Fix: a line break in a title, description, section name or the site name no longer continues onto the next line of the file. * Fix: a fact with a source link is published as an ordinary entry, linked to its source. Checks names any fact without one, since a plain line inside a list stops the reference parser. * Fix: a URL or fact added without a section goes to Other Resources instead of being stored where it is never published. A section can no longer be given a blank name, and one that already has a blank name is published as Untitled section instead of being left out. * Readme: corrected the description of what is left out of the files, the menu location in Installation, and the old Safety Mode name. * Performance: pages are loaded in batches when the file is built. On 10,000 pages, building the file went from about 6.5 seconds to about 1 second, and Checks from about 8 seconds to about 2. = 2.0.0 = A rebuild of how Curator works, with the same published content on upgrade. **Your curation is carried over exactly.** Your sections, pages, descriptions, title overrides and exclusions are migrated into the new model, and the file regenerates with the same content, in the same order, until you deliberately change something. Two lines do move: Curator's own comment lines now sit below the heading rather than above it, so the file begins with the H1 the llms.txt proposal asks for. * New: the Curator workspace. Three places rather than a row of tabs, with site details, import and export, and settings alongside. * New: Review. Everything Curator knows about, with search, filters, bulk actions and an editorial state for each: kept by you, published automatically, or excluded by you. * New: Your llms.txt. Arrange sections and resources with the result shown beside you, in readable form or exact Markdown. Drag, or use Move up, Move down, Move to position and Move to section. * New: Why? Every resource can explain itself, separating what Curator observed from what you decided, and showing the exact line it contributes. * New: representation coverage and Everything accounted for. Curator states whether every resource it found has an explained outcome, and never claims completeness before discovery finishes. * New: unpublished changes. When your curation differs from the published file, Curator shows what changed, including previous and current wording, and publishes on request. * New: facts, custom URLs and site details, so a site can be represented properly even where a page does not exist for something. * New: primary resources. Mark up to ten resources as especially important for understanding your site. * New: suggested descriptions are labelled with the source they came from and stay marked as suggestions until you accept or edit them. * New: import and export, validated and previewed before anything is written. * New: discovery runs in batches and can be paused and resumed. It never reports a site as fully checked when it was interrupted. * Change: resources are stored in their own table rather than a single option, so large sites stay fast and every edit writes one row. * Change: minimum WordPress version is now 6.2, for the database identifier placeholder used by the new store. * New: the workspace shows what machines actually receive for each entry, including text Curator takes from the page when you have not written a description, and says where it came from. * New: Curator never reports a publication visitors are not getting. If an older llms.txt cannot be replaced, generation says so and nothing is marked as published; the file's own date appears in the status panel. * New: page-builder templates that visitors cannot open, such as Elementor's template library, are no longer published when found. Ones carried over from an earlier setup stay published, marked "Kept from your earlier setup", until you decide. * Change: Curator has three places: Your llms.txt (arrange your file and see what machines receive, side by side), Review (what needs a decision) and Settings. Nothing is hidden behind a menu. * Change: Settings lives inside Curator: publishing and content, site details, the file format check, the AI crawler log, and import and export. Old settings links open the matching section. * New: carried-over page-builder templates can be kept as a deliberate decision, recorded in Why?, so Curator stops asking. Excluding them remains one click away. * New: optional Markdown pages. When switched on under Settings, each page in your llms.txt is also available as Markdown at its address plus index.md (for example /about/index.md), following the llms.txt proposal. Off by default; excluded and non-public pages return not found. * Fix: in llms-full.txt and Markdown pages, text from page builders no longer keeps its HTML indentation, which Markdown readers treated as code blocks. * Fix: the "Publish automatically when content changes" checkbox was saved but never used. It is gone; "When to publish" is the one setting that decides. * New: Show the whole file, to read everything machines will receive before you publish. * Change: "Generate" is now Publish. After publishing, Curator checks the public file itself and says plainly whether visitors get the new version, or whether a cache or an old file is serving an older copy. * Change: in Your llms.txt, each page's actions are named in words under Options, including Remove from llms.txt, and section buttons say they act on the section. * Change: the older Preview & Validate and Import / Export tabs give way to Curator's own, inside Settings. * New: Curator checks its own state before publishing. If it finds something it cannot account for, such as a missing resource table after a partial database restore, it refuses to generate, leaves the published file untouched, and shows a diagnostic code rather than publishing an empty file. * Fix: llms.txt and llms-full.txt now begin with the H1 naming your site, as the llms.txt proposal asks. Curator's "Generated by" and "Last generated" comments used to sit above it, so the first thing in the file was a comment and validators reported the heading as missing. The comments are still there, directly below the heading. Reported by thomasblumer777. * Fix: every string in the admin JavaScript is now translatable, and nothing translates before init, so WordPress loads the language pack reliably. Reported by the Persian (fa_IR) translation editor: some interface text could not be translated at all. * Fix: sites already running 1.5.2 or later now migrate on update. The migration ran only on older installs, so an upgraded site kept reading its old configuration: the workspace appeared empty and editing was unavailable. Your published file was never affected. * Includes every fix from 1.5.3: generation as a logged-out visitor, membership-restricted pages left out of both files, access-controlled blocks removed from fallback descriptions, and the crawler log CSV export hardened against formula injection. = 1.5.3 = * Security: both files are now generated as a logged-out visitor. Generation triggered by an administrator was rendering shortcodes and blocks with that administrator's permissions, so a members-only section inside an otherwise public page could be written into llms-full.txt. The rule is now simple: nothing appears in either file that a logged-out visitor could not read at the public URL. * Security: pages restricted by a membership plugin (Paid Memberships Pro, MemberPress, Restrict Content Pro, WooCommerce Memberships) are left out of both files, even though they are published and have no password. The validator lists them, and the new `llmscu_is_restricted` filter covers any other plugin. * Security: the crawler log CSV export is now safe to open in a spreadsheet. A user-agent beginning with =, +, - or @ is prefixed so it cannot run as a formula. * Security: access-controlled blocks are removed from post content before it is used as a fallback description, so member-only text cannot appear in an llms.txt description. = 1.5.2 = * Fix: SEO plugin template variables such as `%seo_description%` and `%excerpt%` (Rank Math), `%%excerpt%%` (Yoast, SEOPress) and `#post_excerpt` (All in One SEO) no longer appear in generated files. They are resolved through the SEO plugin where possible, otherwise the next description source is used. Descriptions saved by Suggest Descriptions that contained only a template are refilled on the next run. Thanks to Afshari for the report. * Fix: Content Types now controls what is published, not just the page search. Re-scan and first-time setup only scan ticked types, and items of an unticked type are left out of both files (the validator lists them). On upgrade, any type already used in your sections is ticked for you, so your files do not change. Thanks to jg100 for the report. * New: "Leave out noindex pages" setting, on by default. Pages your SEO plugin marks as noindex are no longer published. * New: an existing llms.txt or llms-full.txt that this plugin did not create (hand-made, or from an SEO plugin's own llms.txt feature) is never overwritten. The status panel says so and offers "Replace existing file" (see below). * Fix: password-protected posts are no longer published in llms.txt or llms-full.txt, even if they were added to a section before being protected. * Fix: llms-full.txt generation no longer flushes a persistent object cache (Redis, Memcached). Only the in-memory runtime cache is cleared between pages. * Fix: the "noindex" header setting is now honoured consistently. The X-Robots-Tag header is sent for llms.txt served by rewrite rule, and scheduled regeneration no longer re-adds noindex to .htaccess after it has been switched off. * Fix: Rewrite-only mode now removes a physical llms.txt or llms-full.txt left by an earlier mode, and a failed file write in Both mode removes the stale copy so the fresh version is served. Only files created by this plugin are ever deleted. * Fix: multisite sub-sites on subdirectory networks no longer write a physical llms.txt into the shared document root, where it could replace the main site's file. They now serve via rewrite rule, as subdomain sub-sites already did. * Fix: uninstall now removes files written by 1.5.1 and later (it only recognised the older heading-style signature), and network sub-sites no longer touch the shared files on uninstall. * Fix: `GET /wp-json/llms-txt/v1/pages` now returns section names, page URLs and saved descriptions (previously empty). * Fix: URLs with query strings are now written correctly in llms.txt, llms-full.txt and the robots.txt reference. The `&` character was being HTML-encoded in these plain-text files. * New: "Replace existing file" is transactional. The new file is written and checked before the original moves, and the original is restored if the swap fails. Backups get a random file name and a deny-all `.htaccess`. * New: one regeneration runs at a time, across Save, Regenerate, REST, WP-CLI, cron and publish hooks. A request that arrives mid-run is queued rather than dropped, and REST returns 409. * New: llms-full.txt has a size ceiling (default 5 MB, filter `llmscu_full_max_bytes`). Pages beyond it stay in llms.txt, the file says how many were left out, and the validator reports it. * New: limits on saved and imported settings (sections, entries and text lengths). The import size cap is raised from 256 KB to 2 MB to suit larger sites. * Privacy: the public coverage report no longer lists the URLs of pages missing descriptions, and "Quality Score" in the file is now "Description coverage". * Hardening: llms-full.txt conversion keeps only http, https, mailto and tel links (javascript: and data: are dropped), resolves relative links, escapes link and alt text, strips comments and embedded SVG or iframes, and no longer empties a page if a pattern hits the PCRE limit. * Update: WooCommerce product details in llms.txt descriptions are now separated with " | ". * Update: admin and readme copy tidied, the "only plugin" claims removed, and the translation template rebuilt in full. = 1.5.1 = * Fix: generated llms.txt and llms-full.txt now contain exactly one H1 (the site name), per the llms.txt spec. The attribution and "last generated" lines are now HTML comments instead of Markdown H1 headings, and the Coverage Report footer is now an H2. This clears the "more than one H1 title" warning reported by third-party llms.txt validators. * Compat: files written by earlier versions are still recognised as plugin-owned after upgrade. Ownership detection now matches the invariant signature text in both the new comment form and the legacy heading form. The corrected file is written on the next regeneration (save settings, click Regenerate, or wait for the scheduled run). = 1.5.0 = * New: Content Signals (contentsignals.org): declare ai-train / search / ai-input preferences in your robots.txt, separating "you may read me" from "you may train on me". Opt-in, so an existing install never has a stance set silently; when enabled, all three default to yes. * New: Link: rel="describedby" response header, pointing agents at your llms.txt before they parse HTML (RFC 8288 registered rel). Default on, front-end only, respects subdirectory installs. * Update: repositioned around Google's June 2026 guidance, clarifying that Google Search ignores llms.txt (no ranking help or harm) and that the file's value is on-site agent navigation, the surfaces that read it (Perplexity, coding agents), and Chrome's Agentic Browsing audit. * Update: AI Crawler Analytics surfaced as the primary value. * Compat: Tested up to WordPress 7.0. Minimum PHP remains 7.4. = 1.4.6 = * Maintenance: explicit PHPCS ignore annotations for JSON blob input lines. Tested up to WordPress 6.9. No functional changes. = 1.4.5 = * Fix: `sanitize_all_settings()` now validates that `sections`, `post_types`, `descriptions`, and `title_overrides` are arrays before passing them to helper functions or `array_map()`. Previously used `?? array()` fallbacks which guard against null but not wrong types from malformed JSON, risking a `TypeError` on PHP 8+. * Fix: `sanitize_sections()` now validates `pages` is an array before iterating it. * Fix: `sanitize_descriptions()` and `sanitize_title_overrides()` now skip non-string values. * Fix: `post_types` output wrapped in `array_values( array_filter() )` to strip any empty keys produced by `sanitize_key()`. = 1.4.4 = * Fix: `ajax_preview()` now passes POST data through `sanitize_all_settings()` before use, consistent with `ajax_save_settings()`. Previously used `wp_parse_args()` without sanitization. = 1.4.0 = * New: 30-day AI crawler activity chart: a stacked bar chart showing daily visits per bot, auto-compressed to weekly buckets for readability. * New: "Last AI crawler visit" banner at the top of the Crawler tab, showing a live "X minutes/hours/days ago" timestamp at a glance. * New: First Seen / Last Seen columns in the all-time bot summary table. * New: Export CSV button: downloads the full crawler log as a CSV file for use in client reports. * New: Daily aggregate storage (90-day rolling window): daily visit counts are now stored separately from the raw log, enabling the timeline chart without scanning every log entry. * New: REST API endpoint `GET /wp-json/llms-txt/v1/crawler-stats`: returns all-time, 7-day, 30-day, daily, and per-bot first/last seen data. * New: REST API endpoint `GET /wp-json/llms-txt/v1/pages`: returns all curated sections and pages as JSON, useful for external dashboards. * Improvement: All-time bot table now includes Last 7 Days column alongside All-Time for quick comparison. = 1.3.5 = * Fix: All PHP declarations, stored data keys, and WordPress registrations updated to use the distinct `llmscu_` / `LLMSCU_` prefix throughout, replacing the generic `llms_txt_` / `LLMS_Txt_` prefix. No data migration required; existing stored options are unaffected. * Fix: Readme comparative claims removed per WordPress plugin guidelines. = 1.3.3 = * Fix: Reverted v1.3.2 RewriteRule approach which caused llms.txt 404 on some hosts. Replaced with a safe + mod_headers .htaccess block that sets Content-Type charset and X-Robots-Tag without touching WordPress rewrite rules. = 1.3.2 = * Fix: UTF-8 encoding bug causing em dashes and other multibyte characters to render as â€" in browsers and AI crawlers. Physical llms.txt file is now always routed through WordPress via .htaccess rules so the correct Content-Type: text/plain; charset=utf-8 header is always sent. * New: X-Robots-Tag: noindex header option, preventing Google indexing llms.txt as a page in search results. Enabled by default; toggle in Settings tab under Search Indexing. = 1.3.1 = * Security: `X-Content-Type-Options: nosniff` header added when serving llms.txt and llms-full.txt. * Security: Import JSON payload capped at 256 KB and rejected before decode with a plain-English error. * Security: Import schema sanity check: requires at least 2 expected top-level keys before accepting a configuration file. * Robustness: 2 MB file size guard before `file_get_contents()`, falling through to DB option if the physical file exceeds the cap. * Performance: `no_found_rows`, `update_post_meta_cache => false`, `update_post_term_cache => false` added to all `get_posts()` queries. * New: Site Diagnostics panel on the Preview & Validate tab, showing computed root, writable status, delivery mode, file/DB state, rewrite health, last live test result, and environment versions. * New: "Last verified" status bar row, persisted after every live test so it survives page reloads. * New: Reachability health banner, shown above tabs when the last live test failed; includes one-click "Fix: Flush Rewrite Rules" button that reruns the test automatically. * Fix: Multisite uninstall loop changed from a fixed 500-site cap to a paginated do/while loop (100 per page), handling networks of any size. * Fix: `@package` docblock corrected from `LLMS_Txt_Manager` to `LLMS_Txt_Curator` across all PHP files. * Fix: `load_plugin_textdomain()` added, so the plugin is translation-ready. = 1.3.0 = * New: Multisite support (Chunks A to E, complete). Plugin header `Network: true`, network activation, per-site isolation, file path safety, network admin overview, and cron verification all done. * New: Network Admin overview page (Network Admin > Settings > LLMs.txt Curator) with summary strip, per-site status table, per-site Regenerate button, and Regenerate All Sites bulk action. Table updates live via AJAX without a page reload. * New: File mode column in network table: "Physical" (subdirectory) or "Rewrite" (subdomain/domain-mapped) with tooltip. * New: Regen schedule shown per-site in the network table. * New: Network Settings action link in the Network Admin plugins list. * New: `llms_txt_is_network_activated()` helper function. * New: `llms_txt_file_write_safe()` helper, preventing subdomain sub-sites from overwriting the main site's physical llms.txt. Those sites serve via rewrite rule instead. * New: `next_regen` key in `get_file_status()`: formatted next scheduled regeneration time (daily/weekly/instant debounce) for the current site. * Improvement: `maybe_schedule_recurring_regen()` now returns early on `is_network_admin()`, preventing the main site's cron schedule being unnecessarily re-synced on every network admin page load. * Improvement: All four cron methods updated with explicit multisite docblocks confirming per-site safety. * Improvement: WP-CLI handler docblock updated with `--url=` guidance for per-site usage on multisite networks. * Improvement: `delete_file()` in the generator guarded against subdomain sub-sites deleting a shared file. * Improvement: Activation hook accepts `$network_wide`; deactivation clears cron events across all sites. * Improvement: Uninstall iterates all sites; cleans up options, transients, cron, and files per-site. * Improvement: `LLMS_Txt_Admin` guarded from instantiating in network admin context. * Improvement: `get_file_status()` returns `is_network_activated`, `is_subdomain_network`, `file_write_safe`, `network_overview_url`, and `next_regen`. * Improvement: Validator surfaces info message on subdomain sub-sites confirming rewrite serving is intentional. * Improvement: Admin status panel and multisite notice contextually correct per site type. * Confirmed (docblocked): WP-Cron, option storage, transients, nonces, and capability checks are all natively per-site in multisite. No `switch_to_blog()` wrapping required in any cron path. * Removed: `wp_die()` block that previously blocked activation on non-main sites. = 1.2.2 = * New: AI Crawler Analytics -- 7-day bot activity bar chart on the Crawler Log tab, showing visit counts per bot. Refreshes without a page reload. * Improvement: Crawler Log tab restructured -- analytics card at top, all-time summary below, full visit log at the bottom. * Update: readme.txt updated to reflect all features added in v1.2.x. * Update: Stable tag updated to 1.2.2. = 1.2.1 = * New: Scheduled Regeneration -- choose between Instant, Daily, Weekly, or Manual update modes. Daily/Weekly use proper WP-Cron recurring events with next-run time displayed in the UI. * New: Safety Mode -- toggle to block generation on validation errors, with an on-demand validation card showing errors, warnings, and a plain-English stats summary. = 1.2.0 = * New: Description Suggestions -- one-click fills missing descriptions using a five-step fallback chain. Never overwrites manually-set descriptions. * New: Quality Score footer -- every generated file includes a Coverage Report showing quality score %, pages with descriptions, and pages needing attention. * New: Change Detection -- admin banner alerts when curated pages have been updated since last generation, with direct Regenerate Now action. * New: Per-page Title Override -- set an AI-optimised title for any page without touching on-site SEO. * Improvement: OpenGraph description added as step 4 in the description fallback chain. = 1.1.0 = * New: llms-full.txt generation -- full Markdown content for each curated page, per the llmstxt.org spec. * New: AI crawler detection -- logs visits from 12 known AI bots with anonymised IPs. * New: WooCommerce integration -- product data (SKU, price, stock, categories, dimensions) automatically included. * New: AI Crawler Log tab with summary stats and detailed visit log. * New: WP-CLI commands: `status`, `crawler-log`, `crawler-clear`. * New: REST API status endpoint. * New: robots.txt reference and rewrite rule for llms-full.txt. = 1.0.4 = * Initial public release. Drag-and-drop curation, validation engine, SEO plugin integration, schema-aware descriptions, pre-built templates, auto-regeneration, live preview, import/export, WP-CLI, REST API, atomic file writes, ETag caching. == Upgrade Notice == = 2.2.0 = Markdown pages now match what visitors see, including page builder content, with a new converter and a Markdown view for every page, plus read-only access for signed-in tools and agents. Fixes damaged Arabic, Persian and other non-Latin text. llms-full.txt is rebuilt once. = 2.1.0 = Notes for machines, Checks, ownership detection and bringing in an existing llms.txt. Your file now reads correctly with the llms.txt reference parser, so it changes once on upgrade. If you publish manually, click Publish once. = 2.0.0 = Major update. Your curation is migrated automatically and your published content does not change until you edit it, aside from Curator's two comment lines moving below the heading so the file starts with an H1. Back up first. Includes the 1.5.3 security fixes. Requires WordPress 6.2 or later. = 1.5.3 = Security fix. Files are now generated as a logged-out visitor, and members-only pages and blocks are kept out of llms.txt and llms-full.txt. Recommended for any site using a membership plugin. Regenerate after updating. = 1.5.2 = Fixes raw SEO variables (such as %seo_description%) in descriptions. Content Types now controls output, and noindex and password-protected pages are left out. Save or Regenerate after updating. = 1.5.1 = Generated files now carry a single H1 (the site name), clearing the "more than one H1" warning from third-party validators. Regenerate after upgrading to rewrite the file. = 1.5.0 = Adds opt-in Content Signals in robots.txt and a rel="describedby" header, repositions around Google's June 2026 llms.txt guidance, and tests up to WordPress 7.0. No breaking changes; Content Signals stays off until you enable it. = 1.4.6 = Adds explicit PHPCS ignore annotations for JSON blob input lines and updates Tested up to to 6.9. No functional changes. = 1.4.5 = Security fix: type validation hardening in sanitize_all_settings() and helper methods. No breaking changes. = 1.4.4 = Security fix: sanitizes preview AJAX input through the same sanitize_all_settings() pipeline used by save. No breaking changes. = 1.4.0 = Adds 30-day crawler analytics chart, last-crawled banner, first/last seen per bot, CSV export, and two new REST API endpoints. No breaking changes; existing data is preserved and the new daily aggregate store builds automatically from future visits. = 1.3.5 = Internal prefix change (llms_txt_ → llmscu_) for WordPress guidelines compliance. If you installed from the plugin repository, existing settings are preserved. If upgrading from a direct download, existing stored data will be re-initialised on first save. = 1.3.3 = Critical fix: resolves llms.txt 404 introduced in v1.3.2. Upgrade immediately if on v1.3.2. = 1.3.2 = Fixes UTF-8 encoding bug (em dashes rendering as â€"). Adds X-Robots-Tag: noindex option (on by default). No breaking changes; existing config preserved. = 1.3.1 = Security and robustness hardening: nosniff header, import size/schema validation, file size guard, query performance flags, diagnostics panel, health banner. Translation-ready. No breaking changes. = 1.3.0 = Adds full WordPress Multisite support. Existing single-site installs are unaffected. No breaking changes. = 1.2.2 = Adds 7-day AI crawler analytics. No breaking changes. = 1.2.1 = Adds Scheduled Regeneration and Safety Mode. No breaking changes. = 1.2.0 = Major quality-of-life release. Description Suggestions, Quality Score, Change Detection, Title Overrides. No breaking changes.