Plugins are a way to extend the functionality of the Answer project. You can create your own plugins to meet your own needs.
:::tip
Viewing the official plugin code will make you to quickly understand and learn plugin development.
:::
:::info
Recommended: Use the official scaffolding tool create-answer-plugin to create and manage plugins. It automates most of the setup process, including file generation, Go module configuration, and plugin installation.
:::
Currently we have three types of plugins:
We classify plugins into different types. Different types of plugins have different functions. Plugins of the same type have the same effect, but are implemented differently.
| Plugin Name | Template Type | Description |
|---|---|---|
| Connector | Backend Plugin | The Connector plugin helps us to implement third-party login functionality |
| Storage | Backend Plugin | The Storage plugin helps us to upload files to third-party storage. |
| Cache | Backend Plugin | Support for using different caching middleware. |
| Search | Backend Plugin | Support for using search engines to speed up the search for question answers. |
| User Center | Backend Plugin | Using the third-party user system to manage users. |
| Notification | Backend Plugin | The Notification plugin helps us to send messages to third-party notification systems. |
| Route | Standard UI Plugin | Provides support for custom routing. |
| Editor | Standard UI Plugin | Supports extending the markdown editor's toolbar. |
| Captcha | Standard UI Plugin | Provides support for captcha. |
| Reviewer | Backend Plugin | Allows customizing the reviewer functionality. |
| Filter | Backend Plugin | Filter out illegal questions or answers. (coming soon) |
| Render | Standard UI Plugin | Parsers for different content formats. (coming soon) |
:::info
The name field in package.json is the name of the package we add dependencies to; do not use _ to connect this field naming, please use -; for example:
“editor-chart” ✅
“editor_chart” ❌
:::
The easiest way to create a plugin is using the official scaffolding tool:
# Install the tool globally (optional) npm install -g create-answer-plugin # or pnpm add -g create-answer-plugin # Or use npx directly (recommended) npx create-answer-plugin create <pluginName> # or use the alias npx answer-plugin create <pluginName> # or use the simplified form npx answer-plugin <pluginName>
Note: The package name is create-answer-plugin, but you can use either create-answer-plugin or answer-plugin as the command (both work!).
The tool will:
go.mod with all dependenciesOptions:
pluginName (optional): Pre-fill the plugin name--path, -p: Path to Answer project (root directory). If not specified, defaults to current directory.Example:
# Navigate to your Answer project root cd /path/to/answer # Create a plugin npx create-answer-plugin create my-plugin # or with path option npx create-answer-plugin create my-plugin --path /path/to/answer # Select: Standard UI Plugin → Route # Enter route path: /hello
The plugin will be created in ui/src/plugins/my-plugin/ (note: plugins is plural).
If you prefer to create plugins manually:
Go to the ui > src > plugins directory of the project (note: plugins is plural).
Create your plugin directory and files following the structure of existing plugins.
The easiest way to install a plugin is using the scaffolding tool's install command:
# Navigate to your Answer project root cd /path/to/answer # Install a specific plugin (automatically handles registration) npx create-answer-plugin install my-plugin # or npx answer-plugin install my-plugin # or with path option npx answer-plugin install my-plugin --path /path/to/answer # Install all not installed plugins npx create-answer-plugin install
Options:
plugins (optional): Plugin names to install (defaults to all not installed plugins)--path, -p: Path to Answer project (defaults to current directory)The install command automatically:
cmd/answer/main.goreplace directive to go.modgo mod tidygo run ./cmd/answer/main.go i18nList all plugins in the Answer project:
# List all plugins npx create-answer-plugin list # or npx answer-plugin list # or with path option npx answer-plugin list /path/to/answer
Options:
path (optional): Path to Answer project (defaults to current directory)Uninstall plugins from the Answer project:
# Uninstall all installed plugins npx create-answer-plugin uninstall # or npx answer-plugin uninstall # Uninstall specific plugins npx create-answer-plugin uninstall my-plugin another-plugin # or with path option npx answer-plugin uninstall my-plugin --path /path/to/answer
Options:
plugins (optional): Plugin names to uninstall (defaults to all installed plugins)--path, -p: Path to Answer project (defaults to current directory)The uninstall command automatically:
cmd/answer/main.goreplace directive from go.modgo mod tidyInstall the plugin using the scaffolding tool (see above).
Build the frontend:
cd ui pnpm pre-install pnpm build cd ..
Merge i18n resources (if not done automatically):
go run ./cmd/answer/main.go i18n
Start the project:
go run cmd/answer/main.go run -C ./answer-data
If you prefer to install manually:
First, build the frontend:
cd ui pnpm pre-install pnpm build cd ..
In the cmd > answer > main.go file, import your plugin:
import ( answercmd "github.com/apache/answer/cmd" // Import the plugins _ "github.com/apache/answer/ui/src/plugins/my-plugin" )
Use go mod edit to add the plugin to the go.mod file:
go mod edit -replace=github.com/apache/answer/ui/src/plugins/my-plugin=./ui/src/plugins/my-plugin
Update the dependencies:
go mod tidy
Merge i18n resources:
go run ./cmd/answer/main.go i18n
Start the project:
go run cmd/answer/main.go run -C ./answer-data
Install the plugin using the scaffolding tool:
cd /path/to/answer npx create-answer-plugin install my-plugin
Go to the ui directory and install dependencies:
cd ui pnpm pre-install
Build the frontend:
pnpm build
For development, start the dev server:
pnpm start
Merge i18n resources (if not done automatically):
cd .. go run ./cmd/answer/main.go i18n
Go to the ui directory.
Install the dependencies:
pnpm pre-install
Build the frontend:
pnpm build
For development, start the dev server:
pnpm start
Refer to the Run the Backend Plugin section and manually add the plugin to the project (import in main.go, add replace directive, etc.).
The Base interface contains basic information about the plugin and is used to display.
// Info presents the plugin information type Info struct { Name Translator SlugName string Description Translator Author string Version string Link string } // Base is the base plugin type Base interface { // Info returns the plugin information Info() Info }
:::caution
The SlugName of the plugin must be unique. Two plugins with the same SlugName will panic when registering.
:::
:::note
Different plugin types require different interfaces of implementation.
For example, following is the Connector plugin interface.
:::
type Connector interface { Base // ConnectorLogoSVG presents the logo in svg format ConnectorLogoSVG() string // ConnectorName presents the name of the connector // e.g. Facebook, Twitter, Instagram ConnectorName() Translator // ConnectorSlugName presents the slug name of the connector // Please use lowercase and hyphen as the separator // e.g. facebook, twitter, instagram ConnectorSlugName() string // ConnectorSender presents the sender of the connector // It handles the start endpoint of the connector // receiverURL is the whole URL of the receiver ConnectorSender(ctx *GinContext, receiverURL string) (redirectURL string) // ConnectorReceiver presents the receiver of the connector // It handles the callback endpoint of the connector, and returns the ConnectorReceiver(ctx *GinContext, receiverURL string) (userInfo ExternalLoginUserInfo, err error) }
:::tip
Translator is a struct for translation. Please refer to the documentation for details.
:::
For details on the description of each configuration item, please refer to the documentation.
type Config interface { Base // ConfigFields returns the list of config fields ConfigFields() []ConfigField // ConfigReceiver receives the config data, it calls when the config is saved or initialized. // We recommend to unmarshal the data to a struct, and then use the struct to do something. // The config is encoded in JSON format. // It depends on the definition of ConfigFields. ConfigReceiver(config []byte) error }
import "github.com/apache/answer/plugin"
func init() {
plugin.Register(&GitHubConnector{
Config: &GitHubConnectorConfig{},
})
}
The default configuration is as follows:
slug_name: <slug_name> type: <type> version: 0.0.1 author:
import i18nConfig from './i18n'; import Component from './Component'; import info from './info.yaml'; export default { info: { slug_name: info.slug_name, type: info.type, }, i18nConfig, component: Component, };
Among them, type、slug_name and component are required fields. i18nConfig and hooks are optional fields.
Currently the front end supports the following types of plugins:
Refer to editor-chart for details.
The plugin configuration of the routing type adds the route field to the configuration file.
slug_name: <slug_name> route: /<route> type: route version: 0.0.1 author:
import i18nConfig from './i18n'; import Component from './Component'; import info from './info.yaml'; export default { info: { slug_name: info.slug_name, type: info.type, route: info.route, }, i18nConfig, component: Component, };
Refer to captcha-basic for details.
It is not so different from React component, this plugin is more suitable for the following scenarios:
ui/src/plugins/builtin directory and create a directory, such as Demo. Then refer to the existing plugins to create the necessary files to start development.// ui/src/plugins/builtin
.
├── ...
├── Demo
├── i18n (language file)
├── en_US.yaml (default language required)
├── index.ts (required)
├── zh_CN.ts (any language you want to provide)
├── index.tsx (component required)
├── info.yaml (plugin information required)
├── services.ts (api)
plugins/builtin/index.tsimport Demo from './Demo' export default { ...(exists plugins), Demo, };
<PluginRender type="connector" slug_name="third_party_connector" />