Follow-up to #134. The scorer already has manual as a source at weight 800, but the only way to feed it is Breeze's own settings row. That makes the one curated signal in the model the one signal a project cannot version.
The problem
SignalCollector::manualKeys() reads breeze-preload-cache-urls out of breeze_get_option( 'preload_settings' ). So a curated list:
- is not in git — it cannot be reviewed, and nothing records why a URL is on it
- is wiped by a database import, silently, and the site quietly stops warming what mattered
- has to be re-entered per environment, and differs between them by accident rather than intent
Measured on sloneek while adopting #134: the site's 53 category archives scored only through the manual list. They are in no menu, are not a homepage, and their lastmod is old — so with that row emptied they fell from position 27-30 to ~2864 of 2873. That project then decided the archives are not priority, which resolved it there, but the shape of the problem is general.
The signals the kit has are homepage, menu membership and freshness. A priority page that is none of those has no way up:
- a campaign landing page deliberately not in a menu
- a deep page carrying real search traffic
- a category archive on a project where it is priority
- anything correct and finished, so its
lastmod is old
Proposed shape
protected array $breeze_warmup_urls = array(
'/blog/',
'/cs/blog/',
'https://example.de/blog/',
);
Entries merge into manualKeys(), so they score at the existing manual weight and need no new weight, no new tier and no ordering change.
Both forms accepted, deliberately. A relative path is what a project wants most of the time — the same code runs on ddev, on staging and on production, and an absolute URL would be silently wrong on two of the three (rejected by is_local_url(), warming nothing, reporting nothing). An absolute URL is what a project needs when the target is not on home_url()'s host at all.
Which is the case with domain-per-language
isFetchableSameHostUrl() compares against home_url()'s host and nothing else. Under WPML's domain-per-language negotiation every non-default language is on a different host, so an absolute URL for one of them is rejected today.
SignalCollector already calls wpml_active_languages, which carries each language's url, so the allowed-host set is derivable. This feature needs it, and the sitemap crawl arguably wants the same treatment — though that is a separate change and should not ride along silently.
Open question
Whether a relative path should be expanded across active languages, or taken literally. Literal is more predictable and matches what is written; expansion saves five lines per entry on a five-language site and removes the chance of forgetting one. My inclination is literal, with expansion left to a filter, but it is worth deciding before the API exists rather than after.
Not proposed
Any change to ordering, weights or the cap. This adds an input to a source that already exists.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JMYy6JHLf4mU4H4Hd47spb
Follow-up to #134. The scorer already has
manualas a source at weight 800, but the only way to feed it is Breeze's own settings row. That makes the one curated signal in the model the one signal a project cannot version.The problem
SignalCollector::manualKeys()readsbreeze-preload-cache-urlsout ofbreeze_get_option( 'preload_settings' ). So a curated list:Measured on
sloneekwhile adopting #134: the site's 53 category archives scored only through the manual list. They are in no menu, are not a homepage, and theirlastmodis old — so with that row emptied they fell from position 27-30 to ~2864 of 2873. That project then decided the archives are not priority, which resolved it there, but the shape of the problem is general.The signals the kit has are homepage, menu membership and freshness. A priority page that is none of those has no way up:
lastmodis oldProposed shape
Entries merge into
manualKeys(), so they score at the existingmanualweight and need no new weight, no new tier and no ordering change.Both forms accepted, deliberately. A relative path is what a project wants most of the time — the same code runs on ddev, on staging and on production, and an absolute URL would be silently wrong on two of the three (rejected by
is_local_url(), warming nothing, reporting nothing). An absolute URL is what a project needs when the target is not onhome_url()'s host at all.Which is the case with domain-per-language
isFetchableSameHostUrl()compares againsthome_url()'s host and nothing else. Under WPML's domain-per-language negotiation every non-default language is on a different host, so an absolute URL for one of them is rejected today.SignalCollectoralready callswpml_active_languages, which carries each language'surl, so the allowed-host set is derivable. This feature needs it, and the sitemap crawl arguably wants the same treatment — though that is a separate change and should not ride along silently.Open question
Whether a relative path should be expanded across active languages, or taken literally. Literal is more predictable and matches what is written; expansion saves five lines per entry on a five-language site and removes the chance of forgetting one. My inclination is literal, with expansion left to a filter, but it is worth deciding before the API exists rather than after.
Not proposed
Any change to ordering, weights or the cap. This adds an input to a source that already exists.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JMYy6JHLf4mU4H4Hd47spb