Skip to content

Releases: Kntnt/kntnt-ai-visibility

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 16 Jul 16:49

Fixed

  • Resolved the WordPress 6.7+ "translation loading was triggered too early" notice that 0.5.0 reintroduced: the plugin logged one _load_textdomain_just_in_time notice on every request, whether or not any translations were installed. The Excluded paths field's label and help text are now translated lazily, when the settings page renders (after init), instead of while the plugin file is still being included. Settings\Field was the one value object that never received the lazy-label treatment Section and Capability_Column got in 0.2.2, so the two strings the 0.5.0 exclusion section introduced were resolved at bootstrap. Field now accepts a Closure(): string for both label and description, mirroring Section::title() and Capability_Column::label(), and unit tests guard all three against resolving a label at construction.

Full changelog: https://github.com/Kntnt/kntnt-ai-visibility/blob/v0.5.1/CHANGELOG.md

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 24 Jun 13:00

Added

  • Path exclusions: a new Excluded paths settings section (Settings → AI Visibility) curates individual entries out of every artifact — the per-page .md alternate, /llms.txt and /llms-full.txt — by listing path patterns, one regular expression per line, matched against each page's home-relative path (e.g. /cookiepolicy/). Patterns are written without delimiters or flags; matching is Unicode-aware and case-insensitive, an invalid pattern is reported and dropped when you save, and changing the patterns turns the cache over so the exclusion takes effect on the next request. The shared Core\Eligibility gate enforces it for both the per-page .md (is_eligible()) and the aggregates (enumerate()). Two developer filters customise it in code: kntnt_ai_visibility_exclusion_patterns (amend the pattern list) and kntnt_ai_visibility_is_excluded (force a per-post verdict).

Changed

  • build-release-zip.sh now builds dist/kntnt-ai-visibility.zip (creating dist/ when missing) when run with no arguments, instead of printing the usage text and exiting; an explicit destination (--output, --update or --create) still overrides this, and dist/ is git-ignored.

Full changelog: https://github.com/Kntnt/kntnt-ai-visibility/blob/v0.5.0/CHANGELOG.md

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 24 Jun 08:55

Added

  • The Link-headers module (Release 3): RFC 8288 HTTP Link headers that advertise every registered artifact on HTML responses — each singular page's Markdown alternate (rel="alternate", type="text/markdown") and the site-wide /llms.txt and /llms-full.txt singletons (rel="related", type="text/plain"). Headers are emitted on every HTML response through send_headers and skipped on admin, REST, feed, robots.txt and 404 responses; the early-router artifact path is deliberately left undecorated. Discovery_Context gains a nullable post so a provider can answer both the per-page and the site-wide discovery call, and relations are de-duplicated by the full (href, rel, type) triple.
  • The Content Signals module (Release 4): a site-wide, tri-state Content-Signal declaration spliced into the virtual robots.txt under User-agent: *, using the Content Signals Policy vocabulary (search / ai-input / ai-train). Each signal is grant (yes), reserve (no) or defer (omitted); the zero-config defaults – search=defer, ai-input=grant, ai-train=defer – emit the single line Content-Signal: ai-input=yes. An all-defer policy emits nothing and the block is suppressed entirely on a non-public site (blog_public = 0); a new "AI usage" settings section carries the three controls with inline warnings on visibility-reducing choices. A developer filter (kntnt_ai_visibility_content_signals) overrides the resolved policy in code. Specified in docs/spec/content-signals.md and ADR-0012; the CONTEXT.md glossary gains the term Content signal.
  • Developer-filter reference: docs/EXTENSIBILITY.md documents the plugin's kntnt_ai_visibility_* filters – the customisation surface for the Markdown alternates, llms.txt / llms-full.txt, the content signals and caching – with worked examples, and the README gains an Extending section that points to it.

Changed

  • The GitHub self-update check is now cached behind a filterable TTL (default six hours, kntnt_ai_visibility_update_check_ttl) and pinned to the expected GitHub host, so the plugin polls less often and ignores a response served from an unexpected host.
  • Less filesystem work on the cache-hit serve path: the cache-base real path is memoised and a response's ETag is computed only when it is needed.

Fixed

  • Control characters in a post's title, author or term names are now escaped in the Markdown front matter, so a stray control byte cannot break the YAML block.
  • /llms.txt no longer emits a section header for a content type that has no eligible posts.
  • Conditional requests honour a comma-separated If-None-Match list and weak ETags, so a matching validator returns 304 as it should.
  • The declared WordPress requirement is corrected to 6.7, from an erroneous 7.0, matching the actual minimum.

Security

  • The canonical host used in Link headers and advertised URLs is taken from the site configuration rather than the incoming Host header, so a spoofed Host cannot influence what the plugin advertises.
  • Single-flight lock files are written to a namespaced, restricted directory, preventing cross-install collisions and tightening the lock-file location.

