// Package contract is the published seam of the golem15.sitemap plugin: // the Filter another plugin implements to keep addresses out of the // sitemaps or move them to another file group, and the Listing other // plugins read to show the sitemap's addresses (an HTML sitemap, IndexNow). // // It is a package of its own so a plugin can import it without importing // the sitemap plugin's root package, whose init registers the plugin. The // sitemap plugin depends on no implementation: it looks a Filter up with // // f, ok := app.Lookup[contract.Filter]() // // and includes every published address when none is published. A plugin // publishes one in its Register: // // app.Publish[contract.Filter](myFilter{}) package contract import ( "context" "time" ) // The reasons a Decision may give for leaving an address out. The sitemap // counts excluded addresses by reason; another reason is counted under its // own name. const ( // ReasonNoindex is an address whose page is set to noindex. ReasonNoindex = "noindex" // ReasonCanonical is an address whose canonical URL points elsewhere. ReasonCanonical = "canonical" // ReasonRedirect is an address that redirects. ReasonRedirect = "redirect" // ReasonType is an address of a content type switched off in the // sitemap settings; the sitemap sets it itself, a Filter need not. ReasonType = "type" ) // Candidate is one address the sitemap would list: TypeKey is the content // type key (a signpost menu item type, or "extra" for an additional address // of the settings), RecordID the record's ID within it (for an additional // address the hex SHA-256 of its path), Locale the locale ("" when the // address has none) and URL its public path or absolute URL. type Candidate struct { TypeKey string RecordID string Locale string URL string } // Decision is a Filter's answer for one Candidate. Exclude leaves the // address out of the sitemap files, counted under Reason. Group, when not // empty, puts the address in another file group: the files are then named // sitemap--.xml, so a Group must use lowercase letters, digits and // hyphens (another value is ignored). LastMod, when set, is the first // lastmod of an address the sitemap has not listed before; it never moves // the lastmod of a listed address. type Decision struct { Exclude bool Reason string Group string LastMod *time.Time } // Group names a file group a Filter's decisions use: Key is the group as // in Decision.Group, Titles its heading per locale for an HTML sitemap. type Group struct { Key string Titles map[string]string } // Filter decides which addresses the sitemap lists. Decide receives one // batch (a page of records of one content type, or the additional // addresses) and answers one Decision per Candidate in the same order; an // answer of another length or an error fails the rebuild, which keeps the // files it served before. Groups lists the groups the Filter's decisions // may name, with their titles. type Filter interface { Decide(ctx context.Context, batch []Candidate) ([]Decision, error) Groups(ctx context.Context) ([]Group, error) } // Listing is what the sitemap publishes for other plugins: its settings and // the listed addresses of each group. The sitemap plugin publishes it with // app.Publish[contract.Listing] in its Register. type Listing interface { Settings(ctx context.Context) (ListingSettings, error) Entries(ctx context.Context, q EntriesQuery) (EntriesPage, error) } // ListingSettings are the sitemap's settings as other plugins need them. // SiteURL is the absolute site address every address starts with ("" when // none is configured), IndexURL the absolute address of the sitemap index, // DefaultLocale the site's default locale ("" when not set) and Groups the // file groups with listed addresses. HTMLEnabled, HTMLPaths (locale to // path), HTMLPageSize and KeyFile (the IndexNow key file name) describe the // HTML sitemap and IndexNow; they stay zero until those settings exist. type ListingSettings struct { SiteURL string IndexURL string DefaultLocale string Groups []GroupInfo HTMLEnabled bool HTMLPaths map[string]string HTMLPageSize int KeyFile string } // GroupInfo is one file group: Key is the group (as Entries takes it), Slug // the name part of its files (sitemap--.xml; today the same as // Key), Titles its heading per locale and Count its listed addresses. type GroupInfo struct { Key string Slug string Titles map[string]string Count int } // EntriesQuery asks for one page of a group's listed addresses. Locale, // when set, keeps the addresses of that locale and those without one. // After is the Next of the previous page ("" for the first) and Limit the // page size (at most 1000; 0 means 100). type EntriesQuery struct { Group string Locale string After string Limit int } // Entry is one listed address. URL is absolute (on ListingSettings.SiteURL) // and LastMod its last real change, nil when unknown. type Entry struct { Group string TypeKey string RecordID string Locale string URL string Title string LastMod *time.Time } // EntriesPage is one page of Entries in a stable order: Next is the After // of the following page ("" on the last page) and Total the number of // addresses the query matches across all pages. type EntriesPage struct { Entries []Entry Next string Total int }