- classes.SitemapFilter implements the sitemap plugin's contract.Filter on the production values: redirected, noindex and canonicalised addresses leave the sitemaps with their reason; staging lists the same set - the plugin requires golem15.sitemap and publishes the filter in Register - go.mod requires sm-sitemap-plugin, go.work mounts the sibling checkout
101 lines
3.2 KiB
Go
101 lines
3.2 KiB
Go
// Package seo is the golem15.seo plugin: per-record and per-URL SEO for
|
|
// every content type registered in signpost, global SEO settings, history,
|
|
// and the effective SEO of a URL for the frontend. Content plugins never
|
|
// import it: they register a content descriptor (pact.ContentDescriptor) on
|
|
// their menu item type, and this plugin adds an SEO tab to their admin form
|
|
// through a form extension and stores the values in its own tables.
|
|
package seo
|
|
|
|
import (
|
|
"embed"
|
|
"fmt"
|
|
"io/fs"
|
|
|
|
"git.golem15.com/golem15/sm-seo-plugin/classes"
|
|
"git.golem15.com/golem15/sm-seo-plugin/models"
|
|
"git.golem15.com/golem15/sm-seo-plugin/updates"
|
|
"git.golem15.com/golem15/sm-sitemap-plugin/contract"
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
"git.golem15.com/golem15/summercms/modules/party"
|
|
"git.golem15.com/golem15/summercms/modules/surf"
|
|
"github.com/go-gormigrate/gormigrate/v2"
|
|
)
|
|
|
|
var (
|
|
_ party.Plugin = (*Plugin)(nil)
|
|
_ pact.HasConfig = (*Plugin)(nil)
|
|
_ pact.HasMigrations = (*Plugin)(nil)
|
|
_ pact.HasModels = (*Plugin)(nil)
|
|
_ pact.HasRoutes = (*Plugin)(nil)
|
|
_ pact.HasAdminActionExtensions = (*Plugin)(nil)
|
|
_ pact.HasLang = (*Plugin)(nil)
|
|
_ surf.BucketProvider = (*Plugin)(nil)
|
|
)
|
|
|
|
//go:embed config
|
|
var configFS embed.FS
|
|
|
|
//go:embed lang
|
|
var langFS embed.FS
|
|
|
|
// Plugin is the golem15.seo plugin.
|
|
type Plugin struct {
|
|
app *backpack.App
|
|
service *classes.Service
|
|
}
|
|
|
|
func (p *Plugin) ID() string { return "golem15.seo" }
|
|
|
|
// SitemapPluginID is the sitemap plugin the SEO plugin requires: it
|
|
// decides which addresses the sitemaps list (D-95). Content types are still
|
|
// found through signpost, never by plugin ID.
|
|
const SitemapPluginID = "golem15.sitemap"
|
|
|
|
// Requires names the sitemap plugin, whose Filter seam the SEO plugin
|
|
// implements (D-95).
|
|
func (p *Plugin) Requires() []string { return []string{SitemapPluginID} }
|
|
|
|
// Register publishes the sitemap filter (classes.SitemapFilter): noindex,
|
|
// canonicalised and redirected addresses leave the sitemaps (D-95, D-24).
|
|
// It reads the service lazily, since Boot builds the service.
|
|
func (p *Plugin) Register(app *backpack.App) error {
|
|
p.app = app
|
|
return app.Publish[contract.Filter](classes.SitemapFilter{Service: p.Service})
|
|
}
|
|
|
|
// Boot builds the service on the application's database, signpost registry
|
|
// and config, and subscribes to the record events.
|
|
func (p *Plugin) Boot(app *backpack.App) error {
|
|
p.app = app
|
|
svc, err := classes.NewService(app)
|
|
if err != nil {
|
|
return fmt.Errorf("golem15.seo: %w", err)
|
|
}
|
|
p.service = svc
|
|
p.listen(app)
|
|
return nil
|
|
}
|
|
|
|
// Service returns the booted service, nil before Boot.
|
|
func (p *Plugin) Service() *classes.Service {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
return p.service
|
|
}
|
|
|
|
// ConfigFS ships config/config.yaml.
|
|
func (p *Plugin) ConfigFS() fs.FS { return configFS }
|
|
|
|
// LangFS is the embedded English and Polish phrasebooks.
|
|
func (p *Plugin) LangFS() fs.FS { return langFS }
|
|
|
|
func (p *Plugin) Migrations() []*gormigrate.Migration { return updates.All() }
|
|
|
|
func (p *Plugin) Models() []any { return models.All() }
|
|
|
|
func init() {
|
|
party.Register(&Plugin{})
|
|
}
|