Full changelog: https://github.com/Kntnt/kntnt-ai-visibility/blob/v0.4.0/CHANGELOG.md

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 23 Jun 06:46

Fixed

  • Resolved the WordPress 6.7+ "translation loading was triggered too early" notice. The settings-matrix column headers and the section heading are now translated lazily, when the settings page renders (after init), instead of when the plugin boots — so no translation is requested before init.

Full changelog: https://github.com/Kntnt/kntnt-ai-visibility/blob/v0.2.2/CHANGELOG.md

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 22 Jun 22:02

Changed

  • Lowered the minimum PHP version from 8.5 to 8.4. The floor came entirely from the bundled kntnt/html-to-markdown converter's use of the PHP-8.5-only Uri\Rfc3986\Uri class for relative-URL resolution; the converter now hand-ports RFC 3986 §5.2 reference resolution instead (byte-for-byte-identical output, verified by its golden fixtures), leaving the native Dom\HTMLDocument HTML5 parser (PHP 8.4) as the only floor driver. The bundled converter is bumped to ^0.1.3, and CI, PHPStan's phpVersion, the PHPCS testVersion and the Playground e2e harness now target PHP 8.4.

Full changelog: https://github.com/Kntnt/kntnt-ai-visibility/blob/v0.2.1/CHANGELOG.md

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 22 Jun 20:04

Added

  • This changelog.
  • CONTRIBUTING.md with contribution and pull-request guidance.
  • README sections: Questions, bugs, and feature requests, How you can contribute, and Changelog.
  • Modular architecture and design (a Core plus four feature modules) documented in docs/architecture.md, the CONTEXT.md glossary and architecture decision records under docs/adr/.
  • The coding standard is now materialised in the repository under agents.d/coding-standard/ – one module per language axis (general, PHP, WordPress and Bash) plus a private manifest.json snapshot – and loaded on demand rather than held in context every session.
  • On-demand agent guides under agents.d/: writing-standard.md, releasing.md and testing.md, each linked from the AGENTS.md References index.
  • Step 1.3 specification for Release 1 – the Markdown alternate – with concrete Core-slice and module contracts in docs/spec/markdown-alternate.md.
  • Core foundation for Release 1: the Module boot contract and the Core service facade; an artifact-provider registry with its identity, request, serve-pattern and link-relation value objects; a file-backed artifact cache and an early, hardened serve router that contains every request inside the cache directory (adversarially tested against path traversal, encoded traversal, null bytes and symlink escape); a zero-config settings registry over the single kntnt_ai_visibility option; and a visitor-silent logger.
  • Markdown-alternate generation: the shared Page-Markdown service that renders a post through the_content, converts the HTML to GitHub-Flavored Markdown (tables and strikethrough included) with relative URLs absolutised against the site, and assembles the YAML front-matter (title, canonical_url, date, author, and conditional featured_image, categories, tags) followed by the page's visible H1 and body, with single-flight caching; plus the Markdown-alternate provider and its eligibility rule (single, public, published, front-end-viewable entries — including pages, posts and public custom post types — with the static-home /index.md), resolving the target via url_to_postid() with hierarchical-page and published-post-slug fallbacks so a .md request still resolves when the rewrite has steered WordPress's main query to the front page.
  • Markdown-alternate serving and discovery: the request handler with strict content negotiation (.md URL > ?format=markdown > Accept: text/markdown), the inline uncached Accept form carrying Vary: Accept and a steering alternate link, Content-Type/Content-Length/Last-Modified/ETag headers with conditional 304s, a 403 for password-protected content, a 301 for a trailing-slashed .md URL, and canonical-redirect suppression; the per-page <link rel="alternate" type="text/markdown"> discovery tag on wp_head; delete-on-change invalidation (per entry on save and status transition, whole-cache flush on theme switch and settings change) with a cache-version stamp; and a filterable TTL safety net on the serve router.
  • The Markdown-alternate module is now wired into the plugin: the Plugin bootstrap builds the Core service graph and boots the module, and the early serve router runs from the main plugin file before WordPress routing — a cached .md request is served straight from disk and the WordPress lifecycle skipped, while a miss falls through to lazy generation.
  • A content-type settings section on the plugin's settings page: a Core-owned capability matrix — one row per front-end-viewable post type with a checkbox column per artifact kind a module registers (the Markdown .md column to begin with) — replacing the Markdown post-type text field, with the .md selection mirrored by the kntnt_ai_visibility_eligible_post_types filter and defaulting to every viewable type, plus a Clear cache button beside it that flushes every cached file.
  • Release-2 specification for the llms.txt module – the singleton llms.txt and llms-full.txt artifacts and the Core extensions they need (the content-type matrix, the markdown-alternate locator, the single-flight materialiser and the exact-path serve router) – in docs/spec/llms-txt.md.
  • A behavioural WordPress Playground end-to-end test (tests/Integration/playground-e2e.sh) that boots a real Playground HTTP server with the plugin mounted and fixtures seeded, then drives the request lifecycle over HTTP — a real .md (200, text/markdown, front-matter, the converted and absolutised body), ?format=markdown, Accept negotiation (Vary, the steering alternate Link), /index.md, a 404 for ineligible content, a 403 for password-protected content, a 301 for a trailing slash, and path-traversal payloads that never leak; and the llms singletons — /llms.txt (200, text/plain, the curated index with its sections and .md links, no canonical or Vary), /llms-full.txt (the concatenated Pages-only full text), the early-router cache hit with a stable ETag and a conditional 304, HEAD, the password-protected and draft content absent from both files, and traversal/evasion payloads against the singletons — wired into run-tests.sh and the CI e2e job alongside the boot smoke test.
  • The Playground e2e now also covers an invalidation round-trip — a mid-run content change (through a test-only mu-plugin endpoint) bumps the cache version, the rebuilt /llms.txt reflects the change and the orphaned previous-version aggregate is pruned — and a second, separate boot under a /sub subdirectory (tests/Integration/playground-e2e-subdir.sh) that proves the per-page .md and the llms singletons resolve home-relative and stay contained when WordPress lives under a path.
  • Subdirectory-install support: cache keys and request resolution are taken relative to the WordPress home (the serve router strips the same base path), so both per-page .md and the home /index.md resolve and cache correctly when WordPress lives under a path such as /blog/, not only at the domain root.
  • The llms.txt module – two discoverable, machine-readable files for AI agents. /llms.txt is a curated Markdown index: an H1 site name, the tagline, an intro line pointing at the full file, then one section per content type listing each page as a link to its .md alternate followed by its excerpt (titles escaped so they cannot break the link, excerpts stripped and length-capped). /llms-full.txt is the site's selected pages concatenated as Markdown, assembled from the per-page .md alternates and never re-rendered. Both are served as text/plain; charset=utf-8 straight from the early cache router on a warm hit – which gains an exact-path match mode alongside the .md suffix match, with the same path-traversal hardening – and generated lazily on a miss; they are invalidated by a cache-version bump when a public post is published, edited, unpublished or trashed (so a page that leaves public view is dropped promptly), with the existing TTL as a safety net, and never include password-protected content. Which content types appear in each file is the In llms.txt and In llms-full.txt columns of the content-type matrix (every viewable type in llms.txt, Pages only in llms-full.txt by default), each mirrored by a developer filter (kntnt_ai_visibility_llms_post_types, …_llms_full_post_types), with per-entry, title, summary, intro, sections and whole-document filters for full customisation.
  • README section Serving cached Markdown directly documenting the optional web-server tier (nginx and Apache try_files examples) that serves the cached .md files straight from disk, bypassing PHP entirely, with a fall-through to WordPress on a miss; it also notes that /llms.txt and /llms-full.txt are early-served from the PHP cache but, because their cache filename carries a version stamp a static rule cannot resolve, are not eligible for that no-PHP static tier.

