- architecture: introduction, Go modules and workspaces, application lifecycle, request lifecycle - plugins: registration, scheduling, extending, testing - verified Examples for backpack services, towel request context, pact schedules and festival events - TestDocsRequiredPages lists the eight new pages
119 lines
6.5 KiB
Markdown
119 lines
6.5 KiB
Markdown
---
|
|
title: Plugin registration
|
|
description: "Declare a plugin: its ID, the party.Plugin lifecycle, the pact capability interfaces it opts into, its embedded files and the scaffolded layout."
|
|
section: plugins
|
|
order: 10
|
|
---
|
|
# Plugin registration
|
|
|
|
Plugins are the foundation of every SummerCMS application. A plugin adds models, routes, admin screens, console commands, jobs and translations, and it can extend other plugins. This page covers how a plugin tells the framework what it contributes.
|
|
|
|
## Plugin identifiers
|
|
|
|
Every plugin has an ID in `vendor.plugin` form: two lower-case parts, each starting with a letter and containing only letters and digits, such as `acme.blog`. The ID is how the manifest lists the plugin, how other plugins require it and how its configuration is namespaced (`acme.blog.posts_per_page`). WinterCMS writes the same identifier as `Acme.Blog`; in SummerCMS it is always lower case.
|
|
|
|
The scaffolder derives the package and directory name from the second part, so `summer make:plugin acme.blog` creates `plugins/blog` with `package blog`.
|
|
|
|
## The plugin type
|
|
|
|
A plugin is a Go type that implements `party.Plugin`. Its package registers it from `init` with `party.Register`, so importing the package is enough to make the plugin available; the generated `plugins.gen.go` does that import for every plugin in `summer.yaml`.
|
|
|
|
| Method | Purpose |
|
|
|--------|---------|
|
|
| `party.Plugin.ID` | Returns the plugin ID. |
|
|
| `party.Plugin.Requires` | Lists the IDs of plugins that must register and boot before this one, like `$require` in WinterCMS. |
|
|
| `party.Plugin.Register` | Runs before any plugin boots. Publish services on the container here. |
|
|
| `party.Plugin.Boot` | Runs after every plugin registered. Listen to events and use other plugins' services here. |
|
|
|
|
Here is a complete plugin that also declares a backend permission:
|
|
|
|
```go src=modules/party/example_plugin_test.go
|
|
package party_test
|
|
|
|
import (
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
)
|
|
|
|
// BlogPlugin is the acme.blog plugin: the Go form of a WinterCMS Plugin.php.
|
|
// A real plugin package also registers it from init with
|
|
// party.Register(&BlogPlugin{}).
|
|
type BlogPlugin struct{}
|
|
|
|
// The optional capabilities the plugin opts into, checked at compile time.
|
|
var _ pact.HasPermissions = (*BlogPlugin)(nil)
|
|
|
|
// ID is the plugin identifier in vendor.plugin form.
|
|
func (p *BlogPlugin) ID() string { return "acme.blog" }
|
|
|
|
// Requires lists the plugins that must register and boot first ($require).
|
|
func (p *BlogPlugin) Requires() []string { return []string{"acme.user"} }
|
|
|
|
// Register runs before any plugin boots: publish services here.
|
|
func (p *BlogPlugin) Register(app *backpack.App) error { return nil }
|
|
|
|
// Boot runs after every plugin registered: listen to events and look up
|
|
// services other plugins published.
|
|
func (p *BlogPlugin) Boot(app *backpack.App) error { return nil }
|
|
|
|
// Permissions replaces registerPermissions().
|
|
func (p *BlogPlugin) Permissions() []pact.Permission {
|
|
return []pact.Permission{
|
|
{Code: "acme.blog.access_posts", Tab: "Blog", Label: "Manage posts"},
|
|
}
|
|
}
|
|
```
|
|
|
|
The `var _ pact.HasPermissions = (*BlogPlugin)(nil)` line is a compile-time check: if a method is missing or has the wrong signature, the build fails instead of the capability being silently ignored. Add one such line for every capability your plugin implements.
|
|
|
|
## Capability interfaces
|
|
|
|
A WinterCMS plugin overrides `register*` methods of `PluginBase`. A SummerCMS plugin implements small interfaces from [pact](../../modules/pact/README.md) instead, and the framework discovers each one with a type assertion.
|
|
|
|
| Interface | Contributes |
|
|
|-----------|-------------|
|
|
| `pact.HasRoutes` | HTTP routes, declared on a `pact.Router`. |
|
|
| `pact.HasMiddleware`, `pact.HasMiddlewareFactories` | Named and parameterized route middleware. |
|
|
| `pact.HasConfig` | Default configuration, merged under the plugin ID. |
|
|
| `pact.HasMigrations` | An ordered set of database migrations. |
|
|
| `pact.HasCommands` | Console commands for the application binary. |
|
|
| `pact.HasJobs` | Background jobs. |
|
|
| `pact.HasSchedule` | Console commands that run on a schedule; see [Scheduling](scheduling.md). |
|
|
| `pact.HasLang`, `pact.HasLangOverrides` | Translations, and overrides of other namespaces. |
|
|
| `pact.HasMailTemplates` | Mail templates and layouts. |
|
|
| `pact.HasPermissions`, `pact.HasNavigation`, `pact.HasSettings` | Backend permissions, navigation and settings screens. |
|
|
| `pact.HasAdminControllers` | Admin controllers built from `fields.yaml` and `columns.yaml`. |
|
|
| `pact.HasModels` | The plugin's GORM models. No framework package reads it yet. |
|
|
|
|
## Embedded files
|
|
|
|
Configuration defaults, translations and mail templates ship inside the binary through Go's `embed` package. The plugin returns an `fs.FS` for each:
|
|
|
|
- `pact.HasConfig.ConfigFS` returns a tree with `config/config.yaml`. Its keys become `<plugin id>.<key>`, and any other `config/<name>.yaml` becomes `<plugin id>.<name>.<key>`. The application's own `config/` directory and `SUMMER_` variables override them.
|
|
- `pact.HasLang.LangFS` returns `lang/<locale>/<group>.yaml` files.
|
|
- `pact.HasMailTemplates.MailTemplatesFS` returns the `views/mail` templates, and `pact.HasMailTemplates.MailTemplates` lists their names.
|
|
|
|
## The scaffolded layout
|
|
|
|
`summer make:plugin acme.blog` writes a plugin that compiles and follows the WinterCMS directory layout, with each directory as a Go subpackage:
|
|
|
|
```text
|
|
plugins/blog/
|
|
├── go.mod the plugin module, requiring the framework
|
|
├── plugin.go the Plugin type, its capabilities and init registration
|
|
├── routes.go the Routes method
|
|
├── registry.gen.go generated lists of models, migrations, commands, jobs and admin controllers
|
|
├── classes/ services and hooks
|
|
├── config/config.yaml default configuration
|
|
├── console/ console commands
|
|
├── controllers/ HTTP handlers and admin controllers
|
|
├── jobs/ background jobs
|
|
├── lang/en/lang.yaml translations
|
|
├── middleware/ named middleware
|
|
├── models/ GORM models
|
|
├── updates/ migrations
|
|
└── views/mail/ mail templates
|
|
```
|
|
|
|
The `make:` commands, such as `summer make:model acme.blog Post`, add files to these directories and regenerate `registry.gen.go`, so you do not edit that file by hand. The capability methods in `plugin.go` return the generated lists, so a new model, migration, command, job or admin controller is picked up without editing the plugin type.
|