Plugin System Overview
Plugins extend GoPress through public core contracts. They can register hooks, add admin settings pages, store plugin-owned data, inject frontend HTML into standard template slots, transform SEO metadata, and participate in multilingual or sitemap behavior.
Core Ideas
- Plugins register themselves with
core.RegisterPlugin. - Activation state is stored in options and can be changed from the admin. If the new state cannot be persisted, core reverts the toggle and reports an error, so runtime and persisted state always agree.
- Core serializes activation changes and theme switches; activating an active
plugin is a no-op, and
PluginManager.IsActiveis lock-free for request paths. - Plugins that own background goroutines can implement
plugin.Stopper; core callsStop(ctx)during process shutdown after HTTP requests drain. See Creating Plugins. - Hooks returned during activation must be removed during deactivation.
- Plugin database tables should use
dbprefix.PluginTable. - Plugin admin UI should use core settings-provider interfaces and locale files.
- Activation and deactivation rebuild the Gin router, so currently active
middleware.earlyandroutes.registerhooks take effect immediately. - Core clears frontend cache after activation changes, preventing cached pages from retaining removed navigation or script output.
- Sitemap transformers and other registration APIs return symmetric remove handles and follow the same lifecycle contract.
- Plugins can contribute protocol-neutral Agent tools through the Core Agent Registry and revoke their handles on deactivation. Authentication, scopes, RBAC, risk policy, idempotency, and audit remain mandatory Core Executor wrappers rather than plugin-specific implementations.
Plugin Lifecycle
register -> activate -> setup hooks/settings/routes -> run -> deactivate -> remove hooks
Hot disable is an important contract. A disabled plugin should stop affecting admin forms, frontend HTML, SEO metadata, sitemap output, menus, and middleware behavior without requiring a process restart.
Long-lived workers and requests already executing on the previous router still need a lightweight runtime-active guard. Deactivation preserves plugin-owned data unless an explicit uninstall workflow says otherwise.
Common Extension Points
| Extension point | Purpose |
|---|---|
admin.content_list.tabs |
Add filtered content-list tabs and counts. |
admin.taxonomy_list.tabs |
Add request-aware variants above taxonomy lists. |
admin.content.permalink_prefix |
Add contextual editor URL prefixes. |
admin.content_form.fields |
Add editor meta boxes. |
admin.content.saved |
Persist extension-owned form values. |
admin.dashboard.widgets |
Add permission-aware dashboard summaries. |
seo.content.meta |
Transform single-page SEO metadata. |
seo.taxonomy.meta |
Add canonical alternates to taxonomy archives. |
theme.head.end, theme.body.open, theme.footer.end |
Inject site-level markup at semantic frontend slots. |
header.nav.after |
Add a primary-navigation extension item. |
The Hook System and Admin Extension Points document the payloads.
Built-in Plugins
| Plugin | Purpose |
|---|---|
multilang |
WPML-like content and optional Category/Tag translation, menu assignment, canonical language-prefixed URLs, and setting translations. |
seo-extras |
Yoast-like per-content SEO title, description, Open Graph image, and robots overrides. |
code-snippets |
WPCode-like site-level HTML/JS injection into head, body, and footer slots. |
gopress-analytics |
First-party self-hosted page-view, visitor, trend, and top-page analytics. |
gopress-mcp |
Disabled-by-default remote MCP adapter with six read tools, six controlled write tools, short-lived credentials, per-tool Safe Write policy, diagnostics, and audit. |
google-identity |
Google OpenID Connect login and registration through the core public-auth contract. |
metamask-identity |
MetaMask and EIP-4361 Sign-In with Ethereum login and registration through one-time server challenges. |
Boundary Rule
Plugins should only depend on core packages and public interfaces. They should not import a theme, assume a theme's HTML structure, or scan final HTML responses to patch output.
See Public Authentication for identity-provider and theme integration rules.
