Starter template for building ReactPress plugins — server-side hooks, manifest-driven settings, locales, and Admin UI slots.
Aligned with fecommunity/reactpress/plugins · Plugin system reference · 简体中文
ReactPress plugins extend server-side business logic (hooks, content rules, integrations). They follow a WordPress-style model: install and enable from Admin, configure via plugin.json, integrate through register() and hook subscriptions.
| Extension | Responsibility | Runtime |
|---|---|---|
| Theme | Visitor UI, SSR | Next.js (:3001) |
| Plugin | Business rules, hooks | NestJS API (:3002) |
| Webhook | Outbound async notifications | Server HTTP |
Boundary: plugins must not inject theme routes or modify the Next.js build. Themes must not write to the database directly.
This repository ships a minimal working plugin (plugin-starter) that demonstrates:
| Capability | Implementation |
|---|---|
| Server entry | src/server/index.ts → register(hooks, ctx) |
| Hook subscription | article.afterPublish (action) |
| Manifest | plugin.json with settings.schema |
| Admin settings page | admin.menu → /plugins/plugin-starter/settings |
| i18n | src/locales/{locale}.json |
| Admin slot | src/admin/ + admin.slots → article.editor.meta.afterSummary |
| Item | Version |
|---|---|
| Node.js | >= 18 |
| ReactPress | >= 4.0.0 (see plugin.json → requires) |
| Toolkit | @fecommunity/reactpress-toolkit@^4.0.0-beta.18 (types & server build) |
Targets the ReactPress 4.0 plugin layout (
src/server,src/admin,src/locales). Install into the ReactPress monorepo for full runtime. Theplugin/serversubpath is exported from toolkit 4.x beta only.
git clone <your-repo-url> my-plugin
cd my-plugin
npm install # .npmrc enables legacy-peer-deps for toolkit peer resolution| File | Purpose |
|---|---|
plugin.json |
id, name, version, server.hooks.subscribe, settings.schema |
package.json |
Package name (e.g. @your-scope/reactpress-plugin-my-plugin) |
src/server/index.ts |
Hook handlers and business logic |
src/locales/*.json |
Admin UI strings for plugin name and settings fields |
Plugin id rules: kebab-case; must match the directory name under plugins/{id}/ in your ReactPress project.
npm run build
# Output: dist/index.js ← referenced by plugin.json → server.moduleCopy or symlink this directory into the ReactPress monorepo as plugins/{id}/ (id must match plugin.json → id):
# From your ReactPress project root
cp -r /path/to/my-plugin plugins/my-pluginUpdate plugin.json → $schema to the monorepo-relative path:
"$schema": "../plugin.manifest.schema.json"Add the plugin id to plugins/package.json:
{
"reactpress": {
"local": ["my-plugin"]
}
}Start development:
pnpm dev # compiles local plugins before the API startsEnable the plugin:
- Admin: Plugins → Install → Enable → Settings
- CLI:
reactpress plugin install my-plugin && reactpress plugin activate my-plugin
Plugin enable/disable does not require an API restart — hooks are hot-loaded at runtime.
Every plugin package uses the same layout: manifest at the root, all TypeScript under src/, split by runtime (aligned with ReactPress 4.0):
plugin-starter/
├── plugin.json # Manifest (id, hooks, settings schema, admin slots)
├── plugin.manifest.schema.json
├── package.json
├── tsconfig.json # extends tsconfig.base.json — server compile only
├── tsconfig.base.json # shared tsc defaults
├── README.md
├── README_zh.md
├── src/
│ ├── server/ # Node hook logic → tsc → dist/
│ │ ├── index.ts # export register(hooks, ctx)
│ │ ├── config.ts
│ │ └── types.ts
│ ├── admin/ # React Admin UI (bundled by web via Vite)
│ │ ├── index.ts # export registerAdmin(registry, ctx)
│ │ └── StarterPanel.tsx
│ └── locales/ # Admin UI strings (en.json, zh.json, …)
│ ├── en.json
│ └── zh.json
└── dist/ # plugin.json → server.module (./dist/index.js)
└── index.js
| Path | Runtime | Build |
|---|---|---|
src/server/ |
NestJS require() at API startup |
npm run build → tsc → dist/ |
src/admin/ |
Admin SPA (Vite import.meta.glob) |
Compiled when building web/ |
src/locales/ |
Admin i18n API | No build — served as JSON |
plugin.json |
Install / enable / config | No build |
This starter subscribes to one hook:
| Hook | Type | Behavior in this template |
|---|---|---|
article.afterPublish |
action | Logs article title to server output when logTitle is enabled |
Built-in hooks (full list in the plugin system reference):
| Hook | Type |
|---|---|
article.beforeCreate |
filter |
article.beforePublish |
filter |
article.afterPublish |
action |
comment.beforeCreate |
filter |
comment.afterCreate |
action |
This template implements article.afterPublish:
import type { HookService, PluginContext } from '@fecommunity/reactpress-toolkit/plugin/server';
export function register(hooks: HookService, ctx: PluginContext): void {
hooks.addAction(
'article.afterPublish',
async (payload) => {
// handle { article, isNew }
},
{ priority: 10, pluginId: ctx.id },
);
}
export function deactivate(): void {} // optional: cleanup on disableSettings are declared in plugin.json → settings.schema and persisted at:
globalSetting.plugins.entries.{id}.config
Update via Admin Settings or REST API:
curl -X PUT http://localhost:3002/api/extension/plugins/plugin-starter/config \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"config":{"enabled":true,"logTitle":false}}'Saving config triggers an automatic plugin reload.
plugin.json declares both a settings menu (admin.menu) and an editor slot (admin.slots). When the plugin is active, ReactPress Admin loads src/admin/index.ts via Vite import.meta.glob and calls registerAdmin().
| Declaration | Purpose |
|---|---|
admin.menu |
WordPress-style settings page at /plugins/{id}/settings |
admin.slots.subscribe |
Built-in editor mount points (enum ids) |
src/admin/index.ts |
registerAdmin() — register slot components |
Plugins with only
admin.menu(nosrc/admin/) still get a settings page — see hello-world.
Built-in slot ids:
| Slot id | Location |
|---|---|
article.editor.meta.afterSummary |
Article editor — below summary |
article.editor.sidebar.afterPublish |
Article editor — below publish box |
| Command | Purpose |
|---|---|
npm run build |
Compile src/server/ → dist/ |
npm run typecheck |
Type-check without emit |
npm run clean |
Remove dist/ |
After editing src/server/, rebuild and deactivate → reactivate the plugin in Admin, or save config to trigger reload. After editing src/admin/, rebuild the ReactPress web/ package.
| Import path | Used in | Purpose |
|---|---|---|
@fecommunity/reactpress-toolkit/plugin/server |
src/server/ |
HookService, PluginContext |
@fecommunity/reactpress-toolkit/plugin/admin |
src/admin/ |
Slot registration |
@fecommunity/reactpress-toolkit/plugin/react |
Core Admin pages | <AdminSlot /> mount points |
Rule: src/server/ must only import from @fecommunity/reactpress-toolkit/plugin/server.
Reference implementations: hello-world (server + settings menu), seo (server + admin slots).
- Copy this repository to
plugins/{your-id}/ - Update
plugin.json—id,name,server.hooks.subscribe - Implement business logic in
src/server/ - Register the id in
plugins/package.json→reactpress.local
| Resource | Link |
|---|---|
| ReactPress documentation | docs.gaoredu.com |
| ReactPress source | github.com/fecommunity/reactpress |
| Plugin system reference | plugins/README.md |
| Built-in plugin example | plugins/hello-world |
| Theme starter | reactpress-theme-starter |
| Toolkit (npm) | @fecommunity/reactpress-toolkit |
MIT License · © ReactPress / FECommunity