Changed

  • The llms request handler now prunes the stale, version-stamped aggregate cache files that a cache-version bump orphans (for example llms-txt/llms-v7.md after a bump to v8), instead of leaving them until the TTL safety net or a cache flush removes them; pruning is scoped to the one aggregate directory and contained within the cache base, so it never touches the per-page .md cache.
  • Release tags are now v-prefixed (vX.Y.Z) and the GitHub-release notes are taken from the matching CHANGELOG.md section rather than GitHub's auto-generated digest (ADR-0011; ADR-0005 amended): the release workflow matches v[0-9]+.[0-9]+.[0-9]+, strips the v for the header-versus-tag check, and build-release-zip.sh --create publishes the changelog section as the release body.
  • Activation now registers the .md and the /llms.txt / /llms-full.txt rewrite rules and flushes them once; deactivation flushes the rewrite rules and clears the file cache while preserving the settings option; uninstall deletes the kntnt_ai_visibility option and the cache-version option and removes the file cache directory — replacing the scaffold's transient-based cleanup, since the cache is files under uploads rather than transients.
  • Documentation now follows British English via the kntnt-text-skills:writing-rules en_GB standard; the README uses spaced en-dashes ( – ) throughout.
  • Bumped actions/checkout and actions/setup-node to v5 (Node 24 runtime).
  • AGENTS.md slimmed to an always-loaded canon – authoritative ground rules, the non-obvious project facts and a References index – and CLAUDE.md reduced to a single @AGENTS.md bridge, cutting the always-loaded agent context by about 95 %.
  • README.md and CONTRIBUTING.md now point at agents.d/coding-standard/ for the coding standard and describe the agent-context files accurately.

Removed

  • docs/coding-standards.md – the monolithic coding standard, superseded by the on-demand modules under `agents.d/coding-standar...
Read more

0.1.0

Choose a tag to compare

@github-actions github-actions released this 04 Jun 15:44