Repository navigation
Releases
0.9.0
Added
sitemap --new-onlyandSitemap\SeenStoreInterface(wave N, spec 19b §3.5): submit only the URLs that are new
or changed since the last run of the command, whatever<lastmod>says or does not say. The interface (Implement
tier:unseen(iterable<SitemapEntry>): iterable<SitemapEntry>,remember(iterable<SitemapEntry>): void) keeps the
fingerprint of every announced entry — URL plus<lastmod>in ISO 8601, or empty;Console\SitemapRunnertakes it
as the appended, named$seen(SitemapServices::runner(…, seen:)likewise), callsunseen()once after the host
filter andremember()per batch whose results did not fail — with or without the option, never with--dry-run—
so a full run followed by scheduled--new-onlyruns announces each change once.Console\SitemapOptions::$newOnly;
Console\Definitions::sitemap()declares the option for every adapter. Without a store the option answers
SitemapRunner::NO_SEEN_STORE(--new-only needs a store of seen URLs; this application has none (the CLI keeps one in its state file).) with exit 2 and reads nothing — the framework adapters have none in this wave; theindexnow
CLI (indexnowkit/cli) keeps one in its sqlite state file. The summary line gains, N new or changed.
--changed-sinceand--new-onlyadd up: the window first, then the store.
Changed
- Requires
indexnowkit/core ^0.13.1.
0.8.0
Added
-
Console\SitemapRunnertakes?Psr\Clock\ClockInterface $clock = null(appended) andchangedSince(?string $option, ?DateTimeImmutable $now = null)counts a relative--changed-since("1 day") back from$now(wave M, spec 19 §4.9,
PSR-20):SitemapServices::runner(…, ?ClockInterface $clock = null)passes the graph's clock, soTesting\FrozenClock
moves the sitemap filter with the debounce window and the submission timestamps. Before, the runner read the wall
clock throughnew DateTimeImmutable('-1 day')— the one place of the family a frozen clock could not reach. An
absolute date is taken as it is, as before. -
Console\SitemapCommand(wave L, spec 18): theindexnow:sitemapcommand itself as a symfony/console class over
Console\SitemapRunner, with#[AsCommand];Sitemap\Adapter\SitemapServices::command($runner, $sitemapUrlOption)
builds it. The Symfony bundle and the Yii3 package register this class instead of a copy of their own; an adapter
without the package registersConsole\Command\SitemapNotInstalledCommandofindexnowkit/consoleunder the same
name. Constructor:(SitemapRunner $runner, string $sitemapUrlOption = 'sitemap.url')— the second names the
adapter'ssitemap.urloption in the help. -
Console\SitemapRunnertakesbool $enabled = true(appended) and answerssitemap.enabled is false.with exit 2
when it is off;SitemapServices::runner()passesSitemapConfig::$enabled. Before, the Yii3 command checked the flag
itself and the bundle registered no command at all (it still does); the one place is now the runner, whatever the
adapter chose.
Changed
-
Requires
indexnowkit/console ^0.5(the command classes and the stubs live there). -
A
<loc>on a host this site has no key for is dropped (Console\SitemapRunner), before anything fetches or
submits it: only the hostsKeyProviderInterface::managedHosts()names —base_urlplus thehostsmap — pass,
whatever source produced the entries. One line in the run summary (on stderr with--json) says how many URLs were
skipped and on which hosts. Nested sitemaps were already restricted to the origin of the root; the entries were not,
so a sitemap built from user content (or a swapped one) could make the pre-flight ofindexnowkit/verifyGET
internal addresses. With no key at all (neitherbase_urlnor ahostsmap) nothing can be compared: the entries go
as they are, with one warning.strict_hosts: trueis documented as the recommendation for a sitemap built from user
content. -
Sitemap\Adapter\SitemapServices::package()delegates to the core'sAdapter\OptionalPackage::sitemap()(core
0.13.0): the name, the marker and the feature word live there, so an adapter asks about the package without loading
this class. Same object, same texts; adapters should callOptionalPackage::sitemap()directly. -
Requires
indexnowkit/core ^0.13.
0.7.0
0.6.1
0.6.0
Changed
- The libxml error buffer is cleared before a sitemap is parsed: an error another library left in the process
(DOMDocument::loadHTML, a SOAP client) was read as this sitemap's and a correct file was refused. <lastmod>without a time zone (2026-09-06) is UTC, not the process time zone; an unparsable<lastmod>is a debug
line naming the URL instead of silence.- A nested sitemap on the same host with an explicit default port (
https://x.com:443) is the same origin. - A local sitemap index may only reference local parts inside its own directory (
<loc>/etc/passwd</loc>was read and
echoed line by line into the log as a "text sitemap"). - Requires
indexnowkit/core ^0.11.
0.5.1
0.5.0
Added
--no-verifyinConsole\Definitions::sitemap()andSitemapOptions::$noVerify:SitemapRunnertakes an appended
?SubmitterFactoryInterface $unverifiedSubmittersand submits through it (a fresh submitter,--forceor not) when the
flag is given — past the pre-flight ofindexnowkit/verifythe adapters decorate the regular factory with. Without a
second factory (no verify package) the flag is accepted and changes nothing.
Changed
- Requires
indexnowkit/core ^0.9andindexnowkit/console ^0.3.
0.4.0
Changed
- Requires
indexnowkit/core ^0.8andindexnowkit/console ^0.2.
Added
Check\SitemapSpoolChecklines carry the codesitemap.spool(SitemapSpoolCheck::CODE; core 0.8check --json).indexnow:sitemapwarns after a run without--changed-sincethat submitted more thanbatch.max_urlsURLs (the
whole sitemap: engines see every page as changed): run it once, then schedule it with--changed-since(spec 17
§3.3/§5.7). With--jsonthe warning goes to stderr.
0.3.0
Changed
- Requires core 0.7:
Console\SubmitterFactory/Console\SubmitterFactoryInterfaceare now
IndexNowKit\Adapter\SubmitterFactory/IndexNowKit\Adapter\SubmitterFactoryInterface,Console\ResultSummaryis
IndexNowKit\Submission\ResultSummary. Application code that names them (a decorator of thesubmittersargument ofConsole\\SitemapRunner) changes theuseline; nothing else. - The test suite requires
indexnowkit/testing ^0.1(require-dev): the conformance kits and the H01–H05 assertions
moved there from the core (Testing\Conformance\KeyFileAssertions,CheckOutputAssertions,ReadmeAssertions). - Requires
indexnowkit/console ^0.1andsymfony/console: the runners and the formatterConsole\SitemapRunner
builds on moved there from the core with their FQCN unchanged, and the runner renders throughSymfonyStylelike
every command body of the family;symfony/consoleleavessuggest(it is a requirement now).
Added
SitemapConfig::loadOrDisabled(array $block, LoggerInterface $logger, string $checkCommand): the runtime path of
an adapter —fromArray(), and for an invalid block onecriticallineindexnow: invalid sitemap configuration, the sitemap command is disabled until it is fixed: {error} (run "{check}")plusdisabled(). Replaces the copies
in Laravel and Yii2 (spec 17 §4.3).
Documentation
- README: "Notes for AI assistants" (package, minimal complete snippet, verification, pitfalls across the adapters);
ReadmeAiNotesTestkeeps it consistent with the commands and configuration keys. - README:
--forcere-announces URLs inside the debounce window (one-off, not for schedules);batch.max_urlsis a
ceiling, not a target. homepagein composer.json points at the docs site (https://indexnowkit.github.io/php/).
0.2.0
Changed
- Requires
indexnowkit/core ^0.6(wave 0a of docs/spec/17: the staging check, the debounce fix). No change in this
package's own API; upgrade together with the core.
Added
psalm.xmland a weekly Psalm taint analysis workflow in the monorepo: the reader parses untrusted XML, so tainted
data flow is checked separately from the phpstan pipeline. Psalm is not a dev dependency.
Documentation
- README: the Google paragraph, "notification, not indexing", and what
--changed-sincerelies on (<lastmod>; a
run without the option re-announces the whole sitemap;lastmod = now()makes every run a full run).