Cross-product, then dedupe
The topic and city lists are crossed into candidate slugs. Each is checked against pages(hub_id, slug) — a unique index in SQLite — so re-running the same matrix costs nothing and never overwrites live copy.
Pick a hub, give it topics and cities, and it writes the cross-product. Sitemaps rebuild on publish and go to Search Console on the next cron tick. Nothing here waits on you clicking through a CMS.
Select a hub to target it in the generator below. Sitemap age is measured from the last successful rebuild.
One page per filled cell. Dark squares are new; grey squares already exist and will be skipped, not overwritten.
Sitemaps rebuild automatically when a generate run publishes. Submission goes through the Search Console API with the stored service-account credential for each verified property.
Google deprecated the anonymous /ping?sitemap= endpoint in 2023. Submissions here use the Search Console API sitemaps.submit method, which requires the property to be verified and the service account added as an owner.
Live links. Index state is refreshed nightly from the URL Inspection API — it lags real indexing by up to a day.
The topic and city lists are crossed into candidate slugs. Each is checked against pages(hub_id, slug) — a unique index in SQLite — so re-running the same matrix costs nothing and never overwrites live copy.
Each cell is a single generation with the hub's brand voice, service area and internal-link targets in the prompt. Output lands in a draft row. Failures retry twice, then park in failed with the error text rather than silently dropping.
Publishing flips status and triggers a sitemap rebuild for that hub. A cron job submits changed sitemaps to Search Console and pulls index coverage back into pages.index_state overnight.