Theme Dependencies and Versioning
Some themes only work correctly when certain plugins are active (for example a
theme that relies on multilang for language-prefixed routing). GoPress lets a
theme declare the plugins it needs in theme.toml; core resolves and
enforces them.
This is a module-level dependency: the theme names a plugin by slug ("I need this whole plugin module"), but its runtime code still only benefits through core's generic extension points (hooks/filters/funcmap) β it never imports, calls, or references the plugin internals. Direction is theme β plugin only; pluginβplugin dependencies are not supported.
Declaration
Add a [requires] block to theme.toml:
[requires]
core = ">=0.7.0" # optional: required GoPress core version (semver constraint)
plugins = [
{ slug = "multi-language", version = ">=2.0.0" },
{ slug = "seo-extras", version = "^1.0.0", optional = false },
]
slugβ the required plugin's runtime identity (itsName(), also declared in the plugin'splugin.toml[plugin].slug). Note the slug can differ from the plugin directory name (dirmultilangβ slugmulti-language).versionβ optional semver constraint (>=2.0.0,^1.0,~1.2,>=1 <2, β¦). Empty means any version.optionalβ whentrue, an unmet dependency is a warning, not a hard block.coreβ optional constraint on the core version.
Mandatory versioning
Theme and plugin versions must be valid semver and come from a single source:
- Theme version comes from
theme.toml [theme].version(the theme embeds it via//go:embed theme.toml;BaseThemeparses it β do not hardcode it in Go). - Plugin version comes from
plugin.toml [plugin].version(the plugin embeds it via//go:embed plugin.toml).
Both toml files are baked into the binary via //go:embed and read the same
way, so if you change code you must bump the matching toml version β otherwise the
binary reports a stale version.
Core validates versions at build time (gopress gen/build) and at boot.
The four dependency states
| State | Meaning | Handling |
|---|---|---|
| Satisfied | plugin present, active, version in range | allowed |
| Inactive | present and in range but not activated | auto-activatable (offered on theme switch) |
| Version mismatch | active but version fails the constraint | blocks (shows required vs installed) |
| Missing | not compiled into this build | hard block (see "compile-time reality") |
Compile-time reality (the key WordPress difference)
GoPress plugins are compiled into the binary β there is no runtime install. A
missing dependency cannot be fixed at runtime; you must add the plugin to the
build and re-run gopress build. The admin never offers "install"; it only
auto-activates plugins that are compiled in but inactive.
When it is enforced, and how it shows
- Build time (
gopress gen/build): scans each theme's[requires]and warns about missing plugins, invalid semver, and unmet version constraints. - Boot: resolves the active theme's dependencies β inactive required plugins are auto-activated; missing/incompatible ones let the site boot but raise a warning banner in the admin.
- Theme switch: the target theme is pre-checked.
- Inactive deps: the switch confirm dialog lists the plugins that will be enabled; on confirm the switch is transactional (activate plugins first, roll back on failure).
- Missing/version mismatch: the card shows a red "missing dependency" badge, the switch button is disabled, and the reason is shown on hover.
- Plugin deactivate: if the active theme depends on a plugin, its deactivate button is disabled with "required by the active theme; switch themes first".
For plugin authors: the plugin.toml slug
To be depended on, a plugin's plugin.toml must declare slug, and it must equal
the plugin's Name():
[plugin]
slug = "multi-language" # runtime identity; themes depend on this; must equal Name()
name = "Multi-Language" # human-readable display name
version = "2.0.0